From 313b22cb4461dbc85a833172c93b441414bf01f1 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sun, 20 Apr 2025 18:30:30 +0200 Subject: [PATCH] Optimize SimulatorStabGenerator --- .../bausystem/utils/FlatteningWrapper15.java | 14 +- .../features/simulator/data/tnt/TNTPhase.java | 1 + .../features/simulator/execute/Direction.java | 34 ++ .../execute/SimulatorStabGenerator.java | 357 +----------------- .../features/simulator/execute/StabData.java | 52 +++ .../simulator/execute/StabDirection.java | 103 +++++ .../simulator/execute/StabFinalizer.java | 61 +++ .../simulator/execute/StabGenerator.java | 250 ++++++++++++ .../features/simulator/execute/StabSetup.java | 85 +++++ .../features/simulator/execute/StabStep.java | 95 +++++ .../de/steamwar/bausystem/region/Point.java | 4 + 11 files changed, 697 insertions(+), 359 deletions(-) create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/Direction.java create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabData.java create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabDirection.java create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabFinalizer.java create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabGenerator.java create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabSetup.java create mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabStep.java diff --git a/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/FlatteningWrapper15.java b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/FlatteningWrapper15.java index 9407f542..266326e0 100644 --- a/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/FlatteningWrapper15.java +++ b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/FlatteningWrapper15.java @@ -109,7 +109,7 @@ public class FlatteningWrapper15 implements FlatteningWrapper { @Override public void setSelection(Player p, Point minPoint, Point maxPoint) { - WORLDEDIT_PLUGIN.getSession(p).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, toBlockVector3(minPoint), toBlockVector3(maxPoint))); + WORLDEDIT_PLUGIN.getSession(p).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, minPoint.toBlockVector3(), maxPoint.toBlockVector3())); } @Override @@ -178,9 +178,9 @@ public class FlatteningWrapper15 implements FlatteningWrapper { pastePoint.set(v); if (pasteBuilder.isReset()) { - e.setBlocks(new CuboidRegion(toBlockVector3(pasteBuilder.getMinPoint()), toBlockVector3(pasteBuilder.getMaxPoint())), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock()); + e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3()), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock()); if (pasteBuilder.getWaterLevel() != 0) { - e.setBlocks(new CuboidRegion(toBlockVector3(pasteBuilder.getMinPoint()), toBlockVector3(pasteBuilder.getMaxPoint()).withY(pasteBuilder.getWaterLevel())), Objects.requireNonNull(BlockTypes.WATER).getDefaultState().toBaseBlock()); + e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3().withY(pasteBuilder.getWaterLevel())), Objects.requireNonNull(BlockTypes.WATER).getDefaultState().toBaseBlock()); } } Operations.completeBlindly(ch.createPaste(e).to(v).ignoreAirBlocks(pasteBuilder.isIgnoreAir()).build()); @@ -193,7 +193,7 @@ public class FlatteningWrapper15 implements FlatteningWrapper { @Override public Clipboard copy(Point minPoint, Point maxPoint, Point copyPoint) { BukkitWorld bukkitWorld = new BukkitWorld(Bukkit.getWorlds().get(0)); - CuboidRegion region = new CuboidRegion(bukkitWorld, toBlockVector3(minPoint), toBlockVector3(maxPoint)); + CuboidRegion region = new CuboidRegion(bukkitWorld, minPoint.toBlockVector3(), maxPoint.toBlockVector3()); BlockArrayClipboard clipboard = new BlockArrayClipboard(region); try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(bukkitWorld, -1)) { ForwardExtentCopy copy = new ForwardExtentCopy( @@ -204,7 +204,7 @@ public class FlatteningWrapper15 implements FlatteningWrapper { copy.setCopyingBiomes(false); Operations.complete(copy); - clipboard.setOrigin(toBlockVector3(copyPoint)); + clipboard.setOrigin(copyPoint.toBlockVector3()); return clipboard; } catch (WorldEditException e) { Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e); @@ -224,10 +224,6 @@ public class FlatteningWrapper15 implements FlatteningWrapper { } } - private BlockVector3 toBlockVector3(Point point) { - return BlockVector3.at(point.getX(), point.getY(), point.getZ()); - } - @Override public boolean inWater(org.bukkit.World world, Vector tntPosition) { Block block = world.getBlockAt(tntPosition.getBlockX(), tntPosition.getBlockY(), tntPosition.getBlockZ()); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/tnt/TNTPhase.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/tnt/TNTPhase.java index 4c03ac9b..29f59d93 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/tnt/TNTPhase.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/tnt/TNTPhase.java @@ -60,6 +60,7 @@ public final class TNTPhase extends SimulatorPhase { @Override public void toSimulatorActions(Vector position, BiConsumer tickStart, BiConsumer tickEnd) { + if (count <= 0) return; tickStart.accept(tickOffset, new SimulatorAction(order, count) { @Override public void accept(World world) { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/Direction.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/Direction.java new file mode 100644 index 00000000..31737266 --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/Direction.java @@ -0,0 +1,34 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.features.simulator.execute; + +import lombok.AllArgsConstructor; +import org.bukkit.util.Vector; + +import java.util.function.Function; + +@AllArgsConstructor +public enum Direction { + X(Vector::getBlockX), + Y(Vector::getBlockY), + Z(Vector::getBlockZ); + + public final Function component; +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorStabGenerator.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorStabGenerator.java index 0cbd2eeb..37ca8bf3 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorStabGenerator.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorStabGenerator.java @@ -19,370 +19,27 @@ package de.steamwar.bausystem.features.simulator.execute; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.block.BlockTypes; -import de.steamwar.bausystem.BauSystem; -import de.steamwar.bausystem.features.simulator.SimulatorWatcher; import de.steamwar.bausystem.features.simulator.data.Simulator; -import de.steamwar.bausystem.features.simulator.data.SimulatorGroup; -import de.steamwar.bausystem.features.simulator.data.SimulatorPhase; import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement; -import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase; -import de.steamwar.bausystem.features.tracer.TNTPoint; -import de.steamwar.bausystem.features.tracer.Trace; -import de.steamwar.bausystem.features.tracer.TraceManager; -import de.steamwar.bausystem.features.tracer.TraceRecorder; -import de.steamwar.bausystem.region.Point; import de.steamwar.bausystem.region.Region; -import de.steamwar.bausystem.region.flags.Flag; -import de.steamwar.bausystem.region.flags.flagvalues.ColorMode; -import de.steamwar.bausystem.region.utils.RegionExtensionType; -import de.steamwar.bausystem.region.utils.RegionType; -import de.steamwar.bausystem.utils.FlatteningWrapper; -import de.steamwar.bausystem.utils.PasteBuilder; -import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar; import de.steamwar.bausystem.utils.bossbar.BossBarService; -import lombok.AllArgsConstructor; import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; 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 java.util.*; -import java.util.function.Function; -import java.util.logging.Level; -import java.util.stream.Collectors; +public class SimulatorStabGenerator { -public class SimulatorStabGenerator implements Listener { - - // 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> 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 Simulator simulator; - private final TNTElement tntElement; - private final List phases; - private final int depthLimit; - - private Clipboard clipboard; - private boolean cancel = false; - - private Direction direction = null; + private final StabData stabData; public SimulatorStabGenerator(Region region, Simulator simulator, TNTElement tntElement, int depthLimit) { - this.region = region; - this.simulator = simulator; - this.tntElement = tntElement; - this.phases = tntElement.getPhases(); - this.depthLimit = depthLimit; - - setup(); - } - - private void setup() { - TNTPhase tntPhase = simulator.getGroups().stream() - .filter(simulatorGroup -> !simulatorGroup.isDisabled()) - .map(SimulatorGroup::getElements) - .flatMap(List::stream) - .filter(TNTElement.class::isInstance) - .map(TNTElement.class::cast) - .filter(tntElement -> !tntElement.isDisabled()) - .filter(tntElement -> this.tntElement != tntElement) - .map(tntElement -> tntElement.getPhases().stream().max(Comparator.comparingInt(TNTPhase::getTickOffset))) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(phase -> phase != phases.get(0)) - .max(Comparator.comparingInt(TNTPhase::getTickOffset)) - .orElse(null); - if (tntPhase == null) { - throw new SecurityException(""); - } - - TNTPhase phase = phases.get(0); - phases.clear(); - phases.add(phase); - phase.setCount(1); - phase.setTickOffset(tntPhase.getTickOffset()); - phase.setOrder(100); - - TraceRecorder.instance.stopRecording(region); - if (TraceRecorder.instance.isAutoTraceEnabledInRegion(region)) { - TraceRecorder.instance.removeAutoTraceRegion(region); - } - clipboard = FlatteningWrapper.impl.copy(region.getMinPointTestblockExtension(), region.getMaxPointTestblockExtension(), region.getTestBlockPoint()); - - getDirection(); - } - - private BlockVector3 toBlockVector3(Point point) { - return BlockVector3.at(point.getX(), point.getY(), point.getZ()); - } - - private void getDirection() { - 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()); - } - - showBossbar(false); - - Trace trace = TraceRecorder.instance.startRecording(region); - SimulatorExecutor.run(simulator, () -> { - Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { - TraceRecorder.instance.stopRecording(region); - calculateDirection(trace); - }, 20); - }); - } - - private void calculateDirection(Trace trace) { - long tickSinceStart = -1; - List points = null; - for (List current : trace.getHistories()) { - long ticks = current.get(0).getTicksSinceStart(); - if (points == null || ticks > tickSinceStart) { - tickSinceStart = ticks; - points = current; - } else if (ticks == tickSinceStart && points.get(0).getTntId() < current.get(0).getTntId()) { - points = current; - } - } - TraceManager.instance.remove(trace); - if (points == null) { - stop(); - return; - } - - TNTPoint current = points.getLast(); - Vector velocity = current.getVelocity(); - if (velocity.getX() < 0) velocity.setX(-velocity.getX()); - if (velocity.getY() < 0) velocity.setY(-velocity.getY()); - if (velocity.getZ() < 0) velocity.setZ(-velocity.getZ()); - if (velocity.getX() > velocity.getY() && velocity.getX() > velocity.getZ()) { - direction = Direction.X; - } else if (velocity.getY() > velocity.getX() && velocity.getY() > velocity.getZ()) { - direction = Direction.Y; - } else if (velocity.getZ() > velocity.getX() && velocity.getZ() > velocity.getY()) { - direction = Direction.Z; - } else { - stop(); - return; - } - - Bukkit.getLogger().log(LEVEL, "Direction: {0}", direction); - phases.getFirst().setOrder(SimulatorPhase.ORDER_LIMIT); - phases.getFirst().setCount(TNT_INCREASE); - destroyedBlocksPerSlice.clear(); - 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 List currentDepths = new ArrayList<>(); - private int lastDepth = 0; - private int currentDepth = 0; - - private void calculateStep() { - List>> locations = destroyedBlocksPerSlice.entrySet() - .stream() - .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++; - } - } - - if (depth > 0) { - Bukkit.getLogger().log(LEVEL, "{0} {1} {2}", new Object[]{depth, destroyedBlocksPerSlice.size(), destroyedBlocksPerSlice.values().stream().map(Set::size).collect(Collectors.toList())}); - currentDepths.add(depth); - } - destroyedBlocksPerSlice.clear(); - - int maxDepth = currentDepths.stream().max(Integer::compareTo).orElse(0); - currentDepth = maxDepth; - - int countWithoutLast = 0; - for (int i = 0; i < phases.size() - 1; i++) { - countWithoutLast += phases.get(i).getCount(); - } - - TNTPhase lastPhase = phases.getLast(); - boolean moreTNTNeeded = maxDepth - countWithoutLast >= lastPhase.getCount() - 5; - if (!currentDepths.isEmpty() && moreTNTNeeded) { - Bukkit.getLogger().log(LEVEL, "Increasing tnt count by {0}", TNT_INCREASE); - lastPhase.setCount(lastPhase.getCount() + TNT_INCREASE); - recordings = 0; - currentDepths.clear(); - - Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20); - return; - } - - if (recordings++ < MAX_RECORDINGS) { - Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20); - return; - } - - recordings = 0; - if (currentDepths.isEmpty()) { - Bukkit.getLogger().log(LEVEL, "No dimension - Increasing tickOffset to: {0}", phases.getFirst().getTickOffset() + 1); - phases.getFirst().setTickOffset(phases.getFirst().getTickOffset() + 1); - phases.getFirst().setOrder(0); - if (phases.getFirst().getTickOffset() > 80) { - stop(); - } else { - Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20); - } - return; - } - - currentDepths.clear(); - - 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(maxDepth - countWithoutLast); - if (lastPhase.getCount() <= 0) { - Bukkit.getLogger().log(LEVEL, "Count was 0 or negative - removing last phase"); - phases.removeLast(); - } - - if (maxDepth > depthLimit) { - Bukkit.getLogger().log(LEVEL, "Depth is greater than {0} - finished", depthLimit); - stop(); - return; - } - if (maxDepth <= lastDepth) { - Bukkit.getLogger().log(LEVEL, "Depth is equal to last depth recorded {0} - finished", maxDepth); - stop(); - return; - } - lastDepth = maxDepth; - - Bukkit.getLogger().log(LEVEL, "Adding new phase in next tick"); - TNTPhase nextPhase = new TNTPhase(); - nextPhase.setCount(TNT_INCREASE); - nextPhase.setTickOffset(lastPhase.getTickOffset() + 1); - nextPhase.setXJump(lastPhase.isXJump()); - nextPhase.setYJump(lastPhase.isYJump()); - nextPhase.setZJump(lastPhase.isZJump()); - phases.add(nextPhase); - Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20); - } - - @AllArgsConstructor - private enum Direction { - X(Vector::getBlockX), - Y(Vector::getBlockY), - Z(Vector::getBlockZ); - - private final Function component; - } - - private void showBossbar(boolean finished) { - for (Player player : Bukkit.getOnlinePlayers()) { - BauSystemBossbar bossbar = BossBarService.instance.get(player, region, "simulator_stab_generator"); - bossbar.setColor(BarColor.GREEN); - bossbar.setStyle(BarStyle.SEGMENTED_10); - bossbar.setProgress(Math.min(currentDepth / (double) depthLimit, 1.0)); - StringBuilder st = new StringBuilder(); - - if (finished) { - st.append("§eFinished ").append(currentDepth).append("§8/§7").append(depthLimit); - } else if (direction == null) { - st.append("§eCalculating Stab Direction"); - } else { - st.append("§7Direction§7 §e" + direction); - st.append(" §e").append(currentDepth).append("§8/§7").append(depthLimit); - if (recordings > 0) { - st.append(" §7Retries§8:§e ").append(recordings).append("§8/§7").append(MAX_RECORDINGS); - } - } - - bossbar.setTitle(st.toString()); - } - } - - private void stop() { - simulator.setStabGenerator(null); - SimulatorWatcher.update(simulator); - HandlerList.unregisterAll(this); - - showBossbar(true); - new Thread(() -> { - try { - Thread.sleep(4000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - for (Player player : Bukkit.getOnlinePlayers()) { - BossBarService.instance.remove(player, region, "simulator_stab_generator"); - } - } - }).start(); + stabData = new StabData(region, simulator, tntElement, tntElement.getPhases(), depthLimit); + new StabSetup(stabData); } public void cancel() { - cancel = true; - simulator.setStabGenerator(null); + stabData.cancel = true; + stabData.simulator.setStabGenerator(null); for (Player player : Bukkit.getOnlinePlayers()) { - BossBarService.instance.remove(player, region, "simulator_stab_generator"); + BossBarService.instance.remove(player, stabData.region, "simulator_stab_generator"); } - HandlerList.unregisterAll(this); } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabData.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabData.java new file mode 100644 index 00000000..dc1a6e0e --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabData.java @@ -0,0 +1,52 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.features.simulator.execute; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import de.steamwar.bausystem.features.simulator.data.Simulator; +import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement; +import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase; +import de.steamwar.bausystem.region.Region; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.logging.Level; + +@RequiredArgsConstructor +public class StabData { + + protected static final int MAX_RECORDINGS = 5; + protected static final int MAX_TICK_DIFFERENCE = 3; + protected static final Level LEVEL = Level.INFO; + protected static final int TNT_INCREASE = 10; + protected static final int MIN_BLOCK_TO_COUNT_AS_DEPTH = 20; + + protected final Region region; + protected final Simulator simulator; + protected final TNTElement tntElement; + protected final List phases; + protected final int depthLimit; + + protected Clipboard clipboard; + protected boolean cancel = false; + + protected Direction direction = null; + protected int currentDepth = 0; +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabDirection.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabDirection.java new file mode 100644 index 00000000..4be5284b --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabDirection.java @@ -0,0 +1,103 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.features.simulator.execute; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.block.BlockTypes; +import de.steamwar.bausystem.features.simulator.data.SimulatorPhase; +import de.steamwar.bausystem.features.tracer.TNTPoint; +import de.steamwar.bausystem.features.tracer.Trace; +import de.steamwar.bausystem.features.tracer.TraceManager; +import de.steamwar.bausystem.features.tracer.TraceRecorder; +import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar; +import org.bukkit.Bukkit; +import org.bukkit.util.Vector; + +import java.util.List; +import java.util.Objects; + +public class StabDirection extends StabStep { + + public StabDirection(StabData data) { + super(data); + } + + @Override + protected void start() { + try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) { + e.setBlocks((com.sk89q.worldedit.regions.Region) new CuboidRegion(data.region.getMinPointTestblockExtension().toBlockVector3(), data.region.getMaxPointTestblockExtension().toBlockVector3()), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock()); + } + + Trace trace = TraceRecorder.instance.startRecording(data.region); + runSimulator(() -> { + TraceRecorder.instance.stopRecording(data.region); + calculateDirection(trace); + }); + } + + private void calculateDirection(Trace trace) { + long tickSinceStart = -1; + List points = null; + for (List current : trace.getHistories()) { + long ticks = current.get(0).getTicksSinceStart(); + if (points == null || ticks > tickSinceStart) { + tickSinceStart = ticks; + points = current; + } else if (ticks == tickSinceStart && points.get(0).getTntId() < current.get(0).getTntId()) { + points = current; + } + } + TraceManager.instance.remove(trace); + if (points == null) { + stop(); + return; + } + + TNTPoint current = points.getLast(); + Vector velocity = current.getVelocity(); + if (velocity.getX() < 0) velocity.setX(-velocity.getX()); + if (velocity.getY() < 0) velocity.setY(-velocity.getY()); + if (velocity.getZ() < 0) velocity.setZ(-velocity.getZ()); + if (velocity.getX() > velocity.getY() && velocity.getX() > velocity.getZ()) { + data.direction = Direction.X; + } else if (velocity.getY() > velocity.getX() && velocity.getY() > velocity.getZ()) { + data.direction = Direction.Y; + } else if (velocity.getZ() > velocity.getX() && velocity.getZ() > velocity.getY()) { + data.direction = Direction.Z; + } else { + stop(); + return; + } + + Bukkit.getLogger().log(StabData.LEVEL, "Direction: {0}", data.direction); + data.phases.getFirst().setOrder(SimulatorPhase.ORDER_LIMIT); + data.phases.getFirst().setCount(StabData.TNT_INCREASE); + new StabGenerator(data); + } + + @Override + protected void bossbar(BauSystemBossbar bossbar, boolean finished) { + bossbar.setProgress(0); + bossbar.setTitle("§eCalculating Stab Direction"); + } +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabFinalizer.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabFinalizer.java new file mode 100644 index 00000000..5c0d77aa --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabFinalizer.java @@ -0,0 +1,61 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.features.simulator.execute; + +import de.steamwar.bausystem.features.tracer.Trace; +import de.steamwar.bausystem.features.tracer.TraceRecorder; +import de.steamwar.bausystem.region.flags.Flag; +import de.steamwar.bausystem.region.flags.flagvalues.ColorMode; +import de.steamwar.bausystem.region.utils.RegionExtensionType; +import de.steamwar.bausystem.region.utils.RegionType; +import de.steamwar.bausystem.utils.PasteBuilder; +import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar; + +public class StabFinalizer extends StabStep { + + public StabFinalizer(StabData data) { + super(data); + } + + @Override + protected void start() { + try { + PasteBuilder.ClipboardProvider clipboardProvider = new PasteBuilder.ClipboardProviderImpl(data.clipboard); + PasteBuilder pasteBuilder = new PasteBuilder(clipboardProvider) + .color(data.region.getPlain(Flag.COLOR, ColorMode.class).getColor()); + data.region.reset(pasteBuilder, RegionType.TESTBLOCK, RegionExtensionType.EXTENSION); + } catch (SecurityException e) { + stop(); + throw e; + } + + TraceRecorder.instance.startRecording(data.region); + runSimulator(() -> { + TraceRecorder.instance.stopRecording(data.region); + stop(); + }); + } + + @Override + protected void bossbar(BauSystemBossbar bossbar, boolean stopped) { + bossbar.setProgress(Math.min(data.currentDepth / (double) data.depthLimit, 1.0)); + bossbar.setTitle("§e" + data.currentDepth + "§8/§7" + data.depthLimit); + } +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabGenerator.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabGenerator.java new file mode 100644 index 00000000..4a15ebcb --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabGenerator.java @@ -0,0 +1,250 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.features.simulator.execute; + +import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase; +import de.steamwar.bausystem.region.Region; +import de.steamwar.bausystem.region.flags.Flag; +import de.steamwar.bausystem.region.flags.flagvalues.ColorMode; +import de.steamwar.bausystem.region.utils.RegionExtensionType; +import de.steamwar.bausystem.region.utils.RegionType; +import de.steamwar.bausystem.utils.PasteBuilder; +import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityExplodeEvent; + +import java.util.*; +import java.util.stream.Collectors; + +import static de.steamwar.bausystem.features.simulator.execute.Direction.Y; + +public class StabGenerator extends StabStep implements Listener { + + private int recordings = 0; + private List currentDepths = new ArrayList<>(); + private int lastDepth = 0; + + private int retries = 0; + + private final Map> destroyedBlocksPerSlice = new HashMap<>(); + + private Set gabStart = new HashSet<>(); + private Set failedAtLeastOnce = new HashSet<>(); + + @EventHandler + public void onEntityExplode(EntityExplodeEvent event) { + if (Region.getRegion(event.getEntity().getLocation()) == data.region) { + event.blockList().forEach(block -> { + if (!data.region.inRegion(block.getLocation(), RegionType.TESTBLOCK, RegionExtensionType.EXTENSION)) return; + int component = data.direction.component.apply(block.getLocation().toVector()); + destroyedBlocksPerSlice.computeIfAbsent(component, __ -> new HashSet<>()) + .add(block.getLocation()); + }); + } + } + + public StabGenerator(StabData data) { + super(data); + } + + @Override + protected void start() { + try { + PasteBuilder.ClipboardProvider clipboardProvider = new PasteBuilder.ClipboardProviderImpl(data.clipboard); + PasteBuilder pasteBuilder = new PasteBuilder(clipboardProvider) + .color(data.region.getPlain(Flag.COLOR, ColorMode.class).getColor()); + data.region.reset(pasteBuilder, RegionType.TESTBLOCK, RegionExtensionType.EXTENSION); + } catch (SecurityException e) { + stop(); + throw e; + } + + if (data.cancel) { + HandlerList.unregisterAll(this); + return; + } + + runSimulator(this::calculateStab); + } + + private void calculateStab() { + TNTPhase lastPhase = data.phases.getLast(); + + List>> locations = destroyedBlocksPerSlice.entrySet() + .stream() + .sorted(Comparator.comparingInt(Map.Entry::getKey)) + .collect(Collectors.toList()); + int depth = 0; + for (int i = 0; i < locations.size(); i++) { + if (data.direction != Y && i > 0 && Math.abs(locations.get(i - 1).getKey() - locations.get(i).getKey()) > 3) { + if (gabStart.add(locations.get(i).getKey())) { + Bukkit.getLogger().log(StabData.LEVEL, "Increasing tnt count by {0} because of gap", StabData.TNT_INCREASE); + lastPhase.setCount(lastPhase.getCount() + StabData.TNT_INCREASE); + recordings = 0; + currentDepths.clear(); + + run(); + return; + } + } + if (i == 0 || i == locations.size() - 1) { + if (locations.get(i).getValue().size() > StabData.MIN_BLOCK_TO_COUNT_AS_DEPTH) { + depth++; + } + } else { + depth++; + } + } + + if (depth > 0) { + Bukkit.getLogger().log(StabData.LEVEL, "{0} {1} {2}", new Object[]{depth, destroyedBlocksPerSlice.size(), destroyedBlocksPerSlice.values().stream().map(Set::size).collect(Collectors.toList())}); + destroyedBlocksPerSlice.clear(); + currentDepths.add(depth); + } else { + destroyedBlocksPerSlice.clear(); + lastPhase.setTickOffset(lastPhase.getTickOffset() + 1); + Bukkit.getLogger().log(StabData.LEVEL, "No dimension - Increasing tickOffset to: {0}", lastPhase.getTickOffset()); + lastPhase.setOrder(0); + if (lastPhase.getTickOffset() > 80) { + stop(); + } else { + run(); + } + return; + } + + int minDepth = currentDepths.stream().min(Integer::compareTo).orElse(0); + int maxDepth = currentDepths.stream().max(Integer::compareTo).orElse(0); + data.currentDepth = maxDepth; + + int countWithoutLast = 0; + for (int i = 0; i < data.phases.size() - 1; i++) { + countWithoutLast += data.phases.get(i).getCount(); + } + countWithoutLast -= gabStart.size(); + + boolean moreTNTNeeded = maxDepth - countWithoutLast >= lastPhase.getCount() - 5; + if (moreTNTNeeded) { + Bukkit.getLogger().log(StabData.LEVEL, "Increasing tnt count by {0}", StabData.TNT_INCREASE); + lastPhase.setCount(lastPhase.getCount() + StabData.TNT_INCREASE); + recordings = 0; + currentDepths.clear(); + + run(); + return; + } + + if (recordings++ < StabData.MAX_RECORDINGS) { + run(); + return; + } + + recordings = 0; + currentDepths.clear(); + + if (maxDepth - minDepth > lastPhase.getCount()) { + Bukkit.getLogger().log(StabData.LEVEL, "Stab failed at least once. Adding one tnt to {0}", minDepth - 3); + int current = 0; + TNTPhase last = null; + for (TNTPhase phase : data.phases) { + if (current < minDepth - 3) { + current += phase.getCount(); + last = phase; + continue; + } + + if (failedAtLeastOnce.add(last)) { + last = null; + break; + } + + if (last != null) { + last.setCount(last.getCount() + 1); + Bukkit.getLogger().log(StabData.LEVEL, "Added to phase {0} now has {1} tnt", new Object[]{data.phases.indexOf(last), last.getCount()}); + } + break; + } + + if (last != null) { + run(); + return; + } + } + + Bukkit.getLogger().log(StabData.LEVEL, "No more TNT needed on phase adjusting - {0} new count; {1} current count", new Object[]{maxDepth - countWithoutLast, lastPhase.getCount()}); + lastPhase.setCount(maxDepth - countWithoutLast); + if (lastPhase.getCount() <= 0) { + Bukkit.getLogger().log(StabData.LEVEL, "Count was 0 or negative - removing last phase"); + data.phases.removeLast(); + } + + if (maxDepth > data.depthLimit) { + Bukkit.getLogger().log(StabData.LEVEL, "Depth is greater than {0} - finished", data.depthLimit); + new StabFinalizer(data); + return; + } + if (maxDepth <= lastDepth) { + if (lastPhase.getCount() <= 0) { + retries++; + } + if (lastPhase.getCount() > 0 || retries > StabData.MAX_TICK_DIFFERENCE) { + Bukkit.getLogger().log(StabData.LEVEL, "Depth is equal to last depth recorded {0} - finished", maxDepth); + new StabFinalizer(data); + return; + } + } + lastDepth = maxDepth; + + newPhase(data, lastPhase); + run(); + } + + public static void newPhase(StabData data, TNTPhase lastPhase) { + Bukkit.getLogger().log(StabData.LEVEL, "Adding new phase in next tick"); + TNTPhase nextPhase = new TNTPhase(); + nextPhase.setCount(StabData.TNT_INCREASE); + nextPhase.setTickOffset(lastPhase.getTickOffset() + 1); + nextPhase.setXJump(lastPhase.isXJump()); + nextPhase.setYJump(lastPhase.isYJump()); + nextPhase.setZJump(lastPhase.isZJump()); + data.phases.add(nextPhase); + } + + @Override + protected void bossbar(BauSystemBossbar bossbar, boolean finished) { + bossbar.setProgress(Math.min(data.currentDepth / (double) data.depthLimit, 1.0)); + if (finished) { + bossbar.setTitle("§e" + data.currentDepth + "§8/§7" + data.depthLimit); + return; + } + + StringBuilder st = new StringBuilder(); + st.append("§7Direction §e").append(data.direction); + st.append(" §e").append(data.currentDepth).append("§8/§7").append(data.depthLimit); + if (recordings > 0) { + st.append(" §7Retries§8:§e ").append(recordings).append("§8/§7").append(StabData.MAX_RECORDINGS); + } + bossbar.setTitle(st.toString()); + } +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabSetup.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabSetup.java new file mode 100644 index 00000000..9662a638 --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabSetup.java @@ -0,0 +1,85 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.features.simulator.execute; + +import de.steamwar.bausystem.features.simulator.data.SimulatorGroup; +import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement; +import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase; +import de.steamwar.bausystem.features.tracer.TraceRecorder; +import de.steamwar.bausystem.utils.FlatteningWrapper; +import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar; + +import java.util.Comparator; +import java.util.List; +import java.util.Optional; + +public class StabSetup extends StabStep { + + public StabSetup(StabData data) { + super(data); + } + + @Override + protected void start() { + TNTPhase tntPhase = data.simulator.getGroups().stream() + .filter(simulatorGroup -> !simulatorGroup.isDisabled()) + .map(SimulatorGroup::getElements) + .flatMap(List::stream) + .filter(TNTElement.class::isInstance) + .map(TNTElement.class::cast) + .filter(tntElement -> !tntElement.isDisabled()) + .filter(tntElement -> data.tntElement != tntElement) + .map(tntElement -> tntElement.getPhases().stream().max(Comparator.comparingInt(TNTPhase::getTickOffset))) + .filter(Optional::isPresent) + .map(Optional::get) + .peek(phase -> { + if (phase.getOrder() > TNTPhase.ORDER_LIMIT) { + phase.setOrder(TNTPhase.ORDER_LIMIT); + } + }) + .filter(phase -> phase != data.phases.get(0)) + .max(Comparator.comparingInt(TNTPhase::getTickOffset)) + .orElse(null); + if (tntPhase == null) { + throw new SecurityException(""); + } + + TNTPhase phase = data.phases.get(0); + data.phases.clear(); + data.phases.add(phase); + phase.setCount(1); + phase.setTickOffset(tntPhase.getTickOffset()); + phase.setOrder(100); + + TraceRecorder.instance.stopRecording(data.region); + if (TraceRecorder.instance.isAutoTraceEnabledInRegion(data.region)) { + TraceRecorder.instance.removeAutoTraceRegion(data.region); + } + data.clipboard = FlatteningWrapper.impl.copy(data.region.getMinPointTestblockExtension(), data.region.getMaxPointTestblockExtension(), data.region.getTestBlockPoint()); + + new StabDirection(data); + } + + @Override + protected void bossbar(BauSystemBossbar bossbar, boolean finished) { + bossbar.setProgress(0); + bossbar.setTitle("§eSetting up Simulator"); + } +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabStep.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabStep.java new file mode 100644 index 00000000..ad0d05ee --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabStep.java @@ -0,0 +1,95 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.features.simulator.execute; + +import de.steamwar.bausystem.BauSystem; +import de.steamwar.bausystem.features.simulator.SimulatorWatcher; +import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar; +import de.steamwar.bausystem.utils.bossbar.BossBarService; +import org.bukkit.Bukkit; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarStyle; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; + +public abstract class StabStep { + + protected final StabData data; + + protected StabStep(StabData data) { + this.data = data; + run(); + } + + protected final void run() { + Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { + for (Player player : Bukkit.getOnlinePlayers()) { + BauSystemBossbar bossbar = BossBarService.instance.get(player, data.region, "simulator_stab_generator"); + bossbar.setColor(BarColor.GREEN); + bossbar.setStyle(BarStyle.SEGMENTED_10); + bossbar(bossbar, false); + } + }, 1); + + if (this instanceof Listener) { + Bukkit.getPluginManager().registerEvents((Listener) this, BauSystem.getInstance()); + } + Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::start, 20); + } + + protected abstract void start(); + + protected final void runSimulator(Runnable onFinish) { + SimulatorExecutor.run(data.simulator, () -> { + Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { + if (this instanceof Listener) { + HandlerList.unregisterAll((Listener) this); + } + onFinish.run(); + }, 20); + }); + } + + protected abstract void bossbar(BauSystemBossbar bossbar, boolean stopped); + + protected final void stop() { + data.simulator.setStabGenerator(null); + SimulatorWatcher.update(data.simulator); + + for (Player player : Bukkit.getOnlinePlayers()) { + BauSystemBossbar bossbar = BossBarService.instance.get(player, data.region, "simulator_stab_generator"); + bossbar.setColor(BarColor.GREEN); + bossbar.setStyle(BarStyle.SEGMENTED_10); + bossbar(bossbar, true); + } + new Thread(() -> { + try { + Thread.sleep(4000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + for (Player player : Bukkit.getOnlinePlayers()) { + BossBarService.instance.remove(player, data.region, "simulator_stab_generator"); + } + } + }).start(); + } +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/Point.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/Point.java index 0fa5496e..6f8c5929 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/Point.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/Point.java @@ -73,4 +73,8 @@ public class Point { public Location toLocation(Player player, double dx, double dy, double dz) { return new Location(player.getWorld(), x + dx, y + dy, z + dz, player.getLocation().getYaw(), player.getLocation().getPitch()); } + + public BlockVector3 toBlockVector3() { + return BlockVector3.at(this.x, this.y, this.z); + } } \ No newline at end of file