Update and improve SimulatorStabGenerator

This commit is contained in:
2025-04-19 23:04:19 +02:00
parent 17704487c9
commit 05dc42355d
2 changed files with 127 additions and 119 deletions
@@ -32,22 +32,13 @@ import org.bukkit.block.Block;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import java.util.*; import java.util.HashSet;
import java.util.function.BiConsumer; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class Depth { public class Depth {
private static final Map<Region, List<BiConsumer<Vector, Integer>>> callbacks = new HashMap<>();
public static void addCallback(Region region, BiConsumer<Vector, Integer> callback) {
callbacks.computeIfAbsent(region, k -> new ArrayList<>()).add(callback);
}
public static void removeCallback(Region region, BiConsumer<Vector, Integer> callback) {
callbacks.computeIfAbsent(region, k -> new ArrayList<>()).remove(callback);
}
private Region region; private Region region;
private Vector minVector = null; private Vector minVector = null;
private Vector maxVector = null; private Vector maxVector = null;
@@ -79,10 +70,6 @@ public class Depth {
player.spigot().sendMessage(getMessage(player, dimensions.getBlockX() + 1, dimensions.getBlockY() + 1, dimensions.getBlockZ() + 1, tntCount)); player.spigot().sendMessage(getMessage(player, dimensions.getBlockX() + 1, dimensions.getBlockY() + 1, dimensions.getBlockZ() + 1, tntCount));
} }
}); });
new ArrayList<>(callbacks.getOrDefault(region, Collections.emptyList())).forEach(consumer -> {
consumer.accept(dimensions, tntCount);
});
} }
private void internalUpdate(Block block) { private void internalUpdate(Block block) {
@@ -27,7 +27,6 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.cannon.depth.Depth;
import de.steamwar.bausystem.features.simulator.SimulatorWatcher; import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup; import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
@@ -50,28 +49,57 @@ import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
import de.steamwar.bausystem.utils.bossbar.BossBarService; import de.steamwar.bausystem.utils.bossbar.BossBarService;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.boss.BarColor; import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle; import org.bukkit.boss.BarStyle;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import java.util.*; import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors;
public class SimulatorStabGenerator { public class SimulatorStabGenerator implements Listener {
private static final int MAX_RECORDINGS = 10; // Lupfstichs sind noch nicht perfekt
// Schwenkstichs sidn noch nicht perfekt
private static final int MAX_RECORDINGS = 5;
private static final Level LEVEL = Level.INFO;
private static final int TNT_INCREASE = 10;
private static final int MIN_BLOCK_TO_COUNT_AS_DEPTH = 20;
private final Map<Integer, Set<Location>> destroyedBlocksPerSlice = new HashMap<>();
@EventHandler
public void onEntityExplode(EntityExplodeEvent event) {
if (direction == null) return;
if (Region.getRegion(event.getEntity().getLocation()) == region) {
event.blockList().forEach(block -> {
if (!region.inRegion(block.getLocation(), RegionType.TESTBLOCK, RegionExtensionType.EXTENSION)) return;
int component = direction.component.apply(block.getLocation().toVector());
destroyedBlocksPerSlice.computeIfAbsent(component, __ -> new HashSet<>())
.add(block.getLocation());
});
}
}
private final Region region; private final Region region;
private final Simulator simulator; private final Simulator simulator;
private final TNTElement tntElement; private final TNTElement tntElement;
private final List<TNTPhase> phases; private final List<TNTPhase> phases;
private final int depthLimit; private final int depthLimit;
private Clipboard clipboard; private Clipboard clipboard;
private boolean cancel = false; private boolean cancel = false;
private Direction direction = null;
public SimulatorStabGenerator(Region region, Simulator simulator, TNTElement tntElement, int depthLimit) { public SimulatorStabGenerator(Region region, Simulator simulator, TNTElement tntElement, int depthLimit) {
this.region = region; this.region = region;
this.simulator = simulator; this.simulator = simulator;
@@ -111,77 +139,31 @@ public class SimulatorStabGenerator {
TraceRecorder.instance.removeAutoTraceRegion(region); TraceRecorder.instance.removeAutoTraceRegion(region);
} }
clipboard = FlatteningWrapper.impl.copy(region.getMinPointTestblockExtension(), region.getMaxPointTestblockExtension(), region.getTestBlockPoint()); clipboard = FlatteningWrapper.impl.copy(region.getMinPointTestblockExtension(), region.getMaxPointTestblockExtension(), region.getTestBlockPoint());
run();
getDirection();
} }
private BlockVector3 toBlockVector3(Point point) { private BlockVector3 toBlockVector3(Point point) {
return BlockVector3.at(point.getX(), point.getY(), point.getZ()); return BlockVector3.at(point.getX(), point.getY(), point.getZ());
} }
private Direction direction = null; private void getDirection() {
private void removeTestblock() {
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) { try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) {
e.setBlocks((com.sk89q.worldedit.regions.Region) new CuboidRegion(toBlockVector3(region.getMinPointTestblockExtension()), toBlockVector3(region.getMaxPointTestblockExtension())), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock()); e.setBlocks((com.sk89q.worldedit.regions.Region) new CuboidRegion(toBlockVector3(region.getMinPointTestblockExtension()), toBlockVector3(region.getMaxPointTestblockExtension())), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock());
} }
}
private void setTestblock() {
try {
PasteBuilder.ClipboardProvider clipboardProvider = new PasteBuilder.ClipboardProviderImpl(clipboard);
PasteBuilder pasteBuilder = new PasteBuilder(clipboardProvider)
.color(region.getPlain(Flag.COLOR, ColorMode.class).getColor());
region.reset(pasteBuilder, RegionType.TESTBLOCK, RegionExtensionType.EXTENSION);
} catch (SecurityException e) {
stop();
throw e;
}
}
private void run() {
if (cancel) return;
showBossbar(false); showBossbar(false);
Trace trace; Trace trace = TraceRecorder.instance.startRecording(region);
if (direction == null) {
removeTestblock();
trace = TraceRecorder.instance.startRecording(region);
} else {
setTestblock();
trace = null;
}
if (trace == null && currentDepth > 0) {
TNTPhase lastPhase = phases.getLast();
TNTPhase nextPhase = new TNTPhase();
nextPhase.setCount(1);
nextPhase.setTickOffset(lastPhase.getTickOffset());
nextPhase.setOrder(100);
nextPhase.setXJump(lastPhase.isXJump());
nextPhase.setYJump(lastPhase.isYJump());
nextPhase.setZJump(lastPhase.isZJump());
phases.add(nextPhase);
}
SimulatorExecutor.run(simulator, () -> { SimulatorExecutor.run(simulator, () -> {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
if (trace != null) TraceRecorder.instance.stopRecording(region); TraceRecorder.instance.stopRecording(region);
if (trace == null && currentDepth > 0) phases.removeLast(); calculateDirection(trace);
next(trace);
}, 20); }, 20);
}); });
} }
@AllArgsConstructor private void calculateDirection(Trace trace) {
private enum Direction {
X(Vector::getBlockX),
Y(Vector::getBlockY),
Z(Vector::getBlockZ);
private final Function<Vector, Integer> extractVelocity;
}
private void calcDirection(Trace trace) {
long tickSinceStart = -1; long tickSinceStart = -1;
List<TNTPoint> points = null; List<TNTPoint> points = null;
for (List<TNTPoint> current : trace.getHistories()) { for (List<TNTPoint> current : trace.getHistories()) {
@@ -193,6 +175,7 @@ public class SimulatorStabGenerator {
points = current; points = current;
} }
} }
TraceManager.instance.remove(trace);
if (points == null) { if (points == null) {
stop(); stop();
return; return;
@@ -214,33 +197,64 @@ public class SimulatorStabGenerator {
return; return;
} }
Bukkit.getLogger().log(Level.FINEST, "Direction: {}", direction); Bukkit.getLogger().log(LEVEL, "Direction: {0}", direction);
TraceManager.instance.remove(trace);
phases.getFirst().setOrder(SimulatorPhase.ORDER_LIMIT); phases.getFirst().setOrder(SimulatorPhase.ORDER_LIMIT);
phases.getFirst().setCount(10); phases.getFirst().setCount(TNT_INCREASE);
Depth.addCallback(region, callback); destroyedBlocksPerSlice.clear();
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::run, 20); Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
getStab();
}, 20);
}
private void getStab() {
try {
PasteBuilder.ClipboardProvider clipboardProvider = new PasteBuilder.ClipboardProviderImpl(clipboard);
PasteBuilder pasteBuilder = new PasteBuilder(clipboardProvider)
.color(region.getPlain(Flag.COLOR, ColorMode.class).getColor());
region.reset(pasteBuilder, RegionType.TESTBLOCK, RegionExtensionType.EXTENSION);
} catch (SecurityException e) {
stop();
throw e;
}
if (cancel) return;
showBossbar(false);
SimulatorExecutor.run(simulator, () -> {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::calculateStep, 20);
});
} }
private int recordings = 0; private int recordings = 0;
private List<Vector> depths = new ArrayList<>(); private List<Integer> currentDepths = new ArrayList<>();
private int lastDepth = 0; private int lastDepth = 0;
private int currentDepth = 0; private int currentDepth = 0;
private void next(Trace trace) { private void calculateStep() {
if (direction == null) { List<Map.Entry<Integer, Set<Location>>> locations = destroyedBlocksPerSlice.entrySet()
calcDirection(trace); .stream()
return; .sorted(Comparator.comparingInt(Map.Entry::getKey))
.collect(Collectors.toList());
int depth = 0;
for (int i = 0; i < locations.size(); i++) {
if (i == 0 || i == locations.size() - 1) {
if (locations.get(i).getValue().size() > MIN_BLOCK_TO_COUNT_AS_DEPTH) {
depth++;
}
} else {
depth++;
}
} }
List<Integer> depths = new ArrayList<>(); if (depth > 0) {
for (Vector vector : this.depths) { Bukkit.getLogger().log(LEVEL, "{0} {1} {2}", new Object[]{depth, destroyedBlocksPerSlice.size(), destroyedBlocksPerSlice.values().stream().map(Set::size).collect(Collectors.toList())});
depths.add(direction.extractVelocity.apply(vector)); currentDepths.add(depth);
} }
// System.out.println(depths); destroyedBlocksPerSlice.clear();
int depth = depths.stream().max(Integer::compareTo).orElse(0); int maxDepth = currentDepths.stream().max(Integer::compareTo).orElse(0);
currentDepth = depth; currentDepth = maxDepth;
int countWithoutLast = 0; int countWithoutLast = 0;
for (int i = 0; i < phases.size() - 1; i++) { for (int i = 0; i < phases.size() - 1; i++) {
@@ -248,61 +262,74 @@ public class SimulatorStabGenerator {
} }
TNTPhase lastPhase = phases.getLast(); TNTPhase lastPhase = phases.getLast();
boolean moreTNTNeeded = depth - countWithoutLast >= lastPhase.getCount() - 5; boolean moreTNTNeeded = maxDepth - countWithoutLast >= lastPhase.getCount() - 5;
if (!depths.isEmpty() && moreTNTNeeded) { if (!currentDepths.isEmpty() && moreTNTNeeded) {
Bukkit.getLogger().log(Level.FINEST, "Increasing tnt count by 10"); Bukkit.getLogger().log(LEVEL, "Increasing tnt count by {0}", TNT_INCREASE);
lastPhase.setCount(lastPhase.getCount() + 10); lastPhase.setCount(lastPhase.getCount() + TNT_INCREASE);
recordings = 0; recordings = 0;
depths.clear(); currentDepths.clear();
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::run, 20); Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20);
return; return;
} }
if (recordings++ < MAX_RECORDINGS) { if (recordings++ < MAX_RECORDINGS) {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::run, 20); Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20);
return; return;
} }
recordings = 0; recordings = 0;
if (depths.isEmpty()) { if (currentDepths.isEmpty()) {
Bukkit.getLogger().log(Level.FINEST, "No dimension - Increasing tickOffset to: {}", phases.getFirst().getTickOffset() + 1); Bukkit.getLogger().log(LEVEL, "No dimension - Increasing tickOffset to: {0}", phases.getFirst().getTickOffset() + 1);
phases.getFirst().setTickOffset(phases.getFirst().getTickOffset() + 1); phases.getFirst().setTickOffset(phases.getFirst().getTickOffset() + 1);
phases.getFirst().setOrder(0); phases.getFirst().setOrder(0);
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::run, 20); if (phases.getFirst().getTickOffset() > 80) {
stop();
} else {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20);
}
return; return;
} }
depths.clear(); currentDepths.clear();
Bukkit.getLogger().log(Level.FINEST, "No more TNT needed on phase adjusting - {} new depth; {} current count", new Object[]{depth - countWithoutLast, lastPhase.getCount()}); Bukkit.getLogger().log(LEVEL, "No more TNT needed on phase adjusting - {0} new depth; {1} current count", new Object[]{maxDepth - countWithoutLast, lastPhase.getCount()});
lastPhase.setCount(depth - countWithoutLast); lastPhase.setCount(maxDepth - countWithoutLast);
if (lastPhase.getCount() <= 0) { if (lastPhase.getCount() <= 0) {
Bukkit.getLogger().log(Level.FINEST, "Count was 0 or negative - removing last phase"); Bukkit.getLogger().log(LEVEL, "Count was 0 or negative - removing last phase");
phases.removeLast(); phases.removeLast();
} }
if (depth > depthLimit) { if (maxDepth > depthLimit) {
Bukkit.getLogger().log(Level.FINEST, "Depth is greater than {} - finished", depthLimit); Bukkit.getLogger().log(LEVEL, "Depth is greater than {0} - finished", depthLimit);
stop(); stop();
return; return;
} }
if (depth <= lastDepth) { if (maxDepth <= lastDepth) {
Bukkit.getLogger().log(Level.FINEST, "Depth is equal to last depth recorded {} - finished", depth); Bukkit.getLogger().log(LEVEL, "Depth is equal to last depth recorded {0} - finished", maxDepth);
stop(); stop();
return; return;
} }
lastDepth = depth; lastDepth = maxDepth;
Bukkit.getLogger().log(Level.FINEST, "Adding new phase in next tick"); Bukkit.getLogger().log(LEVEL, "Adding new phase in next tick");
TNTPhase nextPhase = new TNTPhase(); TNTPhase nextPhase = new TNTPhase();
nextPhase.setCount(10); nextPhase.setCount(TNT_INCREASE);
nextPhase.setTickOffset(lastPhase.getTickOffset() + 1); nextPhase.setTickOffset(lastPhase.getTickOffset() + 1);
nextPhase.setXJump(lastPhase.isXJump()); nextPhase.setXJump(lastPhase.isXJump());
nextPhase.setYJump(lastPhase.isYJump()); nextPhase.setYJump(lastPhase.isYJump());
nextPhase.setZJump(lastPhase.isZJump()); nextPhase.setZJump(lastPhase.isZJump());
phases.add(nextPhase); phases.add(nextPhase);
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::run, 20); Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20);
}
@AllArgsConstructor
private enum Direction {
X(Vector::getBlockX),
Y(Vector::getBlockY),
Z(Vector::getBlockZ);
private final Function<Vector, Integer> component;
} }
private void showBossbar(boolean finished) { private void showBossbar(boolean finished) {
@@ -331,8 +358,8 @@ public class SimulatorStabGenerator {
private void stop() { private void stop() {
simulator.setStabGenerator(null); simulator.setStabGenerator(null);
Depth.removeCallback(region, callback);
SimulatorWatcher.update(simulator); SimulatorWatcher.update(simulator);
HandlerList.unregisterAll(this);
showBossbar(true); showBossbar(true);
new Thread(() -> { new Thread(() -> {
@@ -348,18 +375,12 @@ public class SimulatorStabGenerator {
}).start(); }).start();
} }
private BiConsumer<Vector, Integer> callback = this::depth;
private void depth(Vector dimension, int tntCount) {
depths.add(dimension.clone().add(new Vector(1, 1, 1)));
}
public void cancel() { public void cancel() {
cancel = true; cancel = true;
simulator.setStabGenerator(null); simulator.setStabGenerator(null);
Depth.removeCallback(region, callback);
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
BossBarService.instance.remove(player, region, "simulator_stab_generator"); BossBarService.instance.remove(player, region, "simulator_stab_generator");
} }
HandlerList.unregisterAll(this);
} }
} }