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/BauSystem.properties b/BauSystem/BauSystem_Main/src/BauSystem.properties
index e4dc1b27..90f1d4cf 100644
--- a/BauSystem/BauSystem_Main/src/BauSystem.properties
+++ b/BauSystem/BauSystem_Main/src/BauSystem.properties
@@ -947,6 +947,9 @@ SPEED_TAB_NAME=Input speed
WORLDEDIT_WAND=WorldEdit Wand
WORLDEDIT_LEFTCLICK=Left click: select pos #1
WORLDEDIT_RIGHTCLICK=Right click: select pos #2
+TNT_DETAILS_COMMAND=§8/§etntdetails §8-§7 Toggle information printed after clicking on a TNT
+TNT_DETAILS_ON = §eTNTDetails §aactivated
+TNT_DETAILS_OFF = §eTNTDetails §cdeactivated
TNT_CLICK_HEADER=§8---=== §eTNT §8===---
TNT_CLICK_ORDER=§eEntity Order§8: §e{0}
TNT_CLICK_FUSE_TIME=§eFuseTime§8: §e{0}
diff --git a/BauSystem/BauSystem_Main/src/BauSystem_de.properties b/BauSystem/BauSystem_Main/src/BauSystem_de.properties
index ea6826ed..fca76eb9 100644
--- a/BauSystem/BauSystem_Main/src/BauSystem_de.properties
+++ b/BauSystem/BauSystem_Main/src/BauSystem_de.properties
@@ -889,6 +889,9 @@ SPEED_TAB_NAME=Geschwindigkeit eingeben
WORLDEDIT_WAND=WorldEdit Wand
WORLDEDIT_LEFTCLICK=Left click: select pos #1
WORLDEDIT_RIGHTCLICK=Right click: select pos #2
+TNT_DETAILS_COMMAND=§8/§etntdetails §8-§7 Aktiviert/Deaktiviert das senden von Details beim Klick auf TNT
+TNT_DETAILS_ON = §eTNTDetails §aaktiviert
+TNT_DETAILS_OFF = §eTNTDetails §cdeaktiviert
TNT_CLICK_HEADER=§8---=== §eTNT §8===---
TNT_CLICK_ORDER=§eEntity Order§8: §e{0}
TNT_CLICK_FUSE_TIME=§eFuseTime§8: §e{0}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/FreezeListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/FreezeListener.java
index a284cfa8..673867e7 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/FreezeListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/FreezeListener.java
@@ -11,8 +11,9 @@ import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.data.type.NoteBlock;
import org.bukkit.block.data.type.Switch;
-import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -60,6 +61,24 @@ public class FreezeListener implements Listener, ScoreboardElement {
@EventHandler
public void onPhysicsEvent(BlockPhysicsEvent e) {
if (Region.getRegion(e.getBlock().getLocation()).get(Flag.FREEZE) == FreezeMode.ACTIVE) {
+ if (e.getSourceBlock().getType() == Material.NOTE_BLOCK) {
+ BlockState state = e.getSourceBlock().getState();
+ NoteBlock noteBlock = (NoteBlock) state.getBlockData();
+ if (noteBlock.isPowered()) {
+ Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
+ state.update(true, false);
+ }, 1);
+ }
+ }
+ if (e.getBlock().getType() == Material.NOTE_BLOCK) {
+ BlockState state = e.getBlock().getState();
+ NoteBlock noteBlock = (NoteBlock) state.getBlockData();
+ if (noteBlock.isPowered()) {
+ Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
+ state.update(true, false);
+ }, 1);
+ }
+ }
e.setCancelled(true);
}
}
@@ -71,6 +90,105 @@ public class FreezeListener implements Listener, ScoreboardElement {
}
}
+ @EventHandler
+ public void onNotePlay(NotePlayEvent event) {
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=45, z=98},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=44, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=97},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=99},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=custom_head,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=97},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=96},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=99},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-108, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=45, z=98},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-104, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=45, z=98},type=CYAN_TERRACOTTA,data=Block{minecraft:cyan_terracotta},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=BARRIER,data=Block{minecraft:barrier},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=harp,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@78078831}
+
+
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=45, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=46, z=100},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=49, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=99},type=SMOOTH_STONE,data=Block{minecraft:smooth_stone},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ ////[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=true],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=102},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-108, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-107, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=100},type=STONE_SLAB,data=Block{minecraft:stone_slab}[type=bottom,waterlogged=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-104, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=46, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=48, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-105, y=47, z=100},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=101},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-107, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-105, y=47, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=46, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=48, z=98},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=97},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=99},type=AIR,data=Block{minecraft:air},fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ //[STDOUT] CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b} -> CraftBlock{pos=BlockPosition{x=-106, y=47, z=98},type=NOTE_BLOCK,data=Block{minecraft:note_block}[instrument=basedrum,note=9,powered=false],fluid=net.minecraft.world.level.material.FluidTypeEmpty@1531ed7b}
+ }
+
+
@EventHandler
public void onPistonRetract(BlockPistonRetractEvent e) {
if (Region.getRegion(e.getBlock().getLocation()).get(Flag.FREEZE) == FreezeMode.ACTIVE) {
@@ -108,13 +226,13 @@ public class FreezeListener implements Listener, ScoreboardElement {
}
}
- @EventHandler(priority = EventPriority.MONITOR)
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent e) {
if (Core.getVersion() < 19) return;
if (e.getPlayer().getInventory().getItemInMainHand().getType() == Material.DEBUG_STICK) return;
if (Region.getRegion(e.getBlock().getLocation()).get(Flag.FREEZE) == FreezeMode.ACTIVE) {
- if (e.isCancelled()) return;
e.setCancelled(true);
+ e.getBlock().setType(Material.BARRIER, false);
e.getBlock().setType(Material.AIR, false);
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TpsLib.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TpsLib.java
index 1435aa44..6b9435e1 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TpsLib.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TpsLib.java
@@ -51,7 +51,7 @@ public class TpsLib implements LuaLib {
tpsLib.set("fiveMinute", getter(() -> TPSWatcher.getTPS(TPSWatcher.TPSType.FIVE_MINUTES)));
tpsLib.set("tenMinute", getter(() -> TPSWatcher.getTPS(TPSWatcher.TPSType.TEN_MINUTES)));
tpsLib.set("current", getter(TPSWatcher::getTPS));
- tpsLib.set("limit", getter(tpsSystem::getCurrentTPSLimit));
+ tpsLib.set("limit", getter(TPSSystem::getCurrentTPSLimit));
return tpsLib;
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TracerLib.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TracerLib.java
new file mode 100644
index 00000000..5178bdf9
--- /dev/null
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TracerLib.java
@@ -0,0 +1,113 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2023 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.script.lua.libs;
+
+import de.steamwar.bausystem.features.tracer.TNTPoint;
+import de.steamwar.bausystem.features.tracer.Trace;
+import de.steamwar.bausystem.features.tracer.TraceManager;
+import de.steamwar.linkage.Linked;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+import org.luaj.vm2.LuaTable;
+import org.luaj.vm2.LuaValue;
+import org.luaj.vm2.lib.ZeroArgFunction;
+
+@Linked
+public class TracerLib implements LuaLib {
+ @Override
+ public String name() {
+ return "tracer";
+ }
+
+ private static LuaTable convertTrace(Trace trace) {
+ LuaTable luaTrace = new LuaTable();
+
+ luaTrace.set("getRecords", new ZeroArgFunction() {
+ @Override
+ public LuaValue call() {
+ return LuaValue.listOf(
+ trace.getHistories()
+ .stream()
+ .map((history) -> LuaValue.listOf(history
+ .stream()
+ .map(TracerLib::convertTntPoint)
+ .toArray(LuaValue[]::new)))
+ .toArray(LuaValue[]::new));
+ }
+ });
+
+ luaTrace.set("getId", new ZeroArgFunction() {
+ @Override
+ public LuaValue call() {
+ return LuaValue.valueOf(trace.getUuid().toString());
+ }
+ });
+
+
+ return luaTrace;
+ }
+
+ private static LuaTable convertTntPoint(TNTPoint tntPoint) {
+ Location pointPos = tntPoint.getLocation();
+ LuaTable luaPos = LuaValue.tableOf(new LuaValue[]{
+ LuaValue.valueOf("x"), LuaValue.valueOf(pointPos.getX()),
+ LuaValue.valueOf("y"), LuaValue.valueOf(pointPos.getY()),
+ LuaValue.valueOf("z"), LuaValue.valueOf(pointPos.getZ()),
+ });
+
+ Vector pointVel = tntPoint.getVelocity();
+ LuaTable luaVel = LuaValue.tableOf(new LuaValue[]{
+ LuaValue.valueOf("x"), LuaValue.valueOf(pointVel.getX()),
+ LuaValue.valueOf("y"), LuaValue.valueOf(pointVel.getY()),
+ LuaValue.valueOf("z"), LuaValue.valueOf(pointVel.getZ()),
+ });
+
+ return LuaValue.tableOf(new LuaValue[]{
+ LuaValue.valueOf("pos"), luaPos,
+ LuaValue.valueOf("vel"), luaVel,
+ LuaValue.valueOf("ticksSinceStart"), LuaValue.valueOf(tntPoint.getTicksSinceStart()),
+ LuaValue.valueOf("fuse"), LuaValue.valueOf(tntPoint.getFuse()),
+ LuaValue.valueOf("isExplosion"), LuaValue.valueOf(tntPoint.isExplosion()),
+ LuaValue.valueOf("isInWater"), LuaValue.valueOf(tntPoint.isInWater()),
+ LuaValue.valueOf("hasDestroyedBuild"), LuaValue.valueOf(tntPoint.isDestroyedBuildArea()),
+ LuaValue.valueOf("hasDestroyedTestblock"), LuaValue.valueOf(tntPoint.isDestroyedTestBlock())
+ });
+ }
+
+ @Override
+ public LuaTable get(Player player) {
+ LuaTable rootTable = LuaValue.tableOf();
+
+ rootTable.set("getTraces", new ZeroArgFunction() {
+ @Override
+ public LuaValue call() {
+ return LuaValue.listOf(TraceManager.instance.getAll()
+ .stream()
+ .map(TracerLib::convertTrace)
+ .toArray(LuaValue[]::new));
+ }
+ }
+
+ );
+
+ return rootTable;
+ }
+}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCommand.java
index de0c4b74..bf329b3b 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCommand.java
@@ -76,7 +76,7 @@ public class SimulatorCommand extends SWCommand {
@Register(value = "start", description = "SIMULATOR_START_HELP")
public void start(@Validator Player p, @ErrorMessage("SIMULATOR_NOT_EXISTS") Simulator simulator) {
- SimulatorExecutor.run(simulator);
+ SimulatorExecutor.run(simulator, () -> {});
}
@Register(value = "rename", description = "SIMULATOR_RENAME_HELP")
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java
index de9dae3f..f9629c3d 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java
@@ -168,9 +168,19 @@ public class SimulatorCursor implements Listener {
}
return;
}
- Simulator simulator = SimulatorStorage.getSimulator(player);
- SimulatorWatcher.show(simulator, player);
+ Simulator simulator = SimulatorStorage.getSimulator(player);
+ if (simulator != null && simulator.getStabGenerator() != null) {
+ removeCursor(player);
+ SimulatorWatcher.show(null, player);
+ SWUtils.sendToActionbar(player, "§cGenerating Stab");
+ synchronized (calculating) {
+ calculating.remove(player);
+ }
+ return;
+ }
+
+ SimulatorWatcher.show(simulator, player);
List entities = SimulatorWatcher.getEntitiesOfSimulator(simulator);
RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), entities);
if (rayTraceResult == null) {
@@ -357,7 +367,7 @@ public class SimulatorCursor implements Listener {
if (simulator == null) {
return;
}
- SimulatorExecutor.run(simulator);
+ SimulatorExecutor.run(simulator, () -> {});
return;
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/Simulator.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/Simulator.java
index 91b7a8e1..8dcb8321 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/Simulator.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/Simulator.java
@@ -20,6 +20,7 @@
package de.steamwar.bausystem.features.simulator.data;
import de.steamwar.bausystem.features.simulator.execute.SimulatorAction;
+import de.steamwar.bausystem.features.simulator.execute.SimulatorStabGenerator;
import de.steamwar.inventory.InvCallback;
import de.steamwar.inventory.SWItem;
import lombok.Getter;
@@ -30,13 +31,13 @@ import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.function.BiConsumer;
@Getter
@Setter
@RequiredArgsConstructor
public final class Simulator {
+ private SimulatorStabGenerator stabGenerator = null;
private Material material = Material.BARREL;
private final String name;
private boolean autoTrace = false;
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/SimulatorExecutor.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorExecutor.java
index 5c3d30e0..b052e4c8 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorExecutor.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorExecutor.java
@@ -46,7 +46,7 @@ public class SimulatorExecutor implements Listener {
private static Map>> tickStartActions = new HashMap<>();
private static Map> tickEndActions = new HashMap<>();
- public static boolean run(Simulator simulator) {
+ public static boolean run(Simulator simulator, Runnable onEnd) {
if (currentlyRunning.contains(simulator)) return false;
currentlyRunning.add(simulator);
@@ -69,7 +69,7 @@ public class SimulatorExecutor implements Listener {
public void accept(World world) {
currentlyRunning.remove(simulator);
- if (simulator.isAutoTrace()) {
+ if (simulator.isAutoTrace() && onEnd == null) {
simulator.getGroups()
.stream()
.map(SimulatorGroup::getElements)
@@ -82,10 +82,12 @@ public class SimulatorExecutor implements Listener {
TraceRecorder.instance.stopRecording(region);
});
}
+
+ onEnd.run();
}
});
- if (simulator.isAutoTrace()) {
+ if (simulator.isAutoTrace() && onEnd == null) {
simulator.getGroups()
.stream()
.map(SimulatorGroup::getElements)
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
new file mode 100644
index 00000000..37ca8bf3
--- /dev/null
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorStabGenerator.java
@@ -0,0 +1,45 @@
+/*
+ * 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.Simulator;
+import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
+import de.steamwar.bausystem.region.Region;
+import de.steamwar.bausystem.utils.bossbar.BossBarService;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class SimulatorStabGenerator {
+
+ private final StabData stabData;
+
+ public SimulatorStabGenerator(Region region, Simulator simulator, TNTElement tntElement, int depthLimit) {
+ stabData = new StabData(region, simulator, tntElement, tntElement.getPhases(), depthLimit);
+ new StabSetup(stabData);
+ }
+
+ public void cancel() {
+ stabData.cancel = true;
+ stabData.simulator.setStabGenerator(null);
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ BossBarService.instance.remove(player, stabData.region, "simulator_stab_generator");
+ }
+ }
+}
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/features/simulator/gui/SimulatorTNTGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTGui.java
index a9c178ce..3520720e 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTGui.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTGui.java
@@ -24,8 +24,11 @@ import de.steamwar.bausystem.features.simulator.data.Simulator;
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.simulator.execute.SimulatorStabGenerator;
+import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui;
+import de.steamwar.bausystem.region.Region;
import de.steamwar.inventory.SWItem;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@@ -97,6 +100,14 @@ public class SimulatorTNTGui extends SimulatorScrollGui {
tnt.setDisabled(!tnt.isDisabled());
SimulatorWatcher.update(simulator);
}));
+ inventory.setItem(49, new SWItem(Material.CALIBRATED_SCULK_SENSOR, "§eCreate Stab", click -> {
+ new SimulatorAnvilGui<>(player, "Depth Limit", "", Integer::parseInt, depthLimit -> {
+ if (depthLimit <= 0) return false;
+ simulator.setStabGenerator(new SimulatorStabGenerator(Region.getRegion(player.getLocation()), simulator, tnt, depthLimit));
+ SimulatorWatcher.update(simulator);
+ return true;
+ }, null).open();
+ }));
inventory.setItem(50, new SWItem(Material.CHEST, parent.getElements().size() == 1 ? "§eMake Group" : "§eAdd another TNT to Group", clickType -> {
TNTElement tntElement = new TNTElement(tnt.getPosition().clone());
tntElement.add(new TNTPhase());
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorAnvilGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorAnvilGui.java
index 380dc618..e22c807a 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorAnvilGui.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorAnvilGui.java
@@ -44,7 +44,7 @@ public class SimulatorAnvilGui {
if (error.get()) {
anvilInv.open();
} else {
- back.open();
+ if (back != null) back.open();
}
error.set(false);
}, 0);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorBaseGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorBaseGui.java
index 6fa35d4c..aeb4da13 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorBaseGui.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorBaseGui.java
@@ -22,7 +22,6 @@ package de.steamwar.bausystem.features.simulator.gui.base;
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.core.Core;
-import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.inventory.SWInventory;
import de.steamwar.inventory.SWItem;
import org.bukkit.Bukkit;
@@ -64,7 +63,11 @@ public abstract class SimulatorBaseGui {
if (Core.getVersion() > 19) {
player.getOpenInventory().setTitle(title());
}
- populate();
+ if (simulator != null && simulator.getStabGenerator() != null) {
+ populateStabGenerator();
+ } else {
+ populate();
+ }
if (player.getOpenInventory().getTopInventory() == inv) {
inventory.open();
SimulatorWatcher.watch(player, simulator, this::open);
@@ -84,10 +87,21 @@ public abstract class SimulatorBaseGui {
});
SimulatorWatcher.watch(player, simulator, this::open);
- populate();
+ if (simulator != null && simulator.getStabGenerator() != null) {
+ populateStabGenerator();
+ } else {
+ populate();
+ }
inventory.open();
}
+ private void populateStabGenerator() {
+ inventory.setItem(22, new SWItem(Material.BARRIER, "§cCancel Stab Generator", click -> {
+ simulator.getStabGenerator().cancel();
+ SimulatorWatcher.update(simulator);
+ }));
+ }
+
public boolean shouldOpen() {
return true;
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/panzern/Panzern.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/panzern/Panzern.java
index 3eca97f4..2823beb0 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/panzern/Panzern.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/panzern/Panzern.java
@@ -25,6 +25,7 @@ import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import de.steamwar.bausystem.utils.WorldEditUtils;
+import de.steamwar.core.Core;
import lombok.Getter;
import lombok.SneakyThrows;
import org.bukkit.Location;
@@ -56,7 +57,7 @@ public class Panzern {
private BaseBlock blockType;
private BaseBlock slabType;
- private static final BaseBlock jukeboxType = BlockTypes.JUKEBOX.getDefaultState().toBaseBlock();
+ private static final BaseBlock jukeboxType = (Core.getVersion() > 19 ? BlockTypes.get("lodestone"): BlockTypes.get("jukebox")).getDefaultState().toBaseBlock();
private static final BaseBlock cobwebType = BlockTypes.COBWEB.getDefaultState().toBaseBlock();
private static final BaseBlock airType = BlockTypes.AIR.getDefaultState().toBaseBlock();
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java
index 75b3f8b7..17e0d9f3 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java
@@ -19,8 +19,8 @@
package de.steamwar.bausystem.features.smartplace;
-import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
+import de.steamwar.Reflection;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.configplayer.Config;
@@ -223,7 +223,7 @@ public class SmartPlaceListener implements Listener {
Block block = event.getBlock().getRelative(BlockFace.DOWN);
BlockState old = block.getState();
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
- block.setType(Material.GLASS);
+ block.setType(Material.GLASS, true);
old.update(true, false);
}, 1);
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSCommand.java
index 1b5b51eb..c1d09c63 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSCommand.java
@@ -42,16 +42,16 @@ public class TPSCommand extends SWCommand {
public void genericCommand(Player p, String... args) {
BauSystem.MESSAGE.sendPrefixless("OTHER_TPS_HEAD", p);
BauSystem.MESSAGE.sendPrefixless("OTHER_TPS_MESSAGE", p,
- TPSWatcher.getTPS(TPSWatcher.TPSType.ONE_SECOND),
- TPSWatcher.getTPS(TPSWatcher.TPSType.TEN_SECONDS),
- TPSWatcher.getTPS(TPSWatcher.TPSType.ONE_MINUTE),
- TPSWatcher.getTPS(TPSWatcher.TPSType.FIVE_MINUTES),
- TPSWatcher.getTPS(TPSWatcher.TPSType.TEN_MINUTES)
+ TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND),
+ TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.TEN_SECONDS),
+ TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_MINUTE),
+ TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.FIVE_MINUTES),
+ TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.TEN_MINUTES)
);
}
@Register
public void genericCommand(Player p, TPSWatcher.TPSType type) {
- BauSystem.MESSAGE.sendPrefixless("OTHER_TPS_SINGLE", p, tpsSystem.getTPS(type));
+ BauSystem.MESSAGE.sendPrefixless("OTHER_TPS_SINGLE", p, TPSWatcher.getTPSUnlimited(type));
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java
index 1e25ff18..ac393e57 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java
@@ -56,11 +56,7 @@ import java.util.Arrays;
public class TPSSystem implements Listener {
@Getter
- private double currentTPSLimit = 20;
-
- public double getTPS(TPSWatcher.TPSType tpsType) {
- return TPSWatcher.getTPSUnlimited(tpsType);
- }
+ private static double currentTPSLimit = 20;
public TPSSystem() {
if (TPSFreezeUtils.isCanFreeze()) {
@@ -338,26 +334,26 @@ public class TPSSystem implements Listener {
} else if (TPSFreezeUtils.frozen()) {
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + BauSystem.MESSAGE.parse("SCOREBOARD_TPS_FROZEN", p);
} else {
- return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + tpsColor() + tpsSystem.getTPS(TPSWatcher.TPSType.ONE_SECOND) + tpsLimit();
+ return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + tpsColor() + TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND) + tpsLimit();
}
}
private String tpsColor() {
- double tps = tpsSystem.getTPS(TPSWatcher.TPSType.ONE_SECOND);
- if (tps > tpsSystem.getCurrentTPSLimit() * 0.9) {
+ double tps = TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND);
+ if (tps > TPSSystem.getCurrentTPSLimit() * 0.9) {
return "§a";
}
- if (tps > tpsSystem.getCurrentTPSLimit() * 0.5) {
+ if (tps > TPSSystem.getCurrentTPSLimit() * 0.5) {
return "§e";
}
return "§c";
}
private String tpsLimit() {
- if (tpsSystem.getCurrentTPSLimit() == 20) {
+ if (TPSSystem.getCurrentTPSLimit() == 20) {
return "";
}
- return "§8/§7" + tpsSystem.getCurrentTPSLimit();
+ return "§8/§7" + TPSSystem.getCurrentTPSLimit();
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java
index 6a0a2314..208b49e8 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java
@@ -102,11 +102,14 @@ public class TraceRecorder implements Listener {
*
* @param region region to be recorded
*/
- public void startRecording(Region region) {
- if (activeTraces.containsKey(region)) return;
+ public Trace startRecording(Region region) {
+ if (activeTraces.containsKey(region)) {
+ return activeTraces.get(region).getTrace();
+ }
TraceRecordingWrapper wrappedTrace = new TraceRecordingWrapper(region);
activeTraces.put(region, wrappedTrace);
+ return wrappedTrace.getTrace();
}
/**
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/TraceEntity.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/TraceEntity.java
index 0f785468..75b893ab 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/TraceEntity.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/TraceEntity.java
@@ -20,6 +20,7 @@
package de.steamwar.bausystem.features.tracer.rendering;
import de.steamwar.bausystem.BauSystem;
+import de.steamwar.bausystem.configplayer.Config;
import de.steamwar.bausystem.features.tracer.TNTPoint;
import de.steamwar.bausystem.features.tracer.Trace;
import de.steamwar.bausystem.features.tracer.TraceManager;
@@ -30,10 +31,13 @@ import net.md_5.bungee.api.chat.ClickEvent;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
+import yapion.hierarchy.types.YAPIONValue;
import java.util.List;
import java.util.stream.Collectors;
+import static de.steamwar.bausystem.features.util.TNTClickListener.TNT_CLICK_DETAILS;
+
/**
* Wrapper for the rendering of a record bundle
*/
@@ -66,6 +70,7 @@ public class TraceEntity extends RFallingBlockEntity {
* @param player the player the message should be printed for
*/
public void printIntoChat(Player player) {
+ if (!Config.getInstance().get(player).getOrSetDefault(TNT_CLICK_DETAILS, new YAPIONValue<>(true)).asBoolean().orElse(true)) return;
TNTPoint representative = records.get(0);
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_HEADER", player);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/SkullCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/SkullCommand.java
index 1f50a2ae..e7da48d1 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/SkullCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/SkullCommand.java
@@ -42,6 +42,15 @@ public class SkullCommand extends SWCommand {
super("skull", "head");
}
+ @Register
+ public void giveCommand(@Validator Player p) {
+ if (p.getName().startsWith(".")) {
+ BauSystem.MESSAGE.send("SKULL_INVALID", p);
+ return;
+ }
+ giveCommand(p, p.getName());
+ }
+
@Register(description = "SKULL_HELP")
public void giveCommand(@Validator Player p, @Mapper("player") @ErrorMessage("SKULL_INVALID") String skull) {
ItemStack is = SWItem.getPlayerSkull(skull).getItemStack();
@@ -63,7 +72,7 @@ public class SkullCommand extends SWCommand {
@Override
public List tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
- return Bukkit.getOnlinePlayers().stream().map(Player::getName).filter(s1 -> !s1.endsWith("⍇")).collect(Collectors.toList());
+ return Bukkit.getOnlinePlayers().stream().map(Player::getName).filter(s1 -> !s1.startsWith(".")).collect(Collectors.toList());
}
};
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/TNTClickListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/TNTClickListener.java
index 3284876a..f412b8ad 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/TNTClickListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/TNTClickListener.java
@@ -21,22 +21,46 @@ package de.steamwar.bausystem.features.util;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.Permission;
+import de.steamwar.bausystem.configplayer.Config;
+import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.inventory.EquipmentSlot;
+import yapion.hierarchy.types.YAPIONObject;
+import yapion.hierarchy.types.YAPIONValue;
@Linked
-public class TNTClickListener implements Listener {
+public class TNTClickListener extends SWCommand implements Listener {
+
+ public static final String TNT_CLICK_DETAILS = "tnt_click_details";
+
+ public TNTClickListener() {
+ super("tntdetails");
+ }
+
+ @Register(description = "TNT_DETAILS_COMMAND")
+ public void toggle(Player player) {
+ YAPIONObject yapionObject = Config.getInstance().get(player);
+ if (yapionObject.getOrSetDefault(TNT_CLICK_DETAILS, new YAPIONValue<>(true)).asBoolean().orElse(true)) {
+ yapionObject.put(TNT_CLICK_DETAILS, false);
+ BauSystem.MESSAGE.send("TNT_DETAILS_OFF", player);
+ } else {
+ yapionObject.put(TNT_CLICK_DETAILS, true);
+ BauSystem.MESSAGE.send("TNT_DETAILS_ON", player);
+ }
+ }
@EventHandler
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (event.getHand() != EquipmentSlot.HAND) return;
+ if (!Config.getInstance().get(event.getPlayer()).getOrSetDefault(TNT_CLICK_DETAILS, new YAPIONValue<>(true)).asBoolean().orElse(true)) return;
Entity entity = event.getRightClicked();
if (event.getRightClicked() instanceof TNTPrimed) {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java
index 3b3ea664..f1aed39f 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java
@@ -179,7 +179,12 @@ public class SpectatorListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
- if (event.getMessage().startsWith("/schem save") || event.getMessage().startsWith("//schem save") || event.getMessage().startsWith("/schematic save") || event.getMessage().startsWith("//schematic save")) {
+ if (event.getMessage().startsWith("/schem save") ||
+ event.getMessage().startsWith("//schem save") ||
+ event.getMessage().startsWith("/schematic save") ||
+ event.getMessage().startsWith("//schematic save") ||
+ event.getMessage().startsWith("/download") ||
+ event.getMessage().startsWith("//download")) {
if (!Permission.SUPERVISOR.hasPermission(event.getPlayer())) {
event.setCancelled(true);
event.setMessage("/");
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
diff --git a/BauSystem/build.gradle.kts b/BauSystem/build.gradle.kts
index 712238c8..fd9dca11 100644
--- a/BauSystem/build.gradle.kts
+++ b/BauSystem/build.gradle.kts
@@ -34,3 +34,19 @@ dependencies {
implementation(project(":BauSystem:BauSystem_20"))
implementation(project(":BauSystem:BauSystem_21"))
}
+
+tasks.register("DevBau20") {
+ group = "run"
+ description = "Run a 1.20 Dev Bau"
+ dependsOn(":SpigotCore:shadowJar")
+ dependsOn(":BauSystem:shadowJar")
+ template = "Bau20"
+}
+
+tasks.register("DevBau21") {
+ group = "run"
+ description = "Run a 1.21 Dev Bau"
+ dependsOn(":SpigotCore:shadowJar")
+ dependsOn(":BauSystem:shadowJar")
+ template = "Bau21"
+}
diff --git a/BauSystem/hotkeys.lua b/BauSystem/hotkeys.lua
new file mode 100644
index 00000000..f1182e7a
--- /dev/null
+++ b/BauSystem/hotkeys.lua
@@ -0,0 +1,87 @@
+-- This file is a part of the SteamWar software.
+--
+-- Copyright (C) 2025 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 .
+
+---
+--- This serves both as an example and a quick start to the Stewamwar Script Api
+---
+
+function hotkeys_freeze(pressed)
+ if pressed then
+ exec("/freeze")
+ end
+end
+
+function hotkeys_rgc(pressed)
+ if pressed then
+ exec("/rgc")
+ end
+end
+
+function hotkeys_rgp(pressed)
+ if pressed then
+ exec("/rgp")
+ end
+end
+
+trace_cycle_counter = 0;
+function hotkeys_cycle_trace_view(pressed)
+ if not pressed then
+ return
+ end
+ trace_cycle = (trace_cycle + 1) % 3
+ trace_commands = {"trace hide", "trace show", "trace show -e -c"}
+ exec(trace_commands[trace_cycle + 1])
+end
+
+function hotkeys_tick_step(pressed)
+ if pressed then
+ exec("tick step")
+ end
+end
+
+function hotkeys_tpslimit(pressed)
+ if not pressed then
+ return
+ end
+ if tps.limit() == 20 then
+ exec("tpslimit 200")
+ else
+ exec("tpslimit 20")
+ end
+end
+
+function hotkeys_tb(pressed)
+ if pressed then
+ exec("tb -e")
+ end
+end
+
+function hotkeys_trace_delete(pressed)
+ if pressed then
+ exec("trace delete")
+ end
+end
+
+hotkey("ctrl+g", hotkeys_freeze)
+hotkey("ctrl+c", hotkeys_rgc)
+hotkey("ctrl+v", hotkeys_rgp)
+hotkey("ctrl+x", hotkeys_tick_step)
+hotkey("shift+x", hotkeys_cycle_trace_view)
+hotkey("ctrl+y", hotkeys_tb)
+hotkey("ctrl+alt", hotkeys_trace_delete)
+hotkey("ctrl+h", hotkeys_trace_delete)
+
diff --git a/BauSystem/sw.def.lua b/BauSystem/sw.def.lua
index 613437a1..50095a2d 100644
--- a/BauSystem/sw.def.lua
+++ b/BauSystem/sw.def.lua
@@ -200,21 +200,6 @@ function tnt.onlyTb() return nil end
---@return boolean
function tnt.onlyBuild() return nil end
----@class trace
-local trace = {}
-
----@return boolean
-function trace.active() return nil end
-
----@return boolean
-function trace.auto() return nil end
-
----@return string
-function trace.status() return nil end
-
----@return number
-function trace.time() return nil end
-
---@param name string
---@return iregion
function region.get(name) return nil end
@@ -222,6 +207,25 @@ function region.get(name) return nil end
---@return iregion[]
function region.list() return nil end
+---@class tracerLib
+tracer = {}
+
+---@class TraceRecord
+---@field pos Position
+---@field vel Position
+---@field ticksSinceStart number
+---@field fuse number
+---@field isExplosion boolean
+---@field isInWater boolean
+---@field hasDestroyedBuild boolean
+---@field hasDestroyedTestblock boolean
+
+---@class Tracer
+---@field getId fun(): string
+---@field getRecords fun(): {[number]: {[number]: TraceRecord}}
+
+function tracer.getTraces() return nil end
+
---@class Position
---@field x number
---@field y number
diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java
index a8d7c099..08179979 100644
--- a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java
+++ b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java
@@ -30,7 +30,6 @@ import java.util.zip.GZIPInputStream;
@AllArgsConstructor
@Getter
public class NodeData {
-
static {
new SqlTypeMapper<>(PipedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("PipedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
new SqlTypeMapper<>(ByteArrayInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("ByteArrayInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.java b/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.java
index 71cf83f4..b56a5994 100644
--- a/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.java
+++ b/CommonCore/SQL/src/de/steamwar/sql/NodeDownload.java
@@ -1,7 +1,7 @@
/*
* This file is a part of the SteamWar software.
*
- * Copyright (C) 2021 SteamWar.de-Serverteam
+ * Copyright (C) 2025 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
diff --git a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java
index bece8549..87b7cac4 100644
--- a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java
+++ b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java
@@ -31,10 +31,13 @@ public class SchematicNode {
static {
SchematicType.Normal.name(); // Ensure SchematicType is loaded.
- new SqlTypeMapper<>(SchematicNode.class, null, (rs, identifier) -> { throw new SecurityException("SchematicNode cannot be used as type (recursive select)"); }, (st, index, value) -> st.setInt(index, value.nodeId));
+ new SqlTypeMapper<>(SchematicNode.class, null, (rs, identifier) -> {
+ throw new SecurityException("SchematicNode cannot be used as type (recursive select)");
+ }, (st, index, value) -> st.setInt(index, value.nodeId));
}
private static final Map>> TAB_CACHE = new HashMap<>();
+
public static void clear() {
TAB_CACHE.clear();
}
@@ -42,39 +45,60 @@ public class SchematicNode {
private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode ";
private static final Table table = new Table<>(SchematicNode.class);
- private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem", "NodeType");
- private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem", "NodeType", "NodeRank", "ReplaceColor", "AllowReplay");
+ private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem",
+ "NodeType");
+ private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem",
+ "NodeType", "NodeRank", "ReplaceColor", "AllowReplay");
private static final Statement delete = table.delete(Table.PRIMARY);
- private static final SelectStatement byId = new SelectStatement<>(table, nodeSelector + "WHERE NodeId = ?");
- private static final SelectStatement byOwnerNameParent = new SelectStatement<>(table, nodeSelector + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode " + Statement.NULL_SAFE_EQUALS + "?");
- private static final SelectStatement byParent = new SelectStatement<>(table, nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
- private static final SelectStatement dirsByParent = new SelectStatement<>(table, nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? AND NodeType is NULL ORDER BY NodeName");
- private static final SelectStatement byOwnerType = new SelectStatement<>(table, nodeSelector + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
- private static final SelectStatement byType = new SelectStatement<>(table, nodeSelector + "WHERE NodeType = ? ORDER BY NodeName");
- private static final SelectStatement all = new SelectStatement<>(table, "SELECT * FROM EffectiveSchematicNode WHERE EffectiveOwner = ? ORDER BY NodeName");
- private static final SelectStatement list = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName");
- private static final SelectStatement byParentName = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?");
- private static final SelectStatement schematicAccessibleForUser = new SelectStatement<>(table, "SELECT COUNT(DISTINCT NodeId) FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeId = ?");
- private static final SelectStatement accessibleByUserTypeInParent = new SelectStatement<>(table, "WITH RECURSIVE RSASN AS(WITH RECURSIVE RSAN AS (WITH RSANH AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE NM.UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN INNER JOIN RSA ON RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT * FROM RSANH UNION SELECT SN.NodeId, SN.ParentNode FROM RSANH JOIN SchematicNode SN ON SN.ParentNode = RSANH.NodeId) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN JOIN RSASN ON SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
- private static final SelectStatement accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?");
- private static final SelectStatement byIdAndUser = new SelectStatement<>(table, "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?");
- private static final SelectStatement allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId");
+ private static final SelectStatement byId = new SelectStatement<>(table,
+ nodeSelector + "WHERE NodeId = ?");
+ private static final SelectStatement byOwnerNameParent = new SelectStatement<>(table,
+ nodeSelector + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode " + Statement.NULL_SAFE_EQUALS + "?");
+ private static final SelectStatement byParent = new SelectStatement<>(table,
+ nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
+ private static final SelectStatement dirsByParent = new SelectStatement<>(table, nodeSelector
+ + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? AND NodeType is NULL ORDER BY NodeName");
+ private static final SelectStatement byOwnerType = new SelectStatement<>(table,
+ nodeSelector + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
+ private static final SelectStatement byType = new SelectStatement<>(table,
+ nodeSelector + "WHERE NodeType = ? ORDER BY NodeName");
+ private static final SelectStatement all = new SelectStatement<>(table,
+ "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId");
+ private static final SelectStatement list = new SelectStatement<>(table,
+ "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
+ + Statement.NULL_SAFE_EQUALS
+ + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName");
+ private static final SelectStatement byParentName = new SelectStatement<>(table,
+ "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
+ + Statement.NULL_SAFE_EQUALS
+ + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?");
+ private static final SelectStatement schematicAccessibleForUser = new SelectStatement<>(table,
+ "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeId = ?");
+ private static final SelectStatement accessibleByUserTypeInParent = new SelectStatement<>(table,
+ "WITH RECURSIVE RSASN AS(WITH RECURSIVE RSAN AS (WITH RSANH AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE NM.UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN INNER JOIN RSA ON RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT * FROM RSANH UNION SELECT SN.NodeId, SN.ParentNode FROM RSANH JOIN SchematicNode SN ON SN.ParentNode = RSANH.NodeId) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN JOIN RSASN ON SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId"
+ + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
+ private static final SelectStatement accessibleByUserType = new SelectStatement<>(table,
+ "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?");
+ private static final SelectStatement byIdAndUser = new SelectStatement<>(table,
+ "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?");
+ private static final SelectStatement allParentsOfNode = new SelectStatement<>(table,
+ "WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId");
static {
NodeMember.init();
}
- @Field(keys = {Table.PRIMARY}, autoincrement = true)
+ @Field(keys = { Table.PRIMARY }, autoincrement = true)
private final int nodeId;
- @Field(keys = {"OwnerNameParent"})
+ @Field(keys = { "OwnerNameParent" })
private final int nodeOwner;
@Field(def = "0")
@Getter
private final int effectiveOwner;
- @Field(keys = {"OwnerNameParent"})
+ @Field(keys = { "OwnerNameParent" })
private String nodeName;
- @Field(keys = {"OwnerNameParent"}, nullable = true)
+ @Field(keys = { "OwnerNameParent" }, nullable = true)
private Integer parentNode;
@Field(def = "CURRENT_TIMESTAMP")
private Timestamp lastUpdate;
@@ -102,8 +126,7 @@ public class SchematicNode {
SchematicType nodeType,
int nodeRank,
boolean replaceColor,
- boolean allowReplay
- ) {
+ boolean allowReplay) {
this.nodeId = nodeId;
this.nodeOwner = nodeOwner;
this.effectiveOwner = effectiveOwner;
@@ -118,7 +141,7 @@ public class SchematicNode {
}
public static List getAll(SteamwarUser user) {
- return all.listSelect(user);
+ return all.listSelect(user, user, user);
}
public static Map> getAllMap(SteamwarUser user) {
@@ -130,7 +153,8 @@ public class SchematicNode {
}
public static SchematicNode byParentName(SteamwarUser user, Integer schematicId, String name) {
- return byParentName.select(user, schematicId, user, name, user, schematicId, user, schematicId, schematicId, name);
+ return byParentName.select(user, schematicId, user, name, user, schematicId, user, schematicId, schematicId,
+ name);
}
public static List accessibleByUserType(SteamwarUser user, SchematicType type) {
@@ -142,10 +166,11 @@ public class SchematicNode {
}
public static boolean schematicAccessibleForUser(SteamwarUser user, Integer schematicId) {
- return schematicAccessibleForUser.select(user, schematicId) != null;
+ return schematicAccessibleForUser.select(user, user, user, schematicId) != null;
}
- public static List accessibleByUserTypeParent(SteamwarUser user, SchematicType type, Integer parentId) {
+ public static List accessibleByUserTypeParent(SteamwarUser user, SchematicType type,
+ Integer parentId) {
return accessibleByUserTypeInParent.listSelect(user, user, type, user, parentId);
}
@@ -160,7 +185,8 @@ public class SchematicNode {
private static Map> map(List in) {
Map> map = new HashMap<>();
for (SchematicNode effectiveSchematicNode : in) {
- map.computeIfAbsent(effectiveSchematicNode.getOptionalParent().orElse(0), k -> new ArrayList<>()).add(effectiveSchematicNode);
+ map.computeIfAbsent(effectiveSchematicNode.getOptionalParent().orElse(0), k -> new ArrayList<>())
+ .add(effectiveSchematicNode);
}
return map;
}
@@ -218,7 +244,8 @@ public class SchematicNode {
return byId.select(id);
}
- public static List getAccessibleSchematicsOfTypeInParent(int owner, String schemType, Integer parent) {
+ public static List getAccessibleSchematicsOfTypeInParent(int owner, String schemType,
+ Integer parent) {
return accessibleByUserTypeParent(SteamwarUser.get(owner), SchematicType.fromDB(schemType), parent);
}
@@ -283,10 +310,12 @@ public class SchematicNode {
}
if (s.contains("/")) {
String[] layers = s.split("/");
- Optional currentNode = Optional.ofNullable(SchematicNode.byParentName(user, null, layers[0]));
+ Optional currentNode = Optional
+ .ofNullable(SchematicNode.byParentName(user, null, layers[0]));
for (int i = 1; i < layers.length; i++) {
int finalI = i;
- Optional node = currentNode.map(effectiveSchematicNode -> SchematicNode.byParentName(user, effectiveSchematicNode.getId(), layers[finalI]));
+ Optional node = currentNode.map(effectiveSchematicNode -> SchematicNode
+ .byParentName(user, effectiveSchematicNode.getId(), layers[finalI]));
if (!node.isPresent()) {
return null;
} else {
@@ -365,7 +394,7 @@ public class SchematicNode {
@Deprecated
public void setType(String type) {
- if(isDir())
+ if (isDir())
throw new SecurityException("Node is Directory");
this.nodeType = SchematicType.fromDB(type);
updateDB();
@@ -376,13 +405,13 @@ public class SchematicNode {
}
public String getFileEnding() {
- if(isDir())
+ if (isDir())
throw new SecurityException("Node is Directory");
return NodeData.get(this).getNodeFormat().getFileEnding();
}
public int getRank() {
- if(isDir())
+ if (isDir())
throw new SecurityException("Node is Directory");
return nodeRank;
}
@@ -393,19 +422,19 @@ public class SchematicNode {
}
public void setRank(int rank) {
- if(isDir())
+ if (isDir())
throw new SecurityException("Node is Directory");
this.nodeRank = rank;
}
public SchematicType getSchemtype() {
- if(isDir())
+ if (isDir())
throw new SecurityException("Is Directory");
return nodeType;
}
public void setSchemtype(SchematicType type) {
- if(isDir())
+ if (isDir())
throw new SecurityException("Is Directory");
this.nodeType = type;
updateDB();
@@ -416,7 +445,7 @@ public class SchematicNode {
}
public void setReplaceColor(boolean replaceColor) {
- if(isDir())
+ if (isDir())
throw new SecurityException("Is Directory");
this.replaceColor = replaceColor;
updateDB();
@@ -427,14 +456,15 @@ public class SchematicNode {
}
public void setAllowReplay(boolean allowReplay) {
- if(isDir())
+ if (isDir())
throw new SecurityException("Is Directory");
this.allowReplay = allowReplay;
updateDB();
}
public SchematicNode getParentNode() {
- if(parentNode == null) return null;
+ if (parentNode == null)
+ return null;
return SchematicNode.getSchematicNode(parentNode);
}
@@ -486,7 +516,7 @@ public class SchematicNode {
}
public String generateBreadcrumbs() {
- if(brCache == null) {
+ if (brCache == null) {
brCache = generateBreadcrumbs("/");
}
return brCache;
@@ -495,11 +525,15 @@ public class SchematicNode {
public String generateBreadcrumbs(String split) {
StringBuilder builder = new StringBuilder(getName());
Optional currentNode = Optional.of(this);
- if(currentNode.map(SchematicNode::isDir).orElse(false)) {
+ if (currentNode.map(SchematicNode::isDir).orElse(false)) {
builder.append(split);
}
while (currentNode.isPresent()) {
- currentNode = currentNode.flatMap(schematicNode -> Optional.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner)).map(NodeMember::getParent).orElse(schematicNode.getOptionalParent())).map(SchematicNode::getSchematicNode);
+ currentNode = currentNode
+ .flatMap(schematicNode -> Optional
+ .ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner))
+ .map(NodeMember::getParent).orElse(schematicNode.getOptionalParent()))
+ .map(SchematicNode::getSchematicNode);
currentNode.ifPresent(node -> builder.insert(0, split).insert(0, node.getName()));
}
return builder.toString();
@@ -508,17 +542,22 @@ public class SchematicNode {
public List> generateBreadcrumbsMap(SteamwarUser user) {
List> map = new ArrayList<>();
Optional currentNode = Optional.of(this);
- if(currentNode.map(SchematicNode::isDir).orElse(false)) {
+ if (currentNode.map(SchematicNode::isDir).orElse(false)) {
map.add(new AbstractMap.SimpleEntry<>(getName(), getId()));
}
while (currentNode.isPresent()) {
- currentNode = currentNode.flatMap(schematicNode -> Optional.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner)).map(NodeMember::getParent).orElse(schematicNode.getOptionalParent())).map(SchematicNode::getSchematicNode);
+ currentNode = currentNode
+ .flatMap(schematicNode -> Optional
+ .ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner))
+ .map(NodeMember::getParent).orElse(schematicNode.getOptionalParent()))
+ .map(SchematicNode::getSchematicNode);
currentNode.ifPresent(node -> map.add(0, new AbstractMap.SimpleEntry<>(node.getName(), node.getId())));
}
return map;
}
private static final List FORBIDDEN_NAMES = Collections.unmodifiableList(Arrays.asList("public"));
+
public static boolean invalidSchemName(String[] layers) {
for (String layer : layers) {
if (layer.isEmpty()) {
@@ -535,7 +574,7 @@ public class SchematicNode {
layer.contains(" ")) {
return true;
}
- if(FORBIDDEN_NAMES.contains(layer.toLowerCase())) {
+ if (FORBIDDEN_NAMES.contains(layer.toLowerCase())) {
return true;
}
}
@@ -549,14 +588,15 @@ public class SchematicNode {
}
int index = s.lastIndexOf("/");
String cacheKey = index == -1 ? "" : s.substring(0, index);
- if(TAB_CACHE.containsKey(user.getId()) && TAB_CACHE.get(user.getId()).containsKey(cacheKey)) {
+ if (TAB_CACHE.containsKey(user.getId()) && TAB_CACHE.get(user.getId()).containsKey(cacheKey)) {
return new ArrayList<>(TAB_CACHE.get(user.getId()).get(cacheKey));
}
List list = new ArrayList<>();
if (s.contains("/")) {
String preTab = s.substring(0, s.lastIndexOf("/") + 1);
SchematicNode pa = SchematicNode.getNodeFromPath(user, preTab);
- if (pa == null) return new ArrayList<>();
+ if (pa == null)
+ return new ArrayList<>();
List nodes = SchematicNode.list(user, pa.getId());
String br = pa.generateBreadcrumbs();
nodes.forEach(node -> list.add((sws ? "/" : "") + br + node.getName() + (node.isDir() ? "/" : "")));
diff --git a/CommonCore/SQL/src/de/steamwar/sql/UserElo.java b/CommonCore/SQL/src/de/steamwar/sql/UserElo.java
index 235fc302..d9876c4c 100644
--- a/CommonCore/SQL/src/de/steamwar/sql/UserElo.java
+++ b/CommonCore/SQL/src/de/steamwar/sql/UserElo.java
@@ -75,15 +75,7 @@ public class UserElo {
public static void setElo(int userId, String gameMode, int elo) {
emblemCache.remove(userId);
-
- int oldPlacement = getPlacement(getElo(userId, gameMode).orElse(0), gameMode);
- int newPlacement = getPlacement(elo, gameMode);
-
gameModeUserEloCache.getOrDefault(gameMode, Collections.emptyMap()).remove(userId);
- if (oldPlacement <= 3 || newPlacement <= 3) {
- emblemCache.clear();
- }
-
setElo.update(Season.getSeason(), gameMode, userId, elo);
}
@@ -112,27 +104,17 @@ public class UserElo {
public static String getEmblemProgression(String gameMode, int userId) {
switch (getProgression(userId, gameMode)) {
case -1:
- return "§f/ §8∨ ∧ ∨ ∧ ∨ ∧ ❂ III II I";
+ return "§8❱❱❱❱ ❂";
case 0:
- return "§8/ §6∨ §8∧ ∨ ∧ ∨ ∧ ❂ III II I";
+ return "§e❱§8❱❱❱ ❂";
case 1:
- return "§8/ ∨ §6∧ §8∨ ∧ ∨ ∧ ❂ III II I";
+ return "§e❱❱§8❱❱ ❂";
case 2:
- return "§8/ ∨ ∧ §7∨ §8∧ ∨ ∧ ❂ III II I";
+ return "§e❱❱❱§8❱ ❂";
case 3:
- return "§8/ ∨ ∧ ∨ §7∧ §8∨ ∧ ❂ III II I";
+ return "§e❱❱❱❱§8 ❂";
case 4:
- return "§8/ ∨ ∧ ∨ ∧ §e∨ §8∧ ❂ III II I";
- case 5:
- return "§8/ ∨ ∧ ∨ ∧ ∨ §e∧ §8❂ III II I";
- case 6:
- return "§8/ ∨ ∧ ∨ ∧ ∨ ∧ §5❂ §8III II I";
- case 7:
- return "§8/ ∨ ∧ ∨ ∧ ∨ ∧ ❂ §5III §8II I";
- case 8:
- return "§8/ ∨ ∧ ∨ ∧ ∨ ∧ ❂ III §5II §8I";
- case 9:
- return "§8/ ∨ ∧ ∨ ∧ ∨ ∧ ❂ III II §5I";
+ return "§8❱❱❱❱ §5❂";
default:
throw new SecurityException("Progression is not in range");
}
@@ -142,19 +124,11 @@ public class UserElo {
int elo = getElo(userId, gameMode).orElse(-1);
if (elo < 0) return -1;
- if (elo <= 100) return 0;
- if (elo <= 200) return 1;
- if (elo <= 400) return 2;
- if (elo <= 600) return 3;
- if (elo <= 900) return 4;
- if (elo <= 1200) return 5;
-
- int placement = getPlacement(elo, gameMode);
- if (placement == 1) return 9;
- if (placement == 2) return 8;
- if (placement == 3) return 7;
-
- return 6;
+ if (elo < 150) return 0;
+ if (elo < 350) return 1;
+ if (elo < 600) return 2;
+ if (elo < 900) return 3;
+ return 4;
}
public static String toEmblem(int progression) {
@@ -162,25 +136,15 @@ public class UserElo {
case -1:
return "";
case 0:
- return "§6∨ ";
+ return "§e❱ ";
case 1:
- return "§6∧ ";
+ return "§e❱❱ ";
case 2:
- return "§7∨ ";
+ return "§e❱❱❱ ";
case 3:
- return "§7∧ ";
+ return "§e❱❱❱❱ ";
case 4:
- return "§e∨ ";
- case 5:
- return "§e∧ ";
- case 6:
return "§5❂ ";
- case 7:
- return "§5III ";
- case 8:
- return "§5II ";
- case 9:
- return "§5I ";
default:
throw new SecurityException("Progression out of range");
}
diff --git a/FightSystem/FightSystem_Core/build.gradle.kts b/FightSystem/FightSystem_Core/build.gradle.kts
index 2f044447..93dd59c4 100644
--- a/FightSystem/FightSystem_Core/build.gradle.kts
+++ b/FightSystem/FightSystem_Core/build.gradle.kts
@@ -29,4 +29,5 @@ dependencies {
compileOnly(libs.worldedit15)
compileOnly(libs.fastutil)
compileOnly(libs.authlib)
+ compileOnly(libs.netty)
}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java
index 57400063..bff38170 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java
@@ -23,10 +23,7 @@ import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.core.Core;
import de.steamwar.fightsystem.commands.*;
import de.steamwar.fightsystem.countdown.*;
-import de.steamwar.fightsystem.event.HellsBells;
-import de.steamwar.fightsystem.event.Meteor;
-import de.steamwar.fightsystem.event.PersistentDamage;
-import de.steamwar.fightsystem.event.TNTDistributor;
+import de.steamwar.fightsystem.event.*;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.fight.FightWorld;
@@ -97,6 +94,7 @@ public class FightSystem extends JavaPlugin {
new PrepareSchem();
new TestJoin();
new NormalJoin();
+ new Spectator();
new RunningWorldInteraction();
new PersonalKitCreator();
new ArrowStopper();
@@ -135,6 +133,7 @@ public class FightSystem extends JavaPlugin {
new PersistentDamage();
new TNTDistributor();
new WinconditionAmongUs();
+ new NoGravity();
new NoPlayersOnlineCountdown();
new PreSchemCountdown();
@@ -156,6 +155,7 @@ public class FightSystem extends JavaPlugin {
new LockschemCommand();
new StateCommand();
new SkipCommand();
+ new TechhiderbugCommand();
new TPSWarpCommand();
new UnrankCommand();
new WinCommand();
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties
index dde4e266..455e0444 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties
@@ -76,6 +76,7 @@ KITSEARCH_TITLE=Search for kit
SCHEM_NO_ENEMY=§cNo schematic selection without an opponent
SCHEM_TITLE={0} selection
+SCHEM_DIRT=§eDirt Block
SCHEM_PUBLIC=§ePublic {0}
SCHEM_UNCHECKED=§eUnchecked {0}
SCHEM_PRIVATE=§ePrivate {0}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties
index 470226a8..cd294425 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties
@@ -70,6 +70,7 @@ KITSEARCH_TITLE=Nach Kit suchen
SCHEM_NO_ENEMY=§cKeine Schematicwahl ohne Gegner
SCHEM_TITLE={0}-Auswahl
+SCHEM_DIRT=§eErdblock
SCHEM_PUBLIC=§eÖffentliches {0}
SCHEM_UNCHECKED=§eUngeprüftes {0}
SCHEM_PRIVATE=§ePrivates {0}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java
index 2ca6849c..237d860e 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java
@@ -24,15 +24,14 @@ import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.ai.AIManager;
import de.steamwar.fightsystem.fight.*;
+import de.steamwar.fightsystem.fight.Fight;
+import de.steamwar.fightsystem.fight.FightPlayer;
import de.steamwar.fightsystem.listener.PersonalKitCreator;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.utils.ColorConverter;
import de.steamwar.inventory.*;
import de.steamwar.message.Message;
-import de.steamwar.sql.PersonalKit;
-import de.steamwar.sql.SchematicNode;
-import de.steamwar.sql.SchematicType;
-import de.steamwar.sql.SteamwarUser;
+import de.steamwar.sql.*;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -40,7 +39,10 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
public class GUI {
@@ -206,6 +208,14 @@ public class GUI {
for (int i = 0; i < Config.SubTypes.size(); i++) {
setupSchemTypeRow(p, inv, Config.SubTypes.get(i), i + 1);
}
+ if (!Config.test() && SteamwarUser.get(p.getUniqueId()).hasPerm(UserPerm.TEAM)) {
+ SchematicNode node = SchematicNode.getSchematicNode(-1, Config.GameName, (Integer) null);
+ if (node != null) {
+ inv.setItem(2, new SWItem(SWItem.getMaterial(node.getItem()), msg.parse("SCHEM_DIRT", p), click -> {
+ schemSelect(p, node);
+ }));
+ }
+ }
inv.setCallback(-999, (ClickType click) -> p.closeInventory());
inv.open();
}
@@ -241,14 +251,18 @@ public class GUI {
private static void schemDialog(Player p, SchematicType type, boolean publicSchems, boolean unchecked){
SchematicSelector selector = new SchematicSelector(p, Config.test() ? SchematicSelector.selectSchematic() : SchematicSelector.selectSchematicType(unchecked ? type.checkType() : type), node -> {
- FightTeam fightTeam = Fight.getPlayerTeam(p);
- if(fightTeam == null)
- return;
- if(Config.test() || FightState.getFightState() != FightState.POST_SCHEM_SETUP)
- fightTeam.pasteSchem(node);
- p.closeInventory();
+ schemSelect(p, node);
});
selector.setPublicMode(publicSchems?SchematicSelector.PublicMode.PUBLIC_ONLY:SchematicSelector.PublicMode.PRIVATE_ONLY);
selector.open();
}
+
+ private static void schemSelect(Player p, SchematicNode node) {
+ FightTeam fightTeam = Fight.getPlayerTeam(p);
+ if(fightTeam == null)
+ return;
+ if(Config.test() || FightState.getFightState() != FightState.POST_SCHEM_SETUP)
+ fightTeam.pasteSchem(node);
+ p.closeInventory();
+ }
}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java
new file mode 100644
index 00000000..3080c13e
--- /dev/null
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechhiderbugCommand.java
@@ -0,0 +1,80 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 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.fightsystem.commands;
+
+import com.comphenix.tinyprotocol.TinyProtocol;
+import de.steamwar.fightsystem.ArenaMode;
+import de.steamwar.fightsystem.Config;
+import de.steamwar.fightsystem.FightSystem;
+import de.steamwar.fightsystem.fight.Fight;
+import de.steamwar.fightsystem.states.FightState;
+import de.steamwar.fightsystem.states.StateDependentCommand;
+import de.steamwar.sql.SWException;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.logging.Level;
+
+public class TechhiderbugCommand implements CommandExecutor {
+
+ public TechhiderbugCommand() {
+ new StateDependentCommand(ArenaMode.All, FightState.All, "techhiderbug", this);
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command cmd, String alias, String[] args) {
+ StringWriter writer = new StringWriter();
+
+ try {
+ writer.append("ArenaMode: ").append(Config.mode.name()).append('\n');
+ writer.append("FightState: ").append(FightState.getFightState().name()).append('\n');
+ writer.append("TechHider enabled: ").append(FightState.getStateDependentFeatures().get(FightSystem.getTechHider()).toString()).append('\n');
+
+ writer.append("Arena region: ").append(Config.ArenaRegion.toString()).append('\n');
+ writer.append("Team regions: ");
+ Fight.teams().forEach(t -> writer.append(t.getName()).append(':').append(t.getExtendRegion().toString()).append(' '));
+ writer.append('\n');
+
+ writer.append("HullHider regions: ");
+ FightSystem.getHullHider().getHullMap().forEach((t, h) -> writer.append(t.getName()).append(':').append(h.getRegion().toString()).append(' '));
+ writer.append('\n');
+
+ writer.append("Hidden regions: ");
+ FightSystem.getTechHider().getHiddenRegion().forEach((p, r) -> writer.append(p.getName()).append(':').append(r.toString()).append(' '));
+ writer.append('\n');
+
+ writer.append("TinyProtocol: ");
+ writer.append(TinyProtocol.instance.toString()).append('\n');
+
+ writer.append('\n').append("Netty pipelines:\n");
+ Bukkit.getOnlinePlayers().forEach(p -> writer.append(p.getName()).append(": ").append(String.join(" ", TinyProtocol.instance.getPlayerInterceptors().get(p).getChannel().pipeline().names())).append('\n'));
+ } catch (Exception e) {
+ writer.append("Error while generating bug report: ").append(e.getMessage()).append('\n');
+ Bukkit.getLogger().log(Level.SEVERE, "Error while generating bug report", e);
+ }
+
+ SWException.log("Techhider-Bug reported by " + sender.getName() + ": " + Arrays.toString(args), writer.toString());
+ return false;
+ }
+}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/event/NoGravity.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/event/NoGravity.java
new file mode 100644
index 00000000..12246f8e
--- /dev/null
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/event/NoGravity.java
@@ -0,0 +1,41 @@
+/*
+ * 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.fightsystem.event;
+
+import de.steamwar.fightsystem.states.FightState;
+import de.steamwar.fightsystem.states.StateDependentListener;
+import de.steamwar.fightsystem.winconditions.Winconditions;
+import org.bukkit.entity.EntityType;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntitySpawnEvent;
+
+public class NoGravity implements Listener {
+
+ public NoGravity() {
+ new StateDependentListener(Winconditions.NO_GRAVITY, FightState.All, this);
+ }
+
+ @EventHandler
+ public void onEntitySpawn(EntitySpawnEvent event) {
+ if (event.getEntityType() == EntityType.PLAYER) return;
+ event.getEntity().setGravity(false);
+ }
+}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java
index 5b8f62f9..1f205122 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java
@@ -104,40 +104,6 @@ public class Fight {
return null;
}
- @SuppressWarnings("deprecation")
- public static void setPlayerGamemode(Player player, GameMode gameMode) {
- player.setGameMode(gameMode);
-
- if(gameMode == GameMode.SPECTATOR) {
- for(Player currentPlayer : Bukkit.getServer().getOnlinePlayers()) {
- if(currentPlayer.getUniqueId() != player.getUniqueId() && currentPlayer.getGameMode() == GameMode.SPECTATOR) {
- currentPlayer.hidePlayer(player);
- player.hidePlayer(currentPlayer);
- }
- }
-
- if(Config.test() || Config.isReferee(player))
- return;
-
- Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> {
- if(!player.isOnline())
- return;
- pseudoSpectator(player, true);
- }, 1);
- }else if(gameMode == GameMode.SURVIVAL) {
- for(Player currentPlayer : Bukkit.getServer().getOnlinePlayers()) {
- if(currentPlayer.getUniqueId() != player.getUniqueId() && currentPlayer.getGameMode() == GameMode.SPECTATOR) {
- currentPlayer.showPlayer(player);
- player.showPlayer(currentPlayer);
- }
- }
- }
- }
-
- public static void pseudoSpectator(Player player, boolean enable) {
- TinyProtocol.instance.sendPacket(player, ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.GAMEMODE, new GameProfile(player.getUniqueId(), player.getName()), enable ? GameMode.CREATIVE : GameMode.SPECTATOR));
- }
-
public static boolean publicOnly() {
if (Config.OnlyPublicSchematics) {
return true;
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java
index 3a6a12a2..0cb68f71 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java
@@ -73,7 +73,6 @@ public class FightTeam {
if(ArenaMode.VariableTeams.contains(Config.mode)){
notReadyKit.setItem(2, "REQUESTS", new ItemBuilder(Material.PAPER).build(), GUI::chooseJoinRequests);
- notReadyKit.setItem(3, "MANAGE_PLAYERS", SWItem.getPlayerSkull("AdmiralSeekrank").getItemStack(), GUI::managePlayers);
if(!AIManager.availableAIs().isEmpty())
notReadyKit.setItem(6, "ADD_AI", new ItemBuilder(Material.REDSTONE).build(), GUI::addAI);
}
@@ -81,6 +80,7 @@ public class FightTeam {
if(Config.test())
notReadyKit.setItem(5, "CHOOSE_SCHEMATIC", new ItemBuilder(SWItem.getMaterial("CAULDRON_ITEM")).enchant().build(), GUI::preSchemDialog);
+ notReadyKit.setItem(3, "MANAGE_PLAYERS", SWItem.getPlayerSkull("AdmiralSeekrank").getItemStack(), GUI::managePlayers);
notReadyKit.setItem(4, "TEAM_NOT_READY", new ItemBuilder(SWItem.getDye(10), (short) 10).enchant().build(), player -> Objects.requireNonNull(Fight.getPlayerTeam(player)).setReady(true));
}
private static final HotbarKit chooseSchemKit = new HotbarKit(notReadyKit);
@@ -282,9 +282,9 @@ public class FightTeam {
FightSystem.getHullHider().updatePlayer(player);
if(FightState.Spectate.contains(FightState.getFightState())) {
- Fight.setPlayerGamemode(player, GameMode.SPECTATOR);
+ player.setGameMode(GameMode.SPECTATOR);
} else {
- Fight.setPlayerGamemode(player, GameMode.SURVIVAL);
+ player.setGameMode(GameMode.SURVIVAL);
(FightState.ingame() ? fightPlayer.getKit() : memberKit).loadToPlayer(player);
}
});
@@ -317,7 +317,7 @@ public class FightTeam {
entity.teleport(Config.SpecSpawn);
fightPlayer.ifPlayer(player -> {
- Fight.setPlayerGamemode(player, GameMode.SPECTATOR);
+ player.setGameMode(GameMode.SPECTATOR);
player.getInventory().clear();
if(player.isOnline()){
@@ -517,14 +517,14 @@ public class FightTeam {
@Override
public void enable() {
players.values().forEach(fightPlayer -> {
- fightPlayer.ifPlayer(player -> Fight.setPlayerGamemode(player, GameMode.SPECTATOR));
+ fightPlayer.ifPlayer(player -> player.setGameMode(GameMode.SPECTATOR));
fightPlayer.getEntity().teleport(FightTeam.this.spawn);
});
}
@Override
public void disable() {
- players.values().forEach(fightPlayer -> fightPlayer.ifPlayer(player -> Fight.setPlayerGamemode(player, GameMode.SURVIVAL)));
+ players.values().forEach(fightPlayer -> fightPlayer.ifPlayer(player -> player.setGameMode(GameMode.SURVIVAL)));
}
}
}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/HotbarKit.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/HotbarKit.java
index 5bc1d844..6b3df110 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/HotbarKit.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/HotbarKit.java
@@ -29,11 +29,15 @@ import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.states.StateDependentTask;
import de.steamwar.fightsystem.utils.ItemBuilder;
+import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
@@ -107,6 +111,19 @@ public class HotbarKit extends Kit {
Player player = event.getPlayer();
int slot = player.getInventory().getHeldItemSlot();
+ click(player, slot, event);
+ }
+
+ @EventHandler
+ public void onInventoryClick(InventoryClickEvent event) {
+ int slot = event.getSlot();
+ if (slot < 0 || slot >= HOTBAR_SIZE) return;
+
+ Player player = (Player) event.getWhoClicked();
+ click(player, slot, event);
+ }
+
+ private void click(Player player, int slot, Cancellable event) {
Kit activeKit = activeKits.get(player);
if(!(activeKit instanceof HotbarKit) || PersonalKitCreator.inKitCreator(player) || activeKit.getInventory()[slot] == null)
return;
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/LeaveableArena.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/LeaveableArena.java
index 9d0bb4e2..36a5a189 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/LeaveableArena.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/LeaveableArena.java
@@ -84,6 +84,6 @@ public class LeaveableArena implements Listener {
private void markInArena(Player player) {
spectatorsInArena.put(player, player.getGameMode());
- Fight.setPlayerGamemode(player, GameMode.SPECTATOR);
+ player.setGameMode(GameMode.SPECTATOR);
}
}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Permanent.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Permanent.java
index 2f3138ec..4976463c 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Permanent.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Permanent.java
@@ -74,7 +74,7 @@ public class Permanent implements Listener {
public void handlePlayerRespawn(PlayerRespawnEvent event){
Player player = event.getPlayer();
if(Fight.fighting(player)) {
- Fight.setPlayerGamemode(player, GameMode.SPECTATOR);
+ player.setGameMode(GameMode.SPECTATOR);
FightTeam team = Fight.getPlayerTeam(player);
event.setRespawnLocation(team == null ? Config.SpecSpawn : team.getSpawn());
@@ -98,11 +98,11 @@ public class Permanent implements Listener {
FightPlayer fp = Fight.getFightPlayer(player);
if (!Config.ArenaLeaveable && fp == null) {
- Fight.setPlayerGamemode(player, GameMode.SPECTATOR);
+ player.setGameMode(GameMode.SPECTATOR);
spectatorTeam.addEntry(player.getName());
player.teleport(Config.SpecSpawn);
} else if(fp != null && !fp.isLiving()) {
- Fight.setPlayerGamemode(player, GameMode.SPECTATOR);
+ player.setGameMode(GameMode.SPECTATOR);
player.teleport(fp.getTeam().getSpawn());
}
}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/PrepareSchem.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/PrepareSchem.java
index 288eda76..29ccc434 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/PrepareSchem.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/PrepareSchem.java
@@ -86,7 +86,10 @@ public class PrepareSchem implements Listener {
if(schemExists(schem))
return;
+ SchematicNode old = schem;
schem = SchematicNode.createSchematicNode(schem.getOwner(), preparedName(schem), schem.getParent(), Config.SchematicType.checkType().toDB(), schem.getItem());
+ schem.setReplaceColor(old.replaceColor());
+ schem.setAllowReplay(old.allowReplay());
try{
WorldeditWrapper.impl.saveSchem(schem, region, minY);
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Spectator.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Spectator.java
new file mode 100644
index 00000000..399970ca
--- /dev/null
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Spectator.java
@@ -0,0 +1,114 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 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.fightsystem.listener;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerGameModeChangeEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+import com.comphenix.tinyprotocol.TinyProtocol;
+import com.mojang.authlib.GameProfile;
+
+import de.steamwar.core.ProtocolWrapper;
+import de.steamwar.fightsystem.ArenaMode;
+import de.steamwar.fightsystem.Config;
+import de.steamwar.fightsystem.fight.Fight;
+import de.steamwar.fightsystem.fight.FightPlayer;
+import de.steamwar.fightsystem.states.FightState;
+import de.steamwar.fightsystem.states.StateDependentListener;
+import de.steamwar.fightsystem.states.StateDependentTask;
+
+
+public class Spectator implements Listener {
+
+ private final Set pseudoSpectator = new HashSet<>();
+
+ public Spectator() {
+ new StateDependentListener(ArenaMode.AntiTest, FightState.All, this);
+ new StateDependentTask(ArenaMode.AntiTest, FightState.All, this::pseudoSpectatorCheck, 1, 1);
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void handlePlayerJoin(PlayerJoinEvent e) {
+ Player player = e.getPlayer();
+
+ if(player.getGameMode() == GameMode.SPECTATOR)
+ gameModeChange(player, GameMode.SPECTATOR);
+ }
+
+ @EventHandler
+ public void onGameModeChange(PlayerGameModeChangeEvent e) {
+ gameModeChange(e.getPlayer(), e.getNewGameMode());
+ }
+
+ @SuppressWarnings("deprecation")
+ private void gameModeChange(Player player, GameMode gameMode) {
+ if (gameMode == GameMode.SPECTATOR) {
+ for(Player p : Bukkit.getServer().getOnlinePlayers()) {
+ if(p.getUniqueId() != player.getUniqueId())
+ p.hidePlayer(player);
+ }
+ } else {
+ for(Player p : Bukkit.getServer().getOnlinePlayers()) {
+ if(p.getUniqueId() != player.getUniqueId())
+ p.showPlayer(player);
+ }
+ }
+ }
+
+ @EventHandler
+ public void playerQuit(PlayerQuitEvent e) {
+ pseudoSpectator.remove(e.getPlayer());
+ }
+
+ private void pseudoSpectatorCheck() {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.getGameMode() != GameMode.SPECTATOR) {
+ pseudoSpectator.remove(player);
+ continue;
+ }
+
+ if (Config.isReferee(player))
+ continue;
+
+ FightPlayer fightPlayer = Fight.getFightPlayer(player);
+ if (fightPlayer == null || !fightPlayer.getTeam().getExtendRegion().playerInRegion(player.getLocation())) {
+ if (pseudoSpectator.add(player))
+ pseudoSpectator(player, true);
+ } else {
+ if (pseudoSpectator.remove(player))
+ pseudoSpectator(player, false);
+ }
+ }
+ }
+
+ private static void pseudoSpectator(Player player, boolean enable) {
+ TinyProtocol.instance.sendPacket(player, ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.GAMEMODE, new GameProfile(player.getUniqueId(), player.getName()), enable ? GameMode.CREATIVE : GameMode.SPECTATOR));
+ }
+}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/TeamArea.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/TeamArea.java
index 2720b25c..2f888452 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/TeamArea.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/TeamArea.java
@@ -19,9 +19,14 @@
package de.steamwar.fightsystem.listener;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
-import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.events.BoardingEvent;
import de.steamwar.fightsystem.events.TeamDeathEvent;
import de.steamwar.fightsystem.events.TeamLeaveEvent;
@@ -32,23 +37,12 @@ import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.OneShotStateDependent;
import de.steamwar.fightsystem.states.StateDependentListener;
-import de.steamwar.fightsystem.states.StateDependentTask;
-import org.bukkit.Bukkit;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerJoinEvent;
-import org.bukkit.event.player.PlayerQuitEvent;
-
-import java.util.HashSet;
-import java.util.Set;
public class TeamArea implements Listener {
private final FightTeam team;
private final Border spectatorBorder;
private final Border bordingBorder;
- private final Set realSpectator = new HashSet<>();
public TeamArea(FightTeam team) {
this.team = team;
@@ -56,7 +50,6 @@ public class TeamArea implements Listener {
this.bordingBorder = new Border(team.getExtendRegion().to2d(), true, 1, "NO_ENTERN", team.getName() + ".boardingBorder");
new StateDependentListener(ArenaMode.AntiTest, FightState.All, this);
- new StateDependentTask(ArenaMode.AntiTest, FightState.TeamFix, this::realSpectatorCheck, 1, 1);
new OneShotStateDependent(ArenaMode.AntiTest, FightState.Spectate, () -> Fight.teams().forEach(t -> t.getPlayers().forEach(this::teamSpectator)));
}
@@ -114,30 +107,5 @@ public class TeamArea implements Listener {
Player player = e.getPlayer();
spectatorBorder.removePlayer(player);
bordingBorder.removePlayer(player);
- realSpectator.remove(player);
- }
-
- private void realSpectatorCheck() {
- for(FightPlayer fightPlayer : team.getPlayers()) {
- if(fightPlayer.isLiving())
- continue;
-
- fightPlayer.ifPlayer(player -> {
- boolean inRegion = team.getExtendRegion().playerInRegion(player.getLocation());
- if(inRegion && !realSpectator.contains(player)) {
- realSpectator.add(player);
-
- //Later to prevent race condition with Fight.setSpecatator() during respawn
- Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> {
- if(!player.isOnline())
- return;
- Fight.pseudoSpectator(player, false);
- }, 2);
- }else if(!inRegion && realSpectator.contains(player)) {
- Fight.pseudoSpectator(player, true);
- realSpectator.remove(player);
- }
- });
- }
}
}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/FightState.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/FightState.java
index 1d5acf35..cadcec66 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/FightState.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/states/FightState.java
@@ -49,6 +49,7 @@ public enum FightState {
public static final Set AntiIngame = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(PRE_RUNNING, RUNNING)));
public static final Set AntiSpectate = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(SPECTATE)));
+ @Getter
private static final Map stateDependentFeatures = new HashMap<>();
@Getter
private static FightState fightState = PRE_LEADER_SETUP;
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java
index a67c6d5d..caf39e79 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Hull.java
@@ -45,6 +45,7 @@ public class Hull {
return material.isOccluding() || Config.HiddenBlocks.contains(material);
}
+ @Getter
private final Region region;
private final boolean groundVisible;
private final IntVector[] directions;
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java
index 455b960d..c050656d 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java
@@ -33,6 +33,7 @@ import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.states.StateDependentTask;
import de.steamwar.techhider.TechHider;
+import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -56,6 +57,7 @@ import java.util.function.Function;
public class HullHider implements Listener {
+ @Getter
private final Map hullMap = new HashMap<>();
private final Hull[] hulls;
private final Map, BiFunction> packetHiders = new HashMap<>();
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java
index 6a559799..60d37be8 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java
@@ -159,4 +159,9 @@ public class Region {
public interface TriConsumer{
void accept(T x, V y, U z);
}
+
+ @Override
+ public String toString() {
+ return minX + "," + minY + "," + minZ + "->" + maxX + "," + maxY + "," + maxZ;
+ }
}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java
index c45d7ab6..bf890168 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHiderWrapper.java
@@ -32,6 +32,7 @@ import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.techhider.TechHider;
+import lombok.Getter;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -51,6 +52,7 @@ public class TechHiderWrapper extends StateDependent implements TechHider.Locati
public static final boolean ENABLED = !Config.OnlyPublicSchematics && !Config.test() && Config.TechhiderActive;
+ @Getter
private final ConcurrentHashMap hiddenRegion = new ConcurrentHashMap<>();
private final ConcurrentHashMap patterns = new ConcurrentHashMap<>();
private final TechHider techHider;
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionBlocks.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionBlocks.java
index b9b0c9f7..72c0873a 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionBlocks.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionBlocks.java
@@ -84,6 +84,9 @@ public class WinconditionBlocks extends Wincondition implements PrintableWincond
}
private void check() {
+ // Edge Case for DirtBlock
+ if (blocks.isEmpty()) return;
+
blocks.removeIf(block -> !isOfType.test(block));
if(blocks.isEmpty())
win(Fight.getOpposite(team), "WIN_TECHKO", team.getColoredName());
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionPercent.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionPercent.java
index 37d3fafa..f98bdecc 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionPercent.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionPercent.java
@@ -78,6 +78,7 @@ public class WinconditionPercent extends Wincondition implements PrintableWincon
private int totalBlocks = 0;
private int currentBlocks = 0;
+ private boolean countAnyBlock = false;
private TeamPercent(FightTeam team, Winconditions wincondition) {
this.team = team;
@@ -98,7 +99,7 @@ public class WinconditionPercent extends Wincondition implements PrintableWincon
}
event.blockList().forEach(block -> {
- if (Config.PercentBlocks.contains(block.getType()) == Config.PercentBlocksWhitelist) {
+ if (countAnyBlock || Config.PercentBlocks.contains(block.getType()) == Config.PercentBlocksWhitelist) {
currentBlocks--;
}
});
@@ -108,10 +109,16 @@ public class WinconditionPercent extends Wincondition implements PrintableWincon
private void enable() {
totalBlocks = 0;
+ countAnyBlock = false;
team.getSchemRegion().forEach((x, y, z) -> {
if (Config.PercentBlocks.contains(Config.world.getBlockAt(x, y, z).getType()) == Config.PercentBlocksWhitelist)
totalBlocks++;
});
+ // Edge Case for DirtBlock
+ if (totalBlocks == 0) {
+ totalBlocks = team.getSchemRegion().volume();
+ countAnyBlock = true;
+ }
currentBlocks = totalBlocks;
postEnable.accept(team);
}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/Winconditions.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/Winconditions.java
index 296cf97e..2aaecae6 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/Winconditions.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/Winconditions.java
@@ -39,5 +39,6 @@ public enum Winconditions {
METEOR,
AMONG_US,
PERSISTENT_DAMAGE,
- TNT_DISTRIBUTION
+ TNT_DISTRIBUTION,
+ NO_GRAVITY,
}
diff --git a/FightSystem/FightSystem_Core/src/plugin.yml b/FightSystem/FightSystem_Core/src/plugin.yml
index 64ece716..6925bf69 100644
--- a/FightSystem/FightSystem_Core/src/plugin.yml
+++ b/FightSystem/FightSystem_Core/src/plugin.yml
@@ -27,4 +27,5 @@ commands:
resettb:
tpslimit:
tpswarp:
+ techhiderbug:
unrank:
\ No newline at end of file
diff --git a/FightSystem/build.gradle.kts b/FightSystem/build.gradle.kts
index 0cd412bc..87849826 100644
--- a/FightSystem/build.gradle.kts
+++ b/FightSystem/build.gradle.kts
@@ -39,3 +39,13 @@ dependencies {
implementation(project(":FightSystem:FightSystem_20"))
implementation(project(":FightSystem:FightSystem_21"))
}
+
+tasks.register("WarGear20") {
+ group = "run"
+ description = "Run a WarGear 1.20 Fight Server"
+ dependsOn(":SpigotCore:shadowJar")
+ dependsOn(":FightSystem:shadowJar")
+ template = "WarGear20"
+ worldName = "arenas/Pentraki"
+ config = "WarGear20.yml"
+}
diff --git a/LobbySystem/src/de/steamwar/lobby/jumpandrun/JumpAndRun.java b/LobbySystem/src/de/steamwar/lobby/jumpandrun/JumpAndRun.java
index f8ce3338..68097463 100644
--- a/LobbySystem/src/de/steamwar/lobby/jumpandrun/JumpAndRun.java
+++ b/LobbySystem/src/de/steamwar/lobby/jumpandrun/JumpAndRun.java
@@ -67,7 +67,7 @@ public class JumpAndRun extends BasicListener {
int count = CLICKED_COUNT.getOrDefault(player, -1);
if (count >= 0) {
- if (count > 60) {
+ if (count > 20) {
toReset.add(player);
return;
}
@@ -104,12 +104,18 @@ public class JumpAndRun extends BasicListener {
return;
}
Vector point = points.get(index);
- if (location.getY() < point.getY()) {
- return;
- }
- if (location.toVector().distanceSquared(point) >= 12.25) {
+ if (location.getY() < point.getY()) index = -2;
+ if (location.toVector().distanceSquared(point) >= 17) index = -2;
+ if (index > 0 && index < points.size() - 1) {
+ Vector nextPoint = points.get(index + 1);
+ if (location.getY() >= nextPoint.getY() && location.toVector().distanceSquared(nextPoint) < 17) {
+ index = index + 1;
+ }
+ }
+ if (index == -2) {
return;
}
+
CURRENT_POS.put(event.getPlayer(), index);
event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.4F, 1);
if (index < points.size() - 1) {
diff --git a/MissileWars/src/de/steamwar/misslewars/MWTeam.java b/MissileWars/src/de/steamwar/misslewars/MWTeam.java
index 8abc5bc9..b5ee7c51 100644
--- a/MissileWars/src/de/steamwar/misslewars/MWTeam.java
+++ b/MissileWars/src/de/steamwar/misslewars/MWTeam.java
@@ -184,6 +184,7 @@ public class MWTeam {
public void leave(Player p) {
if (!players.contains(p)) return;
+ players.remove(p);
for (ItemStack stack : p.getInventory().getContents()) {
if (stack == null) continue;
@@ -198,7 +199,6 @@ public class MWTeam {
if (players.isEmpty() && MissileWars.getFightState() == FightState.FIGHTING)
MissileWars.end(WinReasons.NO_ENEMY, enemy());
- players.remove(p);
sbteam.removePlayer(p);
}
diff --git a/MissileWars/src/de/steamwar/misslewars/countdowns/EndCountdown.java b/MissileWars/src/de/steamwar/misslewars/countdowns/EndCountdown.java
index 292071a6..f2d3183b 100644
--- a/MissileWars/src/de/steamwar/misslewars/countdowns/EndCountdown.java
+++ b/MissileWars/src/de/steamwar/misslewars/countdowns/EndCountdown.java
@@ -37,7 +37,7 @@ public class EndCountdown extends StateDependent {
@Override
public void enable() {
if (Config.isEvent()) {
- task = Bukkit.getScheduler().runTaskLater(MissileWars.getPlugin(), this::stop, 1200);
+ task = Bukkit.getScheduler().runTaskLater(MissileWars.getPlugin(), this::stop, 200);
} else {
task = Bukkit.getScheduler().runTaskLater(MissileWars.getPlugin(), this::restart, Config.EndTime);
}
diff --git a/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoChecker15.java b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoChecker15.java
index 9dd5e456..a97cb133 100644
--- a/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoChecker15.java
+++ b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoChecker15.java
@@ -31,57 +31,6 @@ import java.util.*;
import java.util.stream.Collectors;
public class AutoChecker15 implements AutoChecker.IAutoChecker {
- private static final Set INVENTORY = EnumSet.of(
- Material.BARREL,
- Material.BLAST_FURNACE,
- Material.BREWING_STAND,
- Material.CAMPFIRE,
- Material.CHEST,
- Material.DISPENSER,
- Material.DROPPER,
- Material.FURNACE,
- Material.HOPPER,
- Material.JUKEBOX,
- Material.SHULKER_BOX,
- Material.WHITE_SHULKER_BOX,
- Material.ORANGE_SHULKER_BOX,
- Material.MAGENTA_SHULKER_BOX,
- Material.LIGHT_BLUE_SHULKER_BOX,
- Material.YELLOW_SHULKER_BOX,
- Material.LIME_SHULKER_BOX,
- Material.PINK_SHULKER_BOX,
- Material.GRAY_SHULKER_BOX,
- Material.LIGHT_GRAY_SHULKER_BOX,
- Material.CYAN_SHULKER_BOX,
- Material.PURPLE_SHULKER_BOX,
- Material.BLUE_SHULKER_BOX,
- Material.BROWN_SHULKER_BOX,
- Material.GREEN_SHULKER_BOX,
- Material.RED_SHULKER_BOX,
- Material.BLACK_SHULKER_BOX,
- Material.SMOKER,
- Material.TRAPPED_CHEST);
-
- private static final Set FLOWERS = EnumSet.of(
- Material.CORNFLOWER,
- Material.POPPY,
- Material.FERN,
- Material.DANDELION,
- Material.BLUE_ORCHID,
- Material.ALLIUM,
- Material.AZURE_BLUET,
- Material.RED_TULIP,
- Material.ORANGE_TULIP,
- Material.WHITE_TULIP,
- Material.PINK_TULIP,
- Material.OXEYE_DAISY,
- Material.LILY_OF_THE_VALLEY,
- Material.WITHER_ROSE,
- Material.SUNFLOWER,
- Material.DIAMOND_HORSE_ARMOR,
- Material.IRON_HORSE_ARMOR,
- Material.GOLDEN_HORSE_ARMOR,
- Material.HONEY_BOTTLE);
public AutoChecker.BlockScanResult scan(Clipboard clipboard) {
AutoChecker.BlockScanResult result = new AutoChecker.BlockScanResult();
@@ -98,7 +47,7 @@ public class AutoChecker15 implements AutoChecker.IAutoChecker {
result.getBlockCounts().merge(material, 1, Integer::sum);
- if(INVENTORY.contains(material)) {
+ if(AutoCheckerItems.impl.getInventoryMaterials().contains(material)) {
checkInventory(result, block, material, new BlockPos(x, y, z));
}
@@ -125,7 +74,7 @@ public class AutoChecker15 implements AutoChecker.IAutoChecker {
));
itemsInInv.put(Material.FIRE_CHARGE, EnumSet.of(Material.DISPENSER));
itemsInInv.put(Material.ARROW, EnumSet.of(Material.DISPENSER));
- FLOWERS.forEach(material -> itemsInInv.put(material, INVENTORY));
+ AutoCheckerItems.impl.getAllowedMaterialsInInventory().forEach(material -> itemsInInv.put(material, AutoCheckerItems.impl.getInventoryMaterials()));
}
private void checkInventory(AutoChecker.BlockScanResult result, BaseBlock block, Material material, BlockPos pos) {
diff --git a/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems15.java b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems15.java
new file mode 100644
index 00000000..0d853c16
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems15.java
@@ -0,0 +1,90 @@
+/*
+ * 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.schematicsystem.autocheck;
+
+import org.bukkit.Material;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+public class AutoCheckerItems15 implements AutoCheckerItems {
+
+ private static final Set INVENTORY = EnumSet.of(
+ Material.BARREL,
+ Material.BLAST_FURNACE,
+ Material.BREWING_STAND,
+ Material.CAMPFIRE,
+ Material.CHEST,
+ Material.DISPENSER,
+ Material.DROPPER,
+ Material.FURNACE,
+ Material.HOPPER,
+ Material.JUKEBOX,
+ Material.SHULKER_BOX,
+ Material.WHITE_SHULKER_BOX,
+ Material.ORANGE_SHULKER_BOX,
+ Material.MAGENTA_SHULKER_BOX,
+ Material.LIGHT_BLUE_SHULKER_BOX,
+ Material.YELLOW_SHULKER_BOX,
+ Material.LIME_SHULKER_BOX,
+ Material.PINK_SHULKER_BOX,
+ Material.GRAY_SHULKER_BOX,
+ Material.LIGHT_GRAY_SHULKER_BOX,
+ Material.CYAN_SHULKER_BOX,
+ Material.PURPLE_SHULKER_BOX,
+ Material.BLUE_SHULKER_BOX,
+ Material.BROWN_SHULKER_BOX,
+ Material.GREEN_SHULKER_BOX,
+ Material.RED_SHULKER_BOX,
+ Material.BLACK_SHULKER_BOX,
+ Material.SMOKER,
+ Material.TRAPPED_CHEST);
+
+ private static final Set FLOWERS = EnumSet.of(
+ Material.CORNFLOWER,
+ Material.POPPY,
+ Material.FERN,
+ Material.DANDELION,
+ Material.BLUE_ORCHID,
+ Material.ALLIUM,
+ Material.AZURE_BLUET,
+ Material.RED_TULIP,
+ Material.ORANGE_TULIP,
+ Material.WHITE_TULIP,
+ Material.PINK_TULIP,
+ Material.OXEYE_DAISY,
+ Material.LILY_OF_THE_VALLEY,
+ Material.WITHER_ROSE,
+ Material.SUNFLOWER,
+ Material.DIAMOND_HORSE_ARMOR,
+ Material.IRON_HORSE_ARMOR,
+ Material.GOLDEN_HORSE_ARMOR,
+ Material.HONEY_BOTTLE);
+
+ @Override
+ public Set getInventoryMaterials() {
+ return INVENTORY;
+ }
+
+ @Override
+ public Set getAllowedMaterialsInInventory() {
+ return FLOWERS;
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_19/build.gradle.kts b/SchematicSystem/SchematicSystem_19/build.gradle.kts
new file mode 100644
index 00000000..38fcd471
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_19/build.gradle.kts
@@ -0,0 +1,33 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 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 .
+ */
+
+plugins {
+ steamwar.java
+}
+
+dependencies {
+ compileOnly(project(":SpigotCore", "default"))
+ compileOnly(project(":SchematicSystem:SchematicSystem_Core", "default"))
+ compileOnly(project(":SchematicSystem:SchematicSystem_15", "default"))
+
+ compileOnly(libs.spigotapi)
+
+ compileOnly(libs.nms19)
+ compileOnly(libs.fawe18)
+}
diff --git a/SchematicSystem/SchematicSystem_19/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems19.java b/SchematicSystem/SchematicSystem_19/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems19.java
new file mode 100644
index 00000000..0c004cfe
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_19/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems19.java
@@ -0,0 +1,75 @@
+/*
+ * 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.schematicsystem.autocheck;
+
+import org.bukkit.Material;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+public class AutoCheckerItems19 extends AutoCheckerItems15 {
+
+ private static final Set ALLOWED_ITEMS_IN_INVENTORY = EnumSet.of(
+ // 64-stackable Items
+ Material.CORNFLOWER,
+ Material.POPPY,
+ Material.FERN,
+ Material.DANDELION,
+ Material.BLUE_ORCHID,
+ Material.ALLIUM,
+ Material.AZURE_BLUET,
+ Material.RED_TULIP,
+ Material.ORANGE_TULIP,
+ Material.WHITE_TULIP,
+ Material.PINK_TULIP,
+ Material.OXEYE_DAISY,
+ Material.LILY_OF_THE_VALLEY,
+ Material.WITHER_ROSE,
+ Material.SUNFLOWER,
+ // 16-stackable Items
+ Material.HONEY_BOTTLE,
+ // Non-stackable items
+ Material.DIAMOND_HORSE_ARMOR,
+ Material.IRON_HORSE_ARMOR,
+ Material.GOLDEN_HORSE_ARMOR,
+ // Disks
+ Material.MUSIC_DISC_11,
+ Material.MUSIC_DISC_13,
+ Material.MUSIC_DISC_CAT,
+ Material.MUSIC_DISC_BLOCKS,
+ Material.MUSIC_DISC_CHIRP,
+ Material.MUSIC_DISC_FAR,
+ Material.MUSIC_DISC_MALL,
+ Material.MUSIC_DISC_MELLOHI,
+ Material.MUSIC_DISC_STAL,
+ Material.MUSIC_DISC_STRAD,
+ Material.MUSIC_DISC_WAIT,
+ Material.MUSIC_DISC_WARD,
+ Material.MUSIC_DISC_OTHERSIDE,
+ Material.MUSIC_DISC_PIGSTEP,
+ Material.MUSIC_DISC_RELIC,
+ Material.MUSIC_DISC_5
+ );
+
+ @Override
+ public Set getAllowedMaterialsInInventory() {
+ return ALLOWED_ITEMS_IN_INVENTORY;
+ }
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems.java
new file mode 100644
index 00000000..fb103f67
--- /dev/null
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems.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.schematicsystem.autocheck;
+
+import de.steamwar.core.VersionDependent;
+import de.steamwar.schematicsystem.SchematicSystem;
+import org.bukkit.Material;
+
+import java.util.Set;
+
+public interface AutoCheckerItems {
+
+ AutoCheckerItems impl = VersionDependent.getVersionImpl(SchematicSystem.getInstance());
+
+ Set getInventoryMaterials();
+ Set getAllowedMaterialsInInventory();
+}
diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java
index ff797b67..31c29bd0 100644
--- a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java
+++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java
@@ -35,10 +35,10 @@ public class DownloadCommand extends SWCommand {
@Register(help = true)
public void genericCommand(Player player, String... args) {
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
- SchematicNode copyNode = SchematicNode.getSchematicNode(user.getId(), "//copy", 0);
+ SchematicNode copyNode = SchematicNode.getSchematicNode(user.getId(), "//copy", (Integer) null);
boolean newSchem = false;
- if(copyNode == null) {
- copyNode = SchematicNode.createSchematicNode(user.getId(), "//copy", 0, SchematicType.Normal.toDB(), "");
+ if (copyNode == null) {
+ copyNode = SchematicNode.createSchematicNode(user.getId(), "//copy", null, SchematicType.Normal.toDB(), "");
newSchem = true;
}
@@ -46,13 +46,13 @@ public class DownloadCommand extends SWCommand {
new SchematicData(copyNode).saveFromPlayer(player);
} catch (IOException e) {
SchematicSystem.MESSAGE.send("DOWNLOAD_ERROR", player);
- if(newSchem) {
+ if (newSchem) {
copyNode.delete();
}
throw new SecurityException(e);
} catch (NoClipboardException e) {
SchematicSystem.MESSAGE.send("COMMAND_SAVE_CLIPBOARD_EMPTY", player);
- if(newSchem) {
+ if (newSchem) {
copyNode.delete();
}
return;
diff --git a/SchematicSystem/build.gradle.kts b/SchematicSystem/build.gradle.kts
index f9871adc..813550b2 100644
--- a/SchematicSystem/build.gradle.kts
+++ b/SchematicSystem/build.gradle.kts
@@ -30,4 +30,5 @@ dependencies {
implementation(project(":SchematicSystem:SchematicSystem_Core"))
implementation(project(":SchematicSystem:SchematicSystem_8"))
implementation(project(":SchematicSystem:SchematicSystem_15"))
+ implementation(project(":SchematicSystem:SchematicSystem_19"))
}
diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/techhider/BlockIds14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/techhider/BlockIds14.java
index ebf5e952..6e2c0397 100644
--- a/SpigotCore/SpigotCore_14/src/de/steamwar/techhider/BlockIds14.java
+++ b/SpigotCore/SpigotCore_14/src/de/steamwar/techhider/BlockIds14.java
@@ -66,8 +66,8 @@ public class BlockIds14 implements BlockIds {
return getBlock.invoke(null, material);
}
- private static final Reflection.Method getCombinedId = Reflection.getTypedMethod(TechHider.block, null, int.class, TechHider.iBlockData);
- private int getCombinedId(Object blockData) {
+ @Override
+ public int getCombinedId(Object blockData) {
return (int) getCombinedId.invoke(null, blockData);
}
}
diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/techhider/BlockIds8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/techhider/BlockIds8.java
index 538e8dbd..64ac6c41 100644
--- a/SpigotCore/SpigotCore_8/src/de/steamwar/techhider/BlockIds8.java
+++ b/SpigotCore/SpigotCore_8/src/de/steamwar/techhider/BlockIds8.java
@@ -25,6 +25,12 @@ import java.util.Collections;
import java.util.Set;
public class BlockIds8 implements BlockIds {
+ @Override
+ public int getCombinedId(Object iBlockData) {
+ int id = (int) getCombinedId.invoke(null, iBlockData); // blockState << 12 | blockId
+ return (id & 4095) | (id >> 12);
+ }
+
@Override
@SuppressWarnings("deprecation")
public int materialToId(Material material) {
diff --git a/SpigotCore/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java b/SpigotCore/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java
index 7cca9c95..6f1dbf1a 100644
--- a/SpigotCore/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java
+++ b/SpigotCore/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java
@@ -23,6 +23,7 @@ import de.steamwar.Reflection;
import de.steamwar.Reflection.Field;
import de.steamwar.core.Core;
import io.netty.channel.*;
+import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -67,8 +68,20 @@ public class TinyProtocol implements Listener {
private boolean closed;
private final Map, List>> packetFilters = new HashMap<>();
+ @Getter
private final Map playerInterceptors = new HashMap<>();
+ @Override
+ public String toString() {
+ return "TinyProtocol{" +
+ "plugin=" + plugin +
+ ", connections=" + connections +
+ ", closed=" + closed +
+ ", packetFilters=" + packetFilters +
+ ", playerInterceptors=" + playerInterceptors +
+ '}';
+ }
+
private TinyProtocol(final Plugin plugin) {
this.plugin = plugin;
this.connections = networkManagers.get(getServerConnection(plugin));
@@ -82,6 +95,7 @@ public class TinyProtocol implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerLogin(PlayerLoginEvent e) {
+ plugin.getLogger().info("Creating PacketInterceptor for: " + e.getPlayer().getName() + " (" + closed + ")");
if(closed)
return;
new PacketInterceptor(e.getPlayer());
@@ -116,6 +130,8 @@ public class TinyProtocol implements Listener {
}
public final void close() {
+ plugin.getLogger().log(Level.INFO, "Closing PacketInterceptor", new Exception("Stacktrace"));
+
if(closed)
return;
closed = true;
@@ -136,17 +152,18 @@ public class TinyProtocol implements Listener {
private static final Field getChannel = Reflection.getField(networkManager, Channel.class, 0);
private static final Field getUUID = Reflection.getField(networkManager, UUID.class, 0);
- private final class PacketInterceptor extends ChannelDuplexHandler {
+ public final class PacketInterceptor extends ChannelDuplexHandler {
private final Player player;
+ @Getter
private final Channel channel;
private PacketInterceptor(Player player) {
this.player = player;
- channel = getChannel.get(connections.stream().filter(connection -> player.getUniqueId().equals(getUUID.get(connection))).findAny().orElseThrow(() -> {
+ channel = connections.stream().filter(connection -> player.getUniqueId().equals(getUUID.get(connection))).map(getChannel::get).filter(Channel::isActive).findAny().orElseThrow(() -> {
Bukkit.getScheduler().runTask(plugin, () -> player.kickPlayer("Connection failure."));
return new SecurityException("Could not find channel for player " + player.getName());
- }));
+ });
if(!channel.isActive())
return;
@@ -154,14 +171,15 @@ public class TinyProtocol implements Listener {
synchronized (playerInterceptors) {
playerInterceptors.put(player, this);
}
+ plugin.getLogger().info("Adding Techhider for: " + player.getName());
try {
channel.pipeline().addBefore("packet_handler", HANDLER_NAME, this);
- } catch (IllegalArgumentException e) {
+ } catch (IllegalArgumentException | NoSuchElementException e) {
Bukkit.getScheduler().runTask(plugin, () -> player.kickPlayer("Connection failure."));
throw new SecurityException(e);
}
- }
+ }
private void sendPacket(Object packet) {
channel.pipeline().writeAndFlush(packet);
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/PersonalKit.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/PersonalKit.java
index fcc5a092..36e31490 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/PersonalKit.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/PersonalKit.java
@@ -1,7 +1,7 @@
/*
This file is a part of the SteamWar software.
- Copyright (C) 2020 SteamWar.de-Serverteam
+ 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
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java
index 62f00369..5ab944dc 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java
@@ -1,7 +1,7 @@
/*
* This file is a part of the SteamWar software.
*
- * Copyright (C) 2022 SteamWar.de-Serverteam
+ * Copyright (C) 2025 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
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/BlockIds.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/BlockIds.java
index 8e129a1d..fa2f7f6e 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/BlockIds.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/BlockIds.java
@@ -19,6 +19,7 @@
package de.steamwar.techhider;
+import de.steamwar.Reflection;
import de.steamwar.core.Core;
import de.steamwar.core.VersionDependent;
import org.bukkit.Material;
@@ -28,6 +29,9 @@ import java.util.Set;
public interface BlockIds {
BlockIds impl = VersionDependent.getVersionImpl(Core.getInstance());
+ Reflection.Method getCombinedId = Reflection.getTypedMethod(TechHider.block, null, int.class, TechHider.iBlockData);
+
+ int getCombinedId(Object iBlockData);
int materialToId(Material material);
Set materialToAllIds(Material material);
}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java
index 03063eb8..021d2fe4 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java
@@ -49,10 +49,8 @@ public class TechHider {
public static final Class> craftMagicNumbers = Reflection.getClass("org.bukkit.craftbukkit.util.CraftMagicNumbers");
private static final Reflection.Method getBlockByMaterial = Reflection.getTypedMethod(craftMagicNumbers, "getBlock", block, Material.class);
- private static final Reflection.Method getBlockByBlockData = Reflection.getTypedMethod(iBlockData, null, block);
- private static final Reflection.Method getMaterialByBlock = Reflection.getTypedMethod(craftMagicNumbers, "getMaterial", Material.class, block);
public boolean iBlockDataHidden(Object iBlockData) {
- return obfuscate.contains((Material) getMaterialByBlock.invoke(null, getBlockByBlockData.invoke(iBlockData)));
+ return obfuscateIds.contains(BlockIds.impl.getCombinedId(iBlockData));
}
public static final Object AIR = getBlockDataByBlock.invoke(getBlockByMaterial.invoke(null, Material.AIR));
@@ -66,15 +64,12 @@ public class TechHider {
@Getter
private final int obfuscationTargetId;
@Getter
- private final Set obfuscate;
- @Getter
private final Set obfuscateIds;
@Getter
private final Set hiddenBlockEntities;
public TechHider(LocationEvaluator locationEvaluator, Material obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) {
this.locationEvaluator = locationEvaluator;
- this.obfuscate = obfuscate;
this.obfuscateIds = obfuscate.stream().flatMap(m -> BlockIds.impl.materialToAllIds(m).stream()).collect(Collectors.toSet());
this.hiddenBlockEntities = hiddenBlockEntities;
this.obfuscationTarget = getBlockDataByBlock.invoke(getBlockByMaterial.invoke(null, obfuscationTarget));
diff --git a/TNTLeague/src/de/steamwar/tntleague/events/IngameListener.kt b/TNTLeague/src/de/steamwar/tntleague/events/IngameListener.kt
index f3722c22..7ae0618f 100644
--- a/TNTLeague/src/de/steamwar/tntleague/events/IngameListener.kt
+++ b/TNTLeague/src/de/steamwar/tntleague/events/IngameListener.kt
@@ -35,6 +35,8 @@ import org.bukkit.event.player.PlayerAttemptPickupItemEvent
import org.bukkit.event.player.PlayerInteractEntityEvent
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerMoveEvent
+import org.bukkit.event.player.*
+import org.bukkit.persistence.PersistentDataType
object IngameListener : Listener {
@@ -75,9 +77,9 @@ object IngameListener : Listener {
@EventHandler
fun onPickupCoins(e: PlayerAttemptPickupItemEvent) {
- if (e.item.itemStack.isSimilar(DealerInventory.coins)) {
- TNTLeagueGame.getTeam(e.player)?.coins =
- e.item.itemStack.amount + (TNTLeagueGame.getTeam(e.player)?.coins ?: 0)
+ if (e.item.itemStack.persistentDataContainer.has(DealerInventory.coinKey)) {
+ val numberOfCoins = e.item.itemStack.persistentDataContainer[DealerInventory.coinKey, PersistentDataType.INTEGER] ?: 0
+ TNTLeagueGame.getTeam(e.player)?.coins = (e.item.itemStack.amount * numberOfCoins) + (TNTLeagueGame.getTeam(e.player)?.coins ?: 0)
e.item.itemStack.amount = 0
e.isCancelled = true
diff --git a/TNTLeague/src/de/steamwar/tntleague/game/TNTLeagueGame.kt b/TNTLeague/src/de/steamwar/tntleague/game/TNTLeagueGame.kt
index 80c86314..440cfa37 100644
--- a/TNTLeague/src/de/steamwar/tntleague/game/TNTLeagueGame.kt
+++ b/TNTLeague/src/de/steamwar/tntleague/game/TNTLeagueGame.kt
@@ -24,8 +24,6 @@ import de.steamwar.message.SubMessage
import de.steamwar.network.NetworkSender
import de.steamwar.network.packets.common.FightInfoPacket
import de.steamwar.scoreboard.SWScoreboard
-import de.steamwar.sql.Fight
-import de.steamwar.sql.FightPlayer
import de.steamwar.sql.SteamwarUser
import de.steamwar.tntleague.colorByTeam
import de.steamwar.tntleague.config.TNTLeagueConfig
@@ -37,10 +35,9 @@ import de.steamwar.tntleague.events.LobbyListener
import de.steamwar.tntleague.inventory.DealerInventory
import de.steamwar.tntleague.message
import de.steamwar.tntleague.plugin
-import de.steamwar.tntleague.util.*
+import de.steamwar.tntleague.util.TNTLeagueScoreboard
import org.bukkit.GameMode
import org.bukkit.Location
-import org.bukkit.Material
import org.bukkit.Sound
import org.bukkit.entity.Item
import org.bukkit.entity.Player
@@ -51,6 +48,7 @@ import org.bukkit.inventory.ItemStack
import org.bukkit.scheduler.BukkitTask
import java.sql.Timestamp
import java.time.Instant
+import kotlin.random.Random
object TNTLeagueGame {
var state: GameState = GameState.LOBBY
@@ -87,18 +85,24 @@ object TNTLeagueGame {
message.broadcast("GAME_STARTED")
- val tnt = ItemStack(Material.TNT)
-
start = Timestamp.from(Instant.now())
+ var spawnCount = 0
spawnerTask = plugin.server.scheduler.runTaskTimer(plugin, bukkit {
+ val coinsToSpawn = if (spawnCount % 28 == 0) {
+ DealerInventory.huge_coins
+ } else if (spawnCount % 7 == 0) {
+ DealerInventory.big_coins
+ } else {
+ DealerInventory.coins
+ }
+ spawnCount++
+
if (world.getNearbyEntitiesByType(Item::class.java, TNTLeagueWorldConfig.blueTeam.itemSpawn, 3.0).sumOf { it.itemStack.amount } <= 256) {
- spawnItems(TNTLeagueWorldConfig.blueTeam.itemSpawn, tnt)
- spawnItems(TNTLeagueWorldConfig.blueTeam.itemSpawn, DealerInventory.coins)
+ spawnItems(TNTLeagueWorldConfig.blueTeam.itemSpawn, coinsToSpawn)
}
if (world.getNearbyEntitiesByType(Item::class.java, TNTLeagueWorldConfig.redTeam.itemSpawn, 3.0).sumOf { it.itemStack.amount } <= 256) {
- spawnItems(TNTLeagueWorldConfig.redTeam.itemSpawn, tnt)
- spawnItems(TNTLeagueWorldConfig.redTeam.itemSpawn, DealerInventory.coins)
+ spawnItems(TNTLeagueWorldConfig.redTeam.itemSpawn, coinsToSpawn)
}
}, 5, 10)
diff --git a/TNTLeague/src/de/steamwar/tntleague/inventory/DealerInventory.kt b/TNTLeague/src/de/steamwar/tntleague/inventory/DealerInventory.kt
index 418c15fb..c9bbe635 100644
--- a/TNTLeague/src/de/steamwar/tntleague/inventory/DealerInventory.kt
+++ b/TNTLeague/src/de/steamwar/tntleague/inventory/DealerInventory.kt
@@ -59,13 +59,31 @@ class DealerInventory(player: Player): KotlinInventory(player) {
companion object {
private val priceKey = NamespacedKey(plugin, "price")
private val amountKey = NamespacedKey(plugin, "amount")
- private val coinKey = NamespacedKey(plugin, "coin")
+ val coinKey = NamespacedKey(plugin, "coin")
val coins = ItemStack(Material.RAW_GOLD).apply {
itemMeta = itemMeta.apply {
displayName(Component.text("Coins").color(NamedTextColor.GOLD))
persistentDataContainer.apply {
- set(coinKey, PersistentDataType.BOOLEAN, true)
+ set(coinKey, PersistentDataType.INTEGER, 1)
+ }
+ }
+ }
+
+ val big_coins = ItemStack(Material.GOLD_INGOT).apply {
+ itemMeta = itemMeta.apply {
+ displayName(Component.text("Big Coins").color(NamedTextColor.GOLD))
+ persistentDataContainer.apply {
+ set(coinKey, PersistentDataType.INTEGER, 3)
+ }
+ }
+ }
+
+ val huge_coins = ItemStack(Material.GOLD_BLOCK).apply {
+ itemMeta = itemMeta.apply {
+ displayName(Component.text("Huge Coins").color(NamedTextColor.GOLD))
+ persistentDataContainer.apply {
+ set(coinKey, PersistentDataType.INTEGER, 9)
}
}
}
diff --git a/TowerRun/src/TowerRun.properties b/TowerRun/src/TowerRun.properties
index 88c2ecd9..0935bd83 100644
--- a/TowerRun/src/TowerRun.properties
+++ b/TowerRun/src/TowerRun.properties
@@ -17,20 +17,23 @@
# along with this program. If not, see .
#
-PREFIX=eTowerRun8r
+PREFIX=§eTowerRun§8»§r
-PLAYER_DIED=c{0} 7died8!
-PLAYER_ESCAPE=a{0} 7escaped8!
-GAME_START=aThe game has started8!
-GAME_WIN=a{0} 7has won the game8!
-GAME_STARTING=7Starting: e{0}s8!
-GAME_WAITING=7Waiting for players8...
-SERVER_STOPPING=cThe server stops in e{0}s8!
-SERVER_RESET=cThe server will be reset in e{0}s8!
-KEY_NAME=eKey
-KEY_FOUND=a{0} 7found a key8!
-GAME_TIE=aThe game ended in a tie8!
-GAME_TIME=a{0}:{1}
-CATCH_UP_WARNING=4!! cYou should catch up 4!!
+PLAYER_DIED=§c{0} §7died§8!
+PLAYER_ESCAPE=§a{0} §7escaped§8!
+GAME_START=§aThe game has started§8!
+GAME_WIN=§a{0} §7has won the game§8!
+GAME_STARTING=§7Starting: §e{0}s§8!
+GAME_WAITING=§7Waiting for players§8...
+SERVER_STOPPING=§cThe server stops in §e{0}s§8!
+SERVER_RESET=§cThe server will be reset in §e{0}s§8!
+KEY_NAME=§eKey
+KEY_FOUND=§a{0} §7found a key§8!
+GAME_TIE=§aThe game ended in a tie§8!
+GAME_TIME=§a{0}:{1}
+CATCH_UP_WARNING=§4!! §cYou should catch up §4!!
-COMMAND_START=aThe game will start soon8!
\ No newline at end of file
+COMMAND_START=§aThe game will start soon§8!
+
+PARTICIPANT_CHAT={0} {1}§8» §7{2}
+SPECTATOR_CHAT=§7{0}§8» §7{1}
\ No newline at end of file
diff --git a/TowerRun/src/TowerRun_de.properties b/TowerRun/src/TowerRun_de.properties
index 2c88c3b6..82fd014b 100644
--- a/TowerRun/src/TowerRun_de.properties
+++ b/TowerRun/src/TowerRun_de.properties
@@ -17,19 +17,19 @@
# along with this program. If not, see .
#
-PLAYER_DIED=c{0} 7ist gestorben8!
-PLAYER_ESCAPE=a{0} 7ist entkommen8!
-GAME_START=aDas Spiel beginnt8!
-GAME_WIN=a{0} 7hat das Spiel gewonnen8!
-GAME_STARTING=7Das Spiel startet in e{0}s8!
-GAME_WAITING=7Warte auf weitere Spieler8...
-SERVER_STOPPING=cDer Server stoppt in e{0}s8!
-SERVER_RESET=cDer Server wird in e{0}s czurckgesetzt8!
-GAME_TIE=7Keiner hat gewonnen8!
+PLAYER_DIED=§c{0} §7ist gestorben§8!
+PLAYER_ESCAPE=§a{0} §7ist entkommen§8!
+GAME_START=§aDas Spiel beginnt§8!
+GAME_WIN=§a{0} §7hat das Spiel gewonnen§8!
+GAME_STARTING=§7Das Spiel startet in §e{0}s§8!
+GAME_WAITING=§7Warte auf weitere Spieler§8...
+SERVER_STOPPING=§cDer Server stoppt in §e{0}s§8!
+SERVER_RESET=§cDer Server wird in §e{0}s §czur§ckgesetzt§8!
+GAME_TIE=§7Keiner hat gewonnen§8!
-KEY_NAME=eSchlssel
-KEY_FOUND=a{0} 7hat einen Schlssel gefunden8!
+KEY_NAME=§eSchl§ssel
+KEY_FOUND=§a{0} §7hat einen Schl§ssel gefunden§8!
-CATCH_UP_WARNING=4!! cDu solltest aufholen 4!!
+CATCH_UP_WARNING=§4!! §cDu solltest aufholen §4!!
-COMMAND_START=7Das Spiel startet bald8!
\ No newline at end of file
+COMMAND_START=§7Das Spiel startet bald§8!
\ No newline at end of file
diff --git a/TowerRun/src/de/steamwar/towerrun/TowerRun.java b/TowerRun/src/de/steamwar/towerrun/TowerRun.java
index 7e6df112..4503c5da 100644
--- a/TowerRun/src/de/steamwar/towerrun/TowerRun.java
+++ b/TowerRun/src/de/steamwar/towerrun/TowerRun.java
@@ -80,7 +80,5 @@ public class TowerRun extends JavaPlugin {
gameCountdown = new GameCountdown();
Bukkit.getScheduler().runTaskTimer(this, new FightInfoPacketSender(), 20, 20);
-
- TowerRunGame.reset();
}
}
diff --git a/TowerRun/src/de/steamwar/towerrun/config/WorldConfig.java b/TowerRun/src/de/steamwar/towerrun/config/WorldConfig.java
index fafdd453..56e90034 100644
--- a/TowerRun/src/de/steamwar/towerrun/config/WorldConfig.java
+++ b/TowerRun/src/de/steamwar/towerrun/config/WorldConfig.java
@@ -35,7 +35,8 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.util.Vector;
import java.io.File;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
@UtilityClass
public class WorldConfig {
@@ -54,7 +55,7 @@ public class WorldConfig {
public static final int MAP_MIN_Z;
public static final int MAP_MAX_X;
public static final int MAP_MAX_Z;
- public static final Map MELTING_TIMES;
+ public static final boolean MELTING;
public static final TowerGeneratorConfig TOWER_GENERATOR_CONFIG;
public static final List WINCONDITIONS = new ArrayList<>();
@@ -161,16 +162,7 @@ public class WorldConfig {
MAP_MAX_X = config.getInt("maxX");
MAP_MAX_Z = config.getInt("maxZ");
- ConfigurationSection meltingBlocksSection = tower.getConfigurationSection("meltingBlocks");
- if (meltingBlocksSection != null) {
- Map meltingTimes = new HashMap<>();
- meltingBlocksSection.getKeys(false).forEach(s -> {
- meltingTimes.put(Material.valueOf(s), meltingBlocksSection.getInt(s));
- });
- MELTING_TIMES = Collections.unmodifiableMap(meltingTimes);
- } else {
- MELTING_TIMES = Collections.emptyMap();
- }
+ MELTING = tower.getBoolean("melting") || tower.contains("meltingBlocks"); // Backwards compatibility with meltingBlocks key!
ACTIVE_WINCONDITIONS = config.getStringList("winconditions");
WINCONDITIONS.stream().filter(winCondition -> ACTIVE_WINCONDITIONS.contains(winCondition.getName())).forEach(winCondition -> winCondition.setActive(true));
diff --git a/TowerRun/src/de/steamwar/towerrun/countdowns/EndCountdown.java b/TowerRun/src/de/steamwar/towerrun/countdowns/EndCountdown.java
index dbe0d40d..6d631e02 100644
--- a/TowerRun/src/de/steamwar/towerrun/countdowns/EndCountdown.java
+++ b/TowerRun/src/de/steamwar/towerrun/countdowns/EndCountdown.java
@@ -20,6 +20,7 @@
package de.steamwar.towerrun.countdowns;
import de.steamwar.towerrun.TowerRun;
+import de.steamwar.towerrun.config.Config;
import de.steamwar.towerrun.game.TowerRunGame;
import de.steamwar.towerrun.state.GameStates;
import org.bukkit.Bukkit;
@@ -41,14 +42,18 @@ public class EndCountdown extends Countdown {
@Override
int defaultTime() {
- return 10;
+ return 30;
}
@Override
void timerEnd() {
Bukkit.getOnlinePlayers().forEach(player -> player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1, 1));
if (RESETS) {
- TowerRunGame.reset();
+ if (Config.event()) {
+ Bukkit.shutdown();
+ } else {
+ TowerRunGame.reset();
+ }
lobbyCountdown.setTime(lobbyCountdown.defaultTime());
} else {
Bukkit.shutdown();
diff --git a/TowerRun/src/de/steamwar/towerrun/game/TowerRunGame.java b/TowerRun/src/de/steamwar/towerrun/game/TowerRunGame.java
index 2c014cb5..c1514db4 100644
--- a/TowerRun/src/de/steamwar/towerrun/game/TowerRunGame.java
+++ b/TowerRun/src/de/steamwar/towerrun/game/TowerRunGame.java
@@ -46,6 +46,10 @@ public class TowerRunGame {
public static final List PLAYERS_ESCAPED = new ArrayList<>();
private static final World world = Bukkit.getWorlds().get(0);
+ public static boolean isEscaped(TowerRunPlayer player) {
+ return PLAYERS_ESCAPED.contains(player);
+ }
+
public static boolean isAlive(TowerRunPlayer player) {
return PLAYERS_ALIVE.contains(player);
}
@@ -143,6 +147,7 @@ public class TowerRunGame {
player.setGameMode(GameMode.SURVIVAL);
}
player.teleport(WorldConfig.SPAWN);
+ PLAYERS_ALIVE.add(TowerRunPlayer.get(player));
});
}
diff --git a/TowerRun/src/de/steamwar/towerrun/generator/TowerGenerator.java b/TowerRun/src/de/steamwar/towerrun/generator/TowerGenerator.java
index 4f379547..63cd94ee 100644
--- a/TowerRun/src/de/steamwar/towerrun/generator/TowerGenerator.java
+++ b/TowerRun/src/de/steamwar/towerrun/generator/TowerGenerator.java
@@ -140,8 +140,10 @@ public class TowerGenerator {
noKeyFloors--;
if (!chestBlocks.isEmpty() && noKeyFloors < 0 && random.nextDouble() < config.keyChance) {
noKeyFloors = random.nextInt(config.maxNoKeyFloors - config.minNoKeyFloors) + config.minNoKeyFloors;
- Container container = chestBlocks.get(random.nextInt(chestBlocks.size()));
- keys.add(container.getLocation());
+ for (int i = 0; i < 2; i++) {
+ Container container = chestBlocks.get(random.nextInt(chestBlocks.size()));
+ keys.add(container.getLocation());
+ }
for (WorldConfig.TowerGeneratorDoorBlock doorBlock : config.doorBlocks) {
int x = doorBlock.getX();
diff --git a/TowerRun/src/de/steamwar/towerrun/listener/GlobalListener.java b/TowerRun/src/de/steamwar/towerrun/listener/GlobalListener.java
index 5c2956b2..c20dd391 100644
--- a/TowerRun/src/de/steamwar/towerrun/listener/GlobalListener.java
+++ b/TowerRun/src/de/steamwar/towerrun/listener/GlobalListener.java
@@ -19,20 +19,20 @@
package de.steamwar.towerrun.listener;
+import de.steamwar.towerrun.TowerRun;
import de.steamwar.towerrun.config.WorldConfig;
import de.steamwar.towerrun.game.TowerRunGame;
import de.steamwar.towerrun.game.TowerRunPlayer;
+import de.steamwar.towerrun.state.GameState;
import de.steamwar.towerrun.state.GameStateBukkitListener;
import de.steamwar.towerrun.state.GameStates;
+import lombok.val;
import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
import org.bukkit.Location;
-import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerJoinEvent;
-import org.bukkit.event.player.PlayerMoveEvent;
-import org.bukkit.event.player.PlayerQuitEvent;
-import org.bukkit.event.player.PlayerRespawnEvent;
+import org.bukkit.event.player.*;
import java.util.EnumSet;
@@ -67,4 +67,25 @@ public class GlobalListener extends GameStateBukkitListener implements Listener
public void onPlayerRespawn(PlayerRespawnEvent event) {
event.setRespawnLocation(WorldConfig.SPAWN);
}
+
+ @EventHandler
+ public void onAsyncPlayerChat(AsyncPlayerChatEvent event) {
+ TowerRunPlayer player = TowerRunPlayer.get(event.getPlayer());
+ if (GameState.getCurrentState() == GameStates.RUNNING && (TowerRunGame.isAlive(player) || TowerRunGame.isEscaped(player))) {
+ String prefix;
+ if (TowerRunGame.isAlive(player)) {
+ if (event.getPlayer().getGameMode() == GameMode.SPECTATOR) {
+ prefix = "§c☠";
+ } else {
+ prefix = "§6❤";
+ }
+ } else {
+ prefix = "§a✔";
+ }
+ TowerRun.getMessage().broadcastPrefixless("PARTICIPANT_CHAT", prefix, event.getPlayer().getName(), event.getMessage());
+ } else {
+ TowerRun.getMessage().broadcastPrefixless("SPECTATOR_CHAT", event.getPlayer().getName(), event.getMessage());
+ }
+ event.setCancelled(true);
+ }
}
diff --git a/TowerRun/src/de/steamwar/towerrun/listener/IngameListener.java b/TowerRun/src/de/steamwar/towerrun/listener/IngameListener.java
index befc7d47..bc74e57f 100644
--- a/TowerRun/src/de/steamwar/towerrun/listener/IngameListener.java
+++ b/TowerRun/src/de/steamwar/towerrun/listener/IngameListener.java
@@ -26,6 +26,8 @@ import de.steamwar.towerrun.config.WorldConfig;
import de.steamwar.towerrun.game.TowerRunGame;
import de.steamwar.towerrun.state.GameStateBukkitListener;
import de.steamwar.towerrun.state.GameStates;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.EntityType;
@@ -42,16 +44,24 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
-import java.util.function.Function;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
public class IngameListener extends GameStateBukkitListener {
private int time = 0;
- private final Map> blocksToMelt = new HashMap<>();
+ private final Map blocksToMelt = new HashMap<>();
private BukkitRunnable blocksToMeltRunnable;
private BukkitRunnable antiCampRunnable;
+ @AllArgsConstructor
+ @EqualsAndHashCode
+ private class Pos {
+ private final int x;
+ private final int y;
+ private final int z;
+ }
+
public IngameListener() {
super(EnumSet.of(GameStates.RUNNING));
}
@@ -62,16 +72,21 @@ public class IngameListener extends GameStateBukkitListener {
blocksToMeltRunnable = new BukkitRunnable() {
@Override
public void run() {
- List blocks = blocksToMelt.get(time);
+ List blocksToBreak = blocksToMelt.entrySet().stream()
+ .filter(entry -> entry.getValue() <= time)
+ .map(Map.Entry::getKey)
+ .collect(Collectors.toList());
time++;
- if (blocks == null) {
+ if (blocksToBreak.isEmpty()) {
return;
}
- blocks.forEach(block -> {
- if (!WorldConfig.MELTING_TIMES.containsKey(block.getType())) return;
+ for (Pos pos : blocksToBreak) {
+ blocksToMelt.remove(pos);
+ Block block = Bukkit.getWorlds().get(0).getBlockAt(pos.x, pos.y, pos.z);
+ if (block.getType() == Material.AIR || block.getType() == Material.LAVA) continue;
block.setType(Material.AIR);
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 0.1F, 1);
- });
+ }
}
};
blocksToMeltRunnable.runTaskTimer(TowerRun.getInstance(), 0, 1);
@@ -80,16 +95,16 @@ public class IngameListener extends GameStateBukkitListener {
@Override
public void run() {
double minY = TowerRunGame.PLAYERS_ALIVE.stream()
- .map(p -> p.player().getLocation().getY())
- .min(Comparator.comparing(Function.identity()))
+ .mapToDouble(p -> p.player().getLocation().getY())
+ .average()
.orElse(0.0);
List toDamage = new ArrayList<>();
TowerRunGame.PLAYERS_ALIVE.forEach(towerRunPlayer -> {
- if (towerRunPlayer.player().getLocation().getY() - minY > 20) {
- towerRunPlayer.player().sendTitle("§a", TowerRun.getMessage().parse("CATCH_UP_WARNING", towerRunPlayer.player()), 5, 30, 5);
- }
if (towerRunPlayer.player().getLocation().getY() - minY > 30) {
+ towerRunPlayer.player().sendTitle("", TowerRun.getMessage().parse("CATCH_UP_WARNING", towerRunPlayer.player()), 5, 30, 5);
+ }
+ if (towerRunPlayer.player().getLocation().getY() - minY > 50) {
toDamage.add(towerRunPlayer.player());
}
});
@@ -115,12 +130,12 @@ public class IngameListener extends GameStateBukkitListener {
public void onPlayerDeath(PlayerDeathEvent event) {
event.setDeathMessage(null);
Bukkit.getScheduler().runTaskLater(TowerRun.getInstance(), () -> {
- if (TowerRun.getTowerGenerator() != null) {
- event.getEntity().teleport(TowerRun.getTowerGenerator().getSpawn());
- } else {
- event.getEntity().teleport(WorldConfig.SPAWN);
- }
- }, 5
+ if (TowerRun.getTowerGenerator() != null) {
+ event.getEntity().teleport(TowerRun.getTowerGenerator().getSpawn());
+ } else {
+ event.getEntity().teleport(WorldConfig.SPAWN);
+ }
+ }, 5
);
event.getEntity().setGameMode(GameMode.SPECTATOR);
Bukkit.getOnlinePlayers().forEach(player -> {
@@ -181,14 +196,19 @@ public class IngameListener extends GameStateBukkitListener {
}
event.getPlayer().getInventory().addItem(new SWItem(Material.LEVER, TowerRun.getMessage().parse("KEY_NAME", event.getPlayer())).getItemStack());
-
event.getClickedBlock().setType(Material.ENDER_CHEST);
- event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.BLOCK_ENDER_CHEST_OPEN, 1, 1);
- TowerRun.getMessage().broadcast("KEY_FOUND", event.getPlayer().getName());
+
+ Bukkit.getOnlinePlayers().forEach(player -> {
+ player.playSound(event.getPlayer().getLocation(), Sound.BLOCK_ENDER_CHEST_OPEN, 1, 1);
+ player.sendTitle("", TowerRun.getMessage().parse("KEY_FOUND", player, event.getPlayer().getName()), 10, 70, 20);
+ });
}
@EventHandler
public void onBlockPhysics(BlockPhysicsEvent event) {
+ if (!WorldConfig.MELTING) {
+ return;
+ }
if (event.getSourceBlock().getType() != Material.LAVA) {
return;
}
@@ -202,11 +222,52 @@ public class IngameListener extends GameStateBukkitListener {
}
private void shouldMelt(Block block) {
- int meltingTime = WorldConfig.MELTING_TIMES.getOrDefault(block.getType(), -1);
- if (meltingTime == -1) {
- return;
+ if (block.getType().isBurnable()) return;
+ if (block.getType().isAir()) return;
+ if (block.isLiquid()) return;
+ int meltingTime = (int) (block.getType().getHardness() * 48 * 20);
+ switch (block.getType()) {
+ case TINTED_GLASS:
+ meltingTime = meltingTime * 2;
+ break;
+ case WHITE_STAINED_GLASS:
+ case ORANGE_STAINED_GLASS:
+ case MAGENTA_STAINED_GLASS:
+ case LIGHT_BLUE_STAINED_GLASS:
+ case YELLOW_STAINED_GLASS:
+ case LIME_STAINED_GLASS:
+ case PINK_STAINED_GLASS:
+ case GRAY_STAINED_GLASS:
+ case LIGHT_GRAY_STAINED_GLASS:
+ case CYAN_STAINED_GLASS:
+ case PURPLE_STAINED_GLASS:
+ case BLUE_STAINED_GLASS:
+ case BROWN_STAINED_GLASS:
+ case GREEN_STAINED_GLASS:
+ case RED_STAINED_GLASS:
+ case BLACK_STAINED_GLASS:
+ case WHITE_STAINED_GLASS_PANE:
+ case ORANGE_STAINED_GLASS_PANE:
+ case MAGENTA_STAINED_GLASS_PANE:
+ case LIGHT_BLUE_STAINED_GLASS_PANE:
+ case YELLOW_STAINED_GLASS_PANE:
+ case LIME_STAINED_GLASS_PANE:
+ case PINK_STAINED_GLASS_PANE:
+ case GRAY_STAINED_GLASS_PANE:
+ case LIGHT_GRAY_STAINED_GLASS_PANE:
+ case CYAN_STAINED_GLASS_PANE:
+ case PURPLE_STAINED_GLASS_PANE:
+ case BLUE_STAINED_GLASS_PANE:
+ case BROWN_STAINED_GLASS_PANE:
+ case GREEN_STAINED_GLASS_PANE:
+ case RED_STAINED_GLASS_PANE:
+ case BLACK_STAINED_GLASS_PANE:
+ meltingTime = meltingTime * 10;
+ default:
+ break;
}
- blocksToMelt.computeIfAbsent(time + meltingTime * 20, integer -> new ArrayList<>()).add(block);
+ Pos pos = new Pos(block.getLocation().getBlockX(), block.getLocation().getBlockY(), block.getLocation().getBlockZ());
+ blocksToMelt.putIfAbsent(pos, time + meltingTime + 1);
}
@EventHandler
diff --git a/TowerRun/src/de/steamwar/towerrun/listener/LobbyListener.java b/TowerRun/src/de/steamwar/towerrun/listener/LobbyListener.java
index c93bc4bb..0a4e4358 100644
--- a/TowerRun/src/de/steamwar/towerrun/listener/LobbyListener.java
+++ b/TowerRun/src/de/steamwar/towerrun/listener/LobbyListener.java
@@ -68,6 +68,8 @@ public class LobbyListener extends GameStateBukkitListener {
if (TowerRunGame.PLAYERS_ALIVE.stream().map(towerRunPlayer -> SteamwarUser.get(towerRunPlayer.player().getUniqueId()).getTeam()).filter(integer -> integer == team).count() < Config.EVENT_MAXIMUM_TEAM_MEMBERS) {
TowerRunGame.PLAYERS_ALIVE.add(TowerRunPlayer.get(player));
+ } else {
+ player.setGameMode(GameMode.SPECTATOR);
}
} else {
TowerRunGame.PLAYERS_ALIVE.add(TowerRunPlayer.get(player));
diff --git a/VelocityCore/build.gradle.kts b/VelocityCore/build.gradle.kts
index 844e9f21..f81416a3 100644
--- a/VelocityCore/build.gradle.kts
+++ b/VelocityCore/build.gradle.kts
@@ -66,4 +66,12 @@ dependencies {
implementation(libs.apolloprotos)
implementation(libs.nbt)
-}
\ No newline at end of file
+}
+
+tasks.register("DevVelocity") {
+ group = "run"
+ description = "Run a Dev Velocity"
+ dependsOn(":VelocityCore:shadowJar")
+ dependsOn(":VelocityCore:Persistent:jar")
+ template = "DevVelocity"
+}
diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties
index 863d1099..c46cd317 100644
--- a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties
+++ b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties
@@ -154,7 +154,7 @@ UNPUNISHMENT_USAGE=§8/§7{0} §8[§eplayer§8]
PUNISHMENT_UNTIL=until {0}
PUNISHMENT_PERMA=permanent
-BAN_TEAM={0} §e{1} §7was §e§lbanned§7 by §e{2} {3}§8: §f{4}
+BAN_TEAM=§e{0} §7was §e§lbanned§7 by §e{1} {2}§8: §f{3}
BAN_PERMA=§7You are §e§lbanned §epermanently§8: §e{0}
BAN_UNTIL=§7You are §e§lbanned §euntil {0}§8: §e{1}
UNBAN_ERROR=§cThe player isn't banned.
@@ -164,49 +164,49 @@ BAN_AVOIDING_ALERT=§cPotential ban bypass by §r{0}§c: {1}
BAN_AVOIDING_LIST=§c{0} §e{1}
BAN_AVOIDING_BAN_HOVER=§cBan player because of bann bypass.
-MUTE_TEAM={0} §e{1} §7was §e§lmuted§7 by §e{2} {3}§8: §f{4}
+MUTE_TEAM=§e{0} §7was §e§lmuted§7 by §e{1} {2}§8: §f{3}
MUTE_PERMA=§7You are §epermanently §e§lmuted§8: §e{0}
MUTE_UNTIL=§7You are §e§lmuted §euntil {0}§8: §e{1}
UNMUTE_ERROR=§cThe player isn't muted.
UNMUTE=§7You have §e§lunmuted §e{0}.
-NOSCHEMRECEIVING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lrecieving schematics§8: §f{4}
+NOSCHEMRECEIVING_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lrecieving schematics§8: §f{3}
NOSCHEMRECEIVING_PERMA=§7You are §epermanently§7 excluded from receiving §e§lschematics§8: §e{0}
NOSCHEMRECEIVING_UNTIL=§7You are excluded from receiving §e§lschematics §euntil {0}§8: §e{1}
UNNOSCHEMRECEIVING_ERROR=§cThe player is not excluded from receiving schematics.
UNNOSCHEMRECEIVING=§e{0} §7may now receive §e§lschematics§7 again§8.
-NOSCHEMSHARING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsharing schematics§8: §f{4}
+NOSCHEMSHARING_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lsharing schematics§8: §f{3}
NOSCHEMSHARING_PERMA=§7You are §epermanently§7 excluded from sharing §e§lschematics§8: §e{0}
NOSCHEMSHARING_UNTIL=§7You are excluded from sharing §e§lschematics §euntil {0}§8: §e{1}
UNNOSCHEMSHARING_ERROR=§cThe player is not excluded from sharing schematics.
UNNOSCHEMSHARING=§e{0} §7may now share §e§lschematics§7 again§8.
-NOSCHEMSUBMITTING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsubmitting schematics§8: §f{4}
+NOSCHEMSUBMITTING_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lsubmitting schematics§8: §f{3}
NOSCHEMSUBMITTING_PERMA=§7You are §epermanently§7 excluded from submitting §e§lschematics§8: §e{0}
NOSCHEMSUBMITTING_UNTIL=§7You are excluded from submitting §e§lschematics §euntil {0}§8: §e{1}
UNNOSCHEMSUBMITTING_ERROR=§cThe player is not excluded from submitting schematics.
UNNOSCHEMSUBMITTING=§e{0} §7may now submit §e§lschematics§7 again§8.
-NODEVSERVER_TEAM={0} §e{1} §7has annoyed §e{2} §7with reason §f{4}§7 and therefore has received §e§ldev server prohibition§7§8, §f{3}
+NODEVSERVER_TEAM=§e{0} §7has annoyed §e{1} §7with reason §f{3}§7 and therefore has received §e§ldev server prohibition§7§8, §f{2}
NODEVSERVER_PERMA=§7You are §epermanently§7 excluded from §e§ldev servers§8: §e{0}
NODEVSERVER_UNTIL=§7You are excluded from §e§ldev servers§7 §euntil {0}§8: §e{1}
UNNODEVSERVER_ERROR=§cThe player is not excluded from dev servers.
UNNODEVSERVER=§e{0} §7may now join §e§ldev servers§7 again§8.
-NOFIGHTSERVER_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lfighting§8: §f{4}
+NOFIGHTSERVER_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lfighting§8: §f{3}
NOFIGHTSERVER_PERMA=§7You are §epermanently§7 excluded from §e§lfighting§8: §e{0}
NOFIGHTSERVER_UNTIL=§7You are excluded from §e§lfighting§7 §euntil {0}§8: §e{1}
UNNOFIGHTSERVER_ERROR=§cThe player is not excluded from fighting.
UNNOFIGHTSERVER=§e{0} §7may now join §e§lfights§7 again§8.
-NOTEAMSERVER_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lteam servers§8: §f{4}
+NOTEAMSERVER_TEAM=§e{0} §7was excluded from §e{1} {2} §7from §e§lteam servers§8: §f{3}
NOTEAMSERVER_PERMA=§7You are §epermanently§7 excluded from §e§lteam servers§8: §e{0}
NOTEAMSERVER_UNTIL=§7You are excluded from §e§lteam servers§7 §euntil {0}§8: §e{1}
UNNOTEAMSERVER_ERROR=§cThe player is not excluded from team servers.
UNNOTEAMSERVER=§e{0} §7may now set §e§lteam servers§7 again§8.
-NOTE_TEAM={0} §e{1} §7received a §e§lnote§7 from §e{2} {3}: §f{4}
+NOTE_TEAM=§e{0} §7received a §e§lnote§7 from §e{1} {2}: §f{3}
#BugCommand
BUG_MESSAGE=§7Please describe the issue in a Discord ticket with the bug ID §e{0} §7further§8.
@@ -572,6 +572,7 @@ CHAT_NO_RECEIVER=§cNobody receives your message
CHAT_EMPTY=§cDon\'t write meaningless empty messages.
CHAT_SERVERTEAM=§8STC §e{0}§8» §f{2}
+CHAT_DISCORD_SERVERTEAM=§8STC §e{0}§8» §f{2}
CHAT_GLOBAL={3}{4}{5}{6}{0}§8» {7}{2}
CHAT_DISCORD_GLOBAL=§8Dc {5}{6}{0}§8» {7}{2}
CHAT_TEAM=§8TC §e{0}§8» §f{2}
diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties
index b758353c..51a47cc3 100644
--- a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties
+++ b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties
@@ -138,7 +138,7 @@ UNPUNISHMENT_USAGE=§8/§7{0} §8[§eSpieler§8]
PUNISHMENT_UNTIL=bis zum {0}
PUNISHMENT_PERMA=permanent
-BAN_TEAM={0} §e{1} §7wurde von §e{2} {3} §e§lgebannt§8. §7Grund§8: §f{4}
+BAN_TEAM=§e{1} §7wurde von §e{2} {3} §e§lgebannt§8. §7Grund§8: §f{4}
BAN_PERMA=§7Du bist §epermanent §e§lgebannt§8. §7Grund§8: §e{0}
BAN_UNTIL=§7Du bist §ebis zum {0} §e§lgebannt§8. §7Grund§8: §e{1}
UNBAN_ERROR=§cDer Spieler ist nicht gebannt.
@@ -148,49 +148,49 @@ BAN_AVOIDING_ALERT=§cMögliche Bannumgehung durch §r{0}§c: {1}
BAN_AVOIDING_LIST=§c{0} §e{1}
BAN_AVOIDING_BAN_HOVER=§cBanne Spieler wegen Bannumgehung
-MUTE_TEAM={0} §e{1} §7wurde von §e{2} {3} §e§lgemuted§8. §7Grund§8: §f{4}
+MUTE_TEAM=§e{0} §7wurde von §e{1} {2} §e§lgemuted§8. §7Grund§8: §f{3}
MUTE_PERMA=§7Du bist §epermanent §e§lgemuted§8. §7Grund§8: §e{0}
MUTE_UNTIL=§7Du bist §ebis zum {0} §e§lgemuted§8. §7Grund§8: §e{1}
UNMUTE_ERROR=§cDer Spieler ist nicht gemuted.
UNMUTE=§7Du hast §e{0} §e§lentmuted.
-NOSCHEMRECEIVING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicerhalten§7 ausgeschlossen§8: §f{4}
+NOSCHEMRECEIVING_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lSchematicerhalten§7 ausgeschlossen§8: §f{3}
NOSCHEMRECEIVING_PERMA=§7Du bist §epermanent §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{0}
NOSCHEMRECEIVING_UNTIL=§7Du bist §ebis zum {0} §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{1}
UNNOSCHEMRECEIVING_ERROR=§cDer Spieler ist nicht vom Erhalten von Schematics ausgeschlossen.
UNNOSCHEMRECEIVING=§e{0} §7darf nun wieder §e§lSchematics§7 erhalten§8.
-NOSCHEMSHARING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicverteilen§7 ausgeschlossen§8: §f{4}
+NOSCHEMSHARING_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lSchematicverteilen§7 ausgeschlossen§8: §f{3}
NOSCHEMSHARING_PERMA=§7Du bist §epermanent §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{0}
NOSCHEMSHARING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{1}
UNNOSCHEMSHARING_ERROR=§cDer Spieler ist nicht vom Verteilen von Schematics ausgeschlossen.
UNNOSCHEMSHARING=§e{0} §7darf nun wieder §e§lSchematics§7 verteilen§8.
-NOSCHEMSUBMITTING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematiceinsenden§7 ausgeschlossen§8: §f{4}
+NOSCHEMSUBMITTING_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lSchematiceinsenden§7 ausgeschlossen§8: §f{3}
NOSCHEMSUBMITTING_PERMA=§7Du bist §epermanent §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{0}
NOSCHEMSUBMITTING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{1}
UNNOSCHEMSUBMITTING_ERROR=§cDer Spieler ist nicht vom Einsenden von Schematics ausgeschlossen.
UNNOSCHEMSUBMITTING=§e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8.
-NODEVSERVER_TEAM={0} §e{1} §7hat §e{2} §7mit Grund §f{4}§7 zu genervt und hat daher §e§lDevserververbot§7 erhalten§8, §f{3}
+NODEVSERVER_TEAM=§e{0} §7hat §e{1} §7mit Grund §f{3}§7 zu genervt und hat daher §e§lDevserververbot§7 erhalten§8, §f{2}
NODEVSERVER_PERMA=§7Du bist §epermanent §7vom §e§lDevserver§7 ausgeschlossen§8: §e{0}
NODEVSERVER_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lDevserver§7 ausgeschlossen§8: §e{1}
UNNODEVSERVER_ERROR=§cDer Spieler ist nicht vom Devserver ausgeschlossen.
UNNODEVSERVER=§e{0} §7darf nun wieder dem §e§lDevserver§7 beitreten§8.
-NOFIGHTSERVER_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lKämpfen§7 ausgeschlossen§8: §f{4}
+NOFIGHTSERVER_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lKämpfen§7 ausgeschlossen§8: §f{3}
NOFIGHTSERVER_PERMA=§7Du bist §epermanent §7vom §e§lKämpfen§7 ausgeschlossen§8: §e{0}
NOFIGHTSERVER_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lKämpfen§7 ausgeschlossen§8: §e{1}
UNNOFIGHTSERVER_ERROR=§cDer Spieler ist nicht vom Kämpfen ausgeschlossen.
UNNOFIGHTSERVER=§e{0} §7darf nun wieder §e§lKämpfen§7 beitreten§8.
-NOTEAMSERVER_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §f{4}
+NOTEAMSERVER_TEAM=§e{0} §7wurde von §e{1} {2} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §f{3}
NOTEAMSERVER_PERMA=§7Du bist §epermanent §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §e{0}
NOTEAMSERVER_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §e{1}
UNNOTEAMSERVER_ERROR=§cDer Spieler ist nicht vom Teamserver setzten ausgeschlossen.
UNNOTEAMSERVER=§e{0} §7darf nun wieder §e§lTeamserver§7 setzen§8.
-NOTE_TEAM={0} §e{1} §7erhielt von §e{2} {3} §7die §e§lNotiz§7§8: §f{4}
+NOTE_TEAM=§e{0} §7erhielt von §e{1} {2} §7die §e§lNotiz§7§8: §f{3}
#BugCommand
BUG_MESSAGE=§7Bitte beschreibe das Problem in einem Discordticket genauer und gebe dabei die Bug-ID §e{0} §7an§8.
@@ -536,9 +536,9 @@ CHAT_YOYONOW_3=Vielen Dank.
CHAT_YOYONOW_4=Ich wünsche dir noch weiterhin ein reibungsloses Spielerlebnis.
CHAT_CHAOSCAOT_1=Du hast mich gerufen!
CHAT_CHAOSCAOT_2=Wenn etwas nicht funktioniert, dann nen es einfach ein Feature.
-CHAT_CHAOSCAOT_3=Und wenn es ein Feature ist, dann kann es nicht kaputt.
-CHAT_CHAOSCAOT_4=Kaputt ist nur eine Definition. Wenn du es als Feature definiert, dann kann es nicht kaputt sein.
-CHAT_CHAOSCAOT_5=Und wenn du es als kaputt definiert, dann sag uns bescheid mit dem Befehl "/bug ".
+CHAT_CHAOSCAOT_3=Und wenn es ein Feature ist, dann kann es nicht kaputt sein.
+CHAT_CHAOSCAOT_4=Kaputt ist nur eine Definition. Wenn du alles als Feature definierst, dann kann es auch keine Bugs geben.
+CHAT_CHAOSCAOT_5=Solltest du es aber doch als Bug definieren, dann sag uns bescheid mit dem Befehl "/bug ".
CHAT_CHAOSCAOT_6=Vielen Dank.
CHAT_RECEIVE=§cUm Chatnachrichten versenden zu können, musst du auch welche empfangen!
CHAT_NO_LINKS=§cDu darfst keine Links versenden.
@@ -547,6 +547,7 @@ CHAT_NO_RECEIVER=§cNiemand empfängt deine Nachricht
CHAT_EMPTY=§cSchreibe keine inhaltslosen Nachrichten.
CHAT_SERVERTEAM=§8STC §e{0}§8» §f{2}
+CHAT_DISCORD_SERVERTEAM=§8STC §e{0}§8» §f{2}
CHAT_GLOBAL={3}{4}{5}{6}{0}§8» {7}{2}
CHAT_DISCORD_GLOBAL=§8Dc {5}{6}{0}§8» {7}{2}
CHAT_TEAM=§8TC §e{0}§8» §f{2}
diff --git a/VelocityCore/src/de/steamwar/velocitycore/ArenaMode.java b/VelocityCore/src/de/steamwar/velocitycore/ArenaMode.java
index 5595d9d9..4490c172 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/ArenaMode.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/ArenaMode.java
@@ -22,6 +22,7 @@ package de.steamwar.velocitycore;
import de.steamwar.sql.SchematicType;
import lombok.Getter;
+import java.time.LocalDateTime;
import java.util.*;
public class ArenaMode extends GameModeConfig {
@@ -76,7 +77,7 @@ public class ArenaMode extends GameModeConfig {
public static List getAllChatNames(boolean historic) {
List chatNames = new LinkedList<>();
for(ArenaMode mode : byInternal.values()){
- if(historic == mode.isHistoric())
+ if(mode.isActive() && historic == mode.isHistoric())
chatNames.addAll(mode.getServer().getChatNames());
}
return chatNames;
@@ -94,6 +95,9 @@ public class ArenaMode extends GameModeConfig {
@Getter
private String config;
+ @Getter
+ private List ActiveMonths = Collections.emptyList();
+
public String hasMap(String map){
for(String m : getMaps()) {
if(m.equalsIgnoreCase(map))
@@ -114,8 +118,10 @@ public class ArenaMode extends GameModeConfig {
return getServer().getChatNames().get(0);
}
- public boolean withoutChatName(){
- return getServer().getChatNames().isEmpty();
+ public boolean isActive() {
+ if (getServer().getChatNames().isEmpty()) return false;
+ if (ActiveMonths.isEmpty()) return true;
+ return ActiveMonths.contains(LocalDateTime.now().getMonth().getValue());
}
public String getSchemTypeOrInternalName() {
diff --git a/VelocityCore/src/de/steamwar/velocitycore/Node.java b/VelocityCore/src/de/steamwar/velocitycore/Node.java
index 9c717886..308d9938 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/Node.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/Node.java
@@ -35,7 +35,7 @@ public abstract class Node {
private static final List OPENJ9_ARGS = Arrays.asList(
"-XX:+EnableCRIUSupport", "-XX:-CRIURestoreNonPortableMode",
"-Xgc:excessiveGCratio=80", "-Xdisableexplicitgc", "-Xnoclassgc", "-Xmos128M", "-Xmns48M", "-XX:+ExitOnOutOfMemoryError", // initial heap half values of memory observed by 1.19 spectate server
- "-Xsyslog:none", "-Xtrace:none", "-Xverify:none", "-Xdump:system:none", "-Xdump:jit:none", "-Xdump:snap:none",
+ "-Xsyslog:none", "-Xtrace:none", "-Xverify:none", "-Xdump:system:none", "-Xdump:jit:none", "-Xdump:snap:none", "-Xdump:heap:opts=hprof",
"-XX:+EnableDynamicAgentLoading", "-Dlog4j.configurationFile=log4j2.xml"
);
private static final Set JAVA_8 = new HashSet<>();
diff --git a/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java b/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java
index a5e08b55..d8952118 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java
@@ -44,6 +44,7 @@ public enum ServerVersion {
PAPER_18("paper-1.18.2.jar", 15, ProtocolVersion.MINECRAFT_1_18_2),
PAPER_19("paper-1.19.3.jar", 19, ProtocolVersion.MINECRAFT_1_19_3),
PAPER_20("paper-1.20.1.jar", 20, ProtocolVersion.MINECRAFT_1_20),
+ DEVEL_21("paper-1.21.5.jar", 21, ProtocolVersion.MINECRAFT_1_21_5),
PAPER_21("paper-1.21.3.jar", 21, ProtocolVersion.MINECRAFT_1_21_2);
private static final Map chatMap = new HashMap<>();
@@ -94,6 +95,10 @@ public enum ServerVersion {
}
public static ServerVersion get(int version) {
+ if (version == 21) {
+ return DEVEL_21;
+ }
+
return versionMap.get(version);
}
diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/BugCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/BugCommand.java
index 22c9f391..088acb09 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/commands/BugCommand.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/commands/BugCommand.java
@@ -19,9 +19,11 @@
package de.steamwar.velocitycore.commands;
+import de.steamwar.persistent.Subserver;
import de.steamwar.sql.SWException;
import de.steamwar.command.SWCommand;
import de.steamwar.messages.Chatter;
+import de.steamwar.velocitycore.SubserverSystem;
public class BugCommand extends SWCommand {
public BugCommand() {
@@ -35,5 +37,9 @@ public class BugCommand extends SWCommand {
sender.withPlayerOrOffline(player -> player.getCurrentServer().map(connection -> connection.getServerInfo().getName()).orElse("offline"), () -> "offline") + " " + sender.user().getUserName() + " " + sender.user().getId()
);
sender.system("BUG_MESSAGE", id);
+
+ if (Subserver.isArena(Subserver.getSubserver(sender.getPlayer()))) {
+ sender.getPlayer().spoofChatInput("/techhiderbug");
+ }
}
}
diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/DevCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/DevCommand.java
index 71b4427c..bf74e672 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/commands/DevCommand.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/commands/DevCommand.java
@@ -135,12 +135,12 @@ public class DevCommand extends SWCommand {
});
devServerPorts.forEach((username, value) -> {
- if (devServers.containsKey(username))
- return;
-
SteamwarUser user = SteamwarUser.get(username);
String name = "Dev " + user.getUserName();
((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().put(name, ServerVersion.get(devServerVersions.get(username)).getProtocolVersion().getProtocol());
+
+ if (devServers.containsKey(username))
+ return;
devServers.put(user.getUserName().toLowerCase(), VelocityCore.getProxy().registerServer(new ServerInfo(name, new InetSocketAddress("127.0.0.1", value))));
});
}
diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/FightCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/FightCommand.java
index 6c320758..ee82988c 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/commands/FightCommand.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/commands/FightCommand.java
@@ -45,7 +45,7 @@ public class FightCommand extends SWCommand {
private static void getModes(Chatter sender, String precommand, boolean historic){
Component start = Component.empty();
for(ArenaMode mode : ArenaMode.getAllModes()){
- if(mode.withoutChatName() || mode.isHistoric() != historic)
+ if (!mode.isActive() || mode.isHistoric() != historic)
continue;
String command = precommand + mode.getChatName();
diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/MsgCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/MsgCommand.java
index 8341318f..5300909d 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/commands/MsgCommand.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/commands/MsgCommand.java
@@ -20,6 +20,8 @@
package de.steamwar.velocitycore.commands;
import com.velocitypowered.api.proxy.Player;
+import com.velocitypowered.proxy.Velocity;
+import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.listeners.ChatListener;
import de.steamwar.command.SWCommand;
import de.steamwar.messages.Chatter;
@@ -41,7 +43,7 @@ public class MsgCommand extends SWCommand {
}
public static void msg(PlayerChatter sender, Player target, String[] args) {
- if(target == null) {
+ if(target == null || VelocityCore.getProxy().getPlayer(target.getUniqueId()).orElse(null) == null) {
sender.system("MSG_OFFLINE");
return;
}
diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/PunishmentCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/PunishmentCommand.java
index 1dc8ebde..4932de02 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/commands/PunishmentCommand.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/commands/PunishmentCommand.java
@@ -210,7 +210,7 @@ public class PunishmentCommand {
target.punish(punishmentType, banTime, msg, punisher.getId(), isPerma);
if(punishmentType == Punishment.PunishmentType.Ban)
ban(target, banTime, msg, punisher, isPerma);
- Chatter.serverteam().system(punishmentType.getTeamMessage(), new Message("PREFIX"), target, sender, new Message((isPerma ? "PUNISHMENT_PERMA" : "PUNISHMENT_UNTIL"), banTime), msg);
+ Chatter.serverteam().system(punishmentType.getTeamMessage(), target, sender, new Message((isPerma ? "PUNISHMENT_PERMA" : "PUNISHMENT_UNTIL"), banTime), msg);
}
@Register
diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/TeamCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/TeamCommand.java
index 0dd865b1..0655ac8b 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/commands/TeamCommand.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/commands/TeamCommand.java
@@ -20,12 +20,11 @@
package de.steamwar.velocitycore.commands;
import com.velocitypowered.api.proxy.ConnectionRequestBuilder;
+import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
-import de.steamwar.persistent.Storage;
-import de.steamwar.velocitycore.VelocityCore;
-import de.steamwar.velocitycore.discord.DiscordBot;
-import de.steamwar.velocitycore.inventory.SWItem;
-import de.steamwar.velocitycore.inventory.SWListInv;
+import com.velocitypowered.api.proxy.server.ServerPing;
+import com.viaversion.viaversion.api.Via;
+import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
@@ -33,7 +32,12 @@ import de.steamwar.command.TypeValidator;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.messages.PlayerChatter;
+import de.steamwar.persistent.Storage;
import de.steamwar.sql.*;
+import de.steamwar.velocitycore.VelocityCore;
+import de.steamwar.velocitycore.discord.DiscordBot;
+import de.steamwar.velocitycore.inventory.SWItem;
+import de.steamwar.velocitycore.inventory.SWListInv;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
@@ -401,12 +405,21 @@ public class TeamCommand extends SWCommand {
return;
}
- InetSocketAddress address = new InetSocketAddress(targetTeam.getAddress(), targetTeam.getPort());
- ServerInfo serverInfo = Storage.teamServers.computeIfAbsent(targetTeam.getTeamId(), integer -> {
- ServerInfo info = new ServerInfo("Team " + targetTeam.getTeamKuerzel(), address);
- VelocityCore.getProxy().registerServer(info);
- return info;
- });
+ InetSocketAddress address;
+ ServerInfo serverInfo;
+ try {
+ address = new InetSocketAddress(targetTeam.getAddress(), targetTeam.getPort());
+ serverInfo = Storage.teamServers.computeIfAbsent(targetTeam.getTeamId(), integer -> {
+ ServerInfo info = new ServerInfo("Team " + targetTeam.getTeamKuerzel(), address);
+ RegisteredServer server = VelocityCore.getProxy().registerServer(info);
+ ServerPing serverPing = server.ping().join();
+ ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().put(info.getName(), serverPing.getVersion().getProtocol());
+ return info;
+ });
+ } catch (Exception e) {
+ sender.system("TEAM_NO_ADDRESS");
+ return;
+ }
if (!address.equals(serverInfo.getAddress())) {
VelocityCore.getProxy().unregisterServer(Storage.teamServers.remove(targetTeam.getTeamId()));
diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/TypeMappers.java b/VelocityCore/src/de/steamwar/velocitycore/commands/TypeMappers.java
index 8036272f..e2c1176a 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/commands/TypeMappers.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/commands/TypeMappers.java
@@ -49,7 +49,11 @@ public class TypeMappers {
return new TypeMapper<>() {
@Override
public ArenaMode map(Chatter sender, PreviousArguments previousArguments, String s) {
- return ArenaMode.getByChat(s);
+ ArenaMode arenaMode = ArenaMode.getByChat(s);
+ if (arenaMode == null) return null;
+ if (arenaMode.isHistoric() != historic) return null;
+ if (!arenaMode.isActive()) return null;
+ return arenaMode;
}
@Override
diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java b/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java
index ecdc5a53..28cd0c22 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/discord/DiscordBot.java
@@ -167,14 +167,19 @@ public class DiscordBot {
checklistChannel = new ChecklistChannel(config.channel("checklist"));
config.getCouncilThread().forEach((roleId, threadId) -> new CouncilChannel(DiscordBot.getGuild().getRoleById(roleId), DiscordBot.getGuild().getThreadChannelById(threadId)));
- announcementChannel = new DiscordChannel(config.channel("announcement")) {
+ announcementChannel = new DiscordChannel(config.channel("announcement"), 0) {
@Override
public void received(MessageReceivedEvent event) {
Chatter.broadcast().system("ALERT", event.getMessage().getContentDisplay());
}
};
- ingameChat = new DiscordChatRoom(config.channel("ingame"), "CHAT_DISCORD_GLOBAL", Chatter::broadcast);
- serverTeamChat = new DiscordChatRoom(config.channel("serverteam"), "CHAT_SERVERTEAM", Chatter::serverteam);
+
+ // There is a hard limit of 30 messages per minute to send as a webhook, thus with 8 webhooks we can send
+ // 240 messages per minute. Which means 4 every second. I looked at the WGS fights and there were around
+ // ~70 in a short burst and then rather long no new message.
+ ingameChat = new DiscordChatRoom(config.channel("ingame"), "CHAT_DISCORD_GLOBAL", Chatter::globalChat, 8);
+ // 60 messages per minute should be enough for the server team!
+ serverTeamChat = new DiscordChatRoom(config.channel("serverteam"), "CHAT_DISCORD_SERVERTEAM", Chatter::serverteam, 2);
VelocityCore.schedule(() -> {
try {
diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/ChecklistChannel.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/ChecklistChannel.java
index 2e6de441..18bbff4a 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/ChecklistChannel.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/ChecklistChannel.java
@@ -23,6 +23,7 @@ import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.velocitycore.commands.CheckCommand;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@@ -31,7 +32,7 @@ public class ChecklistChannel extends DiscordChannel {
private final List lastSchematics = new ArrayList<>();
public ChecklistChannel(String channel) {
- super(channel);
+ super(channel, 0);
}
public void update() {
@@ -41,7 +42,8 @@ public class ChecklistChannel extends DiscordChannel {
schems.removeIf(schem -> lastSchematics.contains(schem.getId()));
for(SchematicNode schem : schems) {
- system("CHECK_LIST_TO_CHECK", CheckCommand.getWaitTime(schem), schem.getSchemtype().getKuerzel(), SteamwarUser.get(schem.getOwner()).getUserName(), schem.getName());
+ String waitTime = "";
+ system("CHECK_LIST_TO_CHECK", waitTime, schem.getSchemtype().getKuerzel(), SteamwarUser.get(schem.getOwner()).getUserName(), schem.getName());
lastSchematics.add(schem.getId());
}
}
diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java
index b420f601..5fcbcf6a 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java
@@ -27,13 +27,20 @@ import de.steamwar.velocitycore.discord.listeners.ChannelListener;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.Webhook;
+import net.dv8tion.jda.api.entities.WebhookClient;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
+import net.dv8tion.jda.internal.requests.IncomingWebhookClientImpl;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
@AllArgsConstructor
public class DiscordChannel extends Chatter.PlayerlessChatter {
@@ -43,30 +50,82 @@ public class DiscordChannel extends Chatter.PlayerlessChatter {
return user != null ? user : SteamwarUser.get(0);
}
+ private final Queue webhooks = new ArrayDeque<>();
+
private final SteamwarUser user;
@Getter
private final MessageChannel channel;
+ private final int maxNumberOfWebhooks;
+
public DiscordChannel(User user) {
- this(userOrPublic(user), user.openPrivateChannel().complete());
+ this(userOrPublic(user), user.openPrivateChannel().complete(), 0);
}
- public DiscordChannel(String channel) {
- this(DiscordBot.getGuild().getTextChannelById(channel));
+ public DiscordChannel(String channel, int maxNumberOfWebhooks) {
+ this(DiscordBot.getGuild().getTextChannelById(channel), maxNumberOfWebhooks);
}
- public DiscordChannel(MessageChannel channel) {
- this(SteamwarUser.get(-1), channel);
+ public DiscordChannel(MessageChannel channel, int maxNumberOfWebhooks) {
+ this(SteamwarUser.get(-1), channel, maxNumberOfWebhooks);
ChannelListener.getChannels().put(this.channel, this);
+
+ if (channel instanceof TextChannel) {
+ TextChannel textChannel = (TextChannel) channel;
+ webhooks.addAll(textChannel.retrieveWebhooks().complete());
+ while (webhooks.size() > maxNumberOfWebhooks) {
+ webhooks.remove().delete().queue();
+ }
+ while (webhooks.size() < maxNumberOfWebhooks) {
+ webhooks.add(textChannel.createWebhook(DiscordBot.getInstance().getJda().getSelfUser().getName()).complete());
+ }
+ }
}
public void send(String message) {
+ message = message
+ .replace("&", "")
+ .replace("@everyone", "`@everyone`")
+ .replace("@here", "`@here`")
+ .replaceAll("<[@#]!?\\d+>", "`$0`");
+
+ if (maxNumberOfWebhooks > 0 && getChannel() instanceof TextChannel && message.contains("»")) {
+ String[] strings = message.split("»", 2);
+ String userName = strings[0];
+ String sendMessage = strings[1];
+ strings = userName.split(" ");
+
+ String ingameName = strings[strings.length - 1];
+
+ SteamwarUser user = SteamwarUser.get(ingameName);
+ if (user == null) {
+ send(new MessageCreateBuilder()
+ .setContent(message));
+ return;
+ }
+
+ String avatarUrl;
+ if (user.getDiscordId() != null) {
+ avatarUrl = DiscordBot.getGuild().retrieveMemberById(user.getDiscordId()).complete().getEffectiveAvatarUrl();
+ } else {
+ avatarUrl = DiscordBot.getInstance().getJda().getSelfUser().getAvatarUrl();
+ }
+
+ Webhook webhook = webhooks.poll();
+ webhooks.add(webhook);
+
+ // This works as per this documentation: https://discord.com/developers/docs/resources/webhook#execute-webhook
+ IncomingWebhookClientImpl webhookClient = (IncomingWebhookClientImpl) WebhookClient.createClient(DiscordBot.getInstance().getJda(), webhook.getUrl());
+ webhookClient.sendRequest()
+ .setUsername(userName)
+ .setAvatarUrl(avatarUrl)
+ .setContent(sendMessage)
+ .queue();
+ return;
+ }
+
send(new MessageCreateBuilder()
- .setContent(message
- .replace("&", "")
- .replace("@everyone", "`@everyone`")
- .replace("@here", "`@here`")
- .replaceAll("<[@#]!?\\d+>", "`$0`")));
+ .setContent(message));
}
public void send(MessageCreateBuilder builder) {
diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChatRoom.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChatRoom.java
index 7b05357c..2db981f1 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChatRoom.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChatRoom.java
@@ -33,8 +33,8 @@ public class DiscordChatRoom extends DiscordChannel {
private final String format;
private final Supplier target;
- public DiscordChatRoom(String channel, String format, Supplier target) {
- super(channel);
+ public DiscordChatRoom(String channel, String format, Supplier target, int maxNumberOfWebhooks) {
+ super(channel, maxNumberOfWebhooks);
this.format = format;
this.target = target;
}
diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/StaticMessageChannel.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/StaticMessageChannel.java
index 69549d38..9ab2920e 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/StaticMessageChannel.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/StaticMessageChannel.java
@@ -46,14 +46,14 @@ public class StaticMessageChannel extends DiscordChannel {
}
public StaticMessageChannel(String channel, Supplier supplier, Consumer interaction) {
- super(channel);
+ super(channel, 0);
this.supplier = supplier;
this.interaction = interaction;
init();
}
public StaticMessageChannel(MessageChannel channel, Supplier supplier, Consumer interaction) {
- super(channel);
+ super(channel, 0);
this.supplier = supplier;
this.interaction = interaction;
init();
diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java
index f32b4767..5c5e708b 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java
@@ -70,7 +70,7 @@ public class DiscordTicketHandler extends ListenerAdapter {
Permission.MESSAGE_HISTORY).complete();
ticketChannel.getManager().setTopic(event.getUser().getId()).complete();
- DiscordChannel channel = new DiscordChannel(DiscordChannel.userOrPublic(event.getUser()), ticketChannel);
+ DiscordChannel channel = new DiscordChannel(DiscordChannel.userOrPublic(event.getUser()), ticketChannel, 0);
channel.send(new MessageCreateBuilder()
.setEmbeds(new EmbedBuilder()
.setTitle(channel.parseToPlain("DC_TICKET_TITLE"))
diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/PluginMessage.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/PluginMessage.java
index af208aed..5d84eb17 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/listeners/PluginMessage.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/PluginMessage.java
@@ -33,6 +33,8 @@ import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import de.steamwar.messages.Chatter;
import de.steamwar.network.packets.NetworkPacket;
+import de.steamwar.sql.SteamwarUser;
+import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.commands.TeamCommand;
import de.steamwar.velocitycore.mods.*;
@@ -360,6 +362,23 @@ public class PluginMessage extends BasicListener {
))
channelRegisterHandlers.put(channel, player -> Chatter.disconnect(player).prefixless("MOD_YELLOW_SING", "minimap"));
+ for(String channel : Arrays.asList(
+ "flashback:remote_food_data",
+ "flashback:remote_set_slot",
+ "flashback:force_client_tick",
+ "flashback:accurate_entity_position",
+ "flashback:instantly_lerp",
+ "flashback:remote_experience",
+ "flashback:clear_particles",
+ "flashback:remote_select_hotbar_slot", // https://github.com/Moulberry/Flashback/tree/master/src/main/java/com/moulberry/flashback/packet
+ "flashback:clear_entities" // https://github.com/Moulberry/Flashback
+ ))
+ channelRegisterHandlers.put(channel, player -> {
+ if (!SteamwarUser.get(player.getUniqueId()).hasPerm(UserPerm.RESTRICTED_MODS)) {
+ Chatter.disconnect(player).prefixless("MOD_YELLOW_SING", "flashback");
+ }
+ });
+
for(String channel : Arrays.asList("bedrockify:cauldron_particles", "bedrockify:eat-particles")) //https://github.com/juancarloscp52/BedrockIfy (Bedrock features on Java, banned for reach-around block placement)
channelRegisterHandlers.put(channel, player -> Chatter.disconnect(player).prefixless("MOD_YELLOW_SING", "bedrockify"));
@@ -377,7 +396,8 @@ public class PluginMessage extends BasicListener {
"axiom:hello", "axiom:set_gamemode", "axiom:set_fly_speed", "axiom:set_world_time",
"axiom:set_world_property", "axiom:set_block", "axiom:set_hotbar_slot", "axiom:switch_active_hotbar",
"axiom:teleport", "axiom:request_chunk_data", "axiom:spawn_entity", "axiom:response_entity_data",
- "axiom:manipulate_entity", "axiom:delete_entity", "axiom:marker_nbt_request", "axiom:set_buffer"
+ "axiom:manipulate_entity", "axiom:delete_entity", "axiom:marker_nbt_request", "axiom:set_buffer",
+ "axiom:allowed_gamemodes", "axiom:ignore_display_entities", "axiom:add_server_heightmap"
)) {
channelRegisterHandlers.put(channel, player -> {});
registerPassthroughToServer(channel);
@@ -385,7 +405,7 @@ public class PluginMessage extends BasicListener {
for(String channel : Arrays.asList(
"floodgate:skin",
- "watut:nbt", //https://github.com/Corosauce/WATUT
+ "watut:nbt", "watut:nbt_server", //https://github.com/Corosauce/WATUT
"bclib:hello_server",
"vivecraft:data", //https://github.com/Vivecraft/VivecraftMod https://github.com/jrbudda/Vivecraft_Spigot_Extensions https://github.com/Techjar/Vivecraft_BungeeCord_Extensions (VR support)
"badpackets:channel_sync", //https://github.com/badasintended/badpackets (Forge fabric translation layer)
diff --git a/VelocityCore/src/de/steamwar/velocitycore/tablist/Tablist.java b/VelocityCore/src/de/steamwar/velocitycore/tablist/Tablist.java
index f15bc79c..6195bd73 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/tablist/Tablist.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/tablist/Tablist.java
@@ -185,7 +185,6 @@ public class Tablist extends ChannelInboundHandlerAdapter {
if(msg instanceof UpsertPlayerInfoPacket packet) {
packet.getActions().remove(UpsertPlayerInfoPacket.Action.INITIALIZE_CHAT);
packet.getActions().remove(UpsertPlayerInfoPacket.Action.UPDATE_LATENCY);
- packet.getActions().remove(UpsertPlayerInfoPacket.Action.UPDATE_DISPLAY_NAME);
packet.getActions().remove(UpsertPlayerInfoPacket.Action.UPDATE_LISTED);
if(packet.getActions().isEmpty()) {
ReferenceCountUtil.release(msg);
diff --git a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt
index 1beb0f29..ec3b54fb 100644
--- a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt
+++ b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt
@@ -149,6 +149,23 @@ fun Route.configureSchematic() {
return@let SchematicFormat.SPONGE_V2
}
+ if (version == SchematicFormat.SPONGE_V3) {
+ try {
+ val fawe = schem.getCompound("Metadata")
+ .getCompound("WorldEdit")
+ .getString("Version")
+ .value
+
+ if (fawe.equals("2.12.3-SNAPSHOT")) {
+ SWException.log("Schematic with Bugged Version Uploaded", """
+ Schematic=$schemName
+ User=${user.userName}
+ Id=${user.id}
+ """.trimIndent())
+ }
+ } catch (_: Exception) {}
+ }
+
val data = NodeData(node.id, version)
data.saveFromStream(content.inputStream(), version)
diff --git a/buildSrc/src/steamwar.devserver.gradle b/buildSrc/src/steamwar.devserver.gradle
new file mode 100644
index 00000000..53f8be3d
--- /dev/null
+++ b/buildSrc/src/steamwar.devserver.gradle
@@ -0,0 +1,214 @@
+/*
+ * 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 .
+ */
+plugins {
+}
+
+class DevServer extends DefaultTask {
+
+ @Input
+ @Optional
+ String worldName = null
+
+ @Input
+ String template = null
+
+ @Input
+ @Optional
+ String plugins = null
+
+ @Input
+ @Optional
+ Integer port = null
+
+ @Input
+ @Optional
+ String jar = null
+
+ @Input
+ @Optional
+ Map dParams = new HashMap<>()
+
+ DevServer() {
+ super()
+ doFirst {
+ List projects = []
+ projects.add(project)
+ while (projects.first.parent != null) {
+ projects.add(0, projects.first.parent)
+ }
+
+ def properties = new Properties()
+ projects.forEach {
+ def file = new File(it.projectDir, "steamwar.properties")
+ if (file.exists()) {
+ properties.load(new FileInputStream(file))
+ }
+ }
+
+ if (worldName == null) worldName = properties.get("worldName")
+ host = properties.get("host")
+
+ if (host == null) {
+ throw new GradleException("Please supply the 'host' in a 'steamwar.properties' files either in this project dir or any parent project!")
+ }
+ }
+ doLast {
+ checkHasTemplate()
+ uploadDependencies()
+ startDevServer()
+ }
+ finalizedBy(new Finalizer())
+ }
+
+ @Internal
+ BufferedWriter processInput
+
+ @Internal
+ String host
+
+ @Internal
+ Boolean running = true
+
+ class Finalizer extends DefaultTask {
+
+ Finalizer() {
+ super()
+ doLast {
+ running = false
+ if (processInput != null) {
+ processInput.write(template.endsWith("Velocity") ? "end\n" : "stop\n")
+ processInput.flush()
+ }
+ }
+ }
+ }
+
+ void checkHasTemplate() {
+ def process = new ProcessBuilder("ssh", host, "-T", "ls $template").start()
+ process.waitFor()
+ if (new BufferedReader(new InputStreamReader(process.inputStream)).lines().count() < 4) {
+ throw new GradleException("Used template is not in your user.home directory of the given host $host")
+ }
+ }
+
+ void uploadDependencies() {
+ def base = plugins == null ? "$template/plugins" : plugins
+ println("Uploading to ~/$base")
+ this.dependsOn.forEach {
+ Project resolved
+ AbstractArchiveTask archiveTask
+ if (it instanceof String) {
+ resolved = project.findProject(it.substring(0, it.lastIndexOf(':')))
+ archiveTask = (AbstractArchiveTask) resolved.tasks.findByName(it.substring(it.lastIndexOf(':') + 1))
+ } else {
+ throw new GradleException("Illegal argument for uploading dependencies")
+ }
+
+ def archive = archiveTask.archiveFile.get().asFile
+ println("Uploading $archive")
+ new ProcessBuilder("ssh", host, "-T", "rm $base/${archive.name.replace("-all", "")}").start().waitFor()
+ new ProcessBuilder("scp", archive.absolutePath, "$host:~/$base/${archive.name.replace("-all", "")}").start().waitFor()
+ println("Uploaded $archive")
+ }
+ }
+
+ void startDevServer() {
+ def devPy = new StringBuilder().append("dev.py")
+ if (port != null) devPy.append(" --port $port")
+ if (worldName != null) devPy.append(" -w $template/$worldName")
+ if (plugins != null) devPy.append(" -p $plugins")
+ if (jar != null) devPy.append(" --jar $jar")
+ for (Map.Entry dParam : dParams.entrySet()) {
+ devPy.append(" -D${dParam.key}=${dParam.value}")
+ }
+ devPy.append(" $template")
+ println("Starting $template with command ${devPy.toString()}")
+
+ def process = new ProcessBuilder("ssh", host, "-T", devPy.toString()).start()
+ def processOutput = new BufferedReader(new InputStreamReader(process.inputStream))
+ new Thread({
+ while (running) {
+ if (processOutput.ready()) {
+ println(processOutput.readLine())
+ }
+ }
+ }).start()
+
+ processInput = new BufferedWriter(new OutputStreamWriter(process.outputStream))
+ def input = new BufferedReader(new InputStreamReader(System.in))
+ new Thread({
+ while (running) {
+ def text = input.readLine()
+ if (text == null) break
+ processInput.write(text)
+ processInput.newLine()
+ processInput.flush()
+ }
+ }).start()
+
+ process.waitFor()
+ processInput = null
+ running = false
+ }
+}
+
+class FightServer extends DevServer {
+
+ @Input
+ @Optional
+ Integer checkSchemID = 0
+
+ @Input
+ @Optional
+ Integer prepareSchemID = 0
+
+ @Input
+ @Optional
+ Integer replay = 0
+
+ @Input
+ @Optional
+ String config = null
+
+ @Input
+ @Optional
+ // Property: fightID
+ Integer eventKampfID = 0
+
+ @Input
+ @Optional
+ UUID blueLeader = null
+
+ @Input
+ @Optional
+ UUID redLeader = null
+
+ FightServer() {
+ super()
+ doFirst {
+ if (checkSchemID != 0) dParams.put("checkSchemID", "$checkSchemID")
+ if (prepareSchemID != 0) dParams.put("prepareSchemID", "$prepareSchemID")
+ if (replay != 0) dParams.put("replay", "$replay")
+ if (eventKampfID != 0) dParams.put("fightID", "$eventKampfID")
+ if (blueLeader != null) dParams.put("blueLeader", blueLeader.toString())
+ if (redLeader != null) dParams.put("redLeader", redLeader.toString())
+ if (config != null) dParams.put("config", config)
+ }
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 87430368..9a649445 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -27,7 +27,6 @@ private val isInCi by lazy { Os.isFamily(Os.FAMILY_UNIX) && ProcessBuilder("host
dependencyResolutionManagement {
repositories {
-
maven {
url = URI("https://m2.dv8tion.net/releases")
content {
@@ -46,7 +45,7 @@ dependencyResolutionManagement {
if (isInCi) {
url = URI("file:///var/www/maven/")
} else {
- url = URI("https://steamwar.de/maven/")
+ url = URI("https://maven.steamwar.de/")
credentials {
val swProps = Properties()
swProps.load(rootDir.resolve("steamwar.properties").inputStream())
@@ -139,7 +138,7 @@ dependencyResolutionManagement {
library("velocityapi", "com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
library("viaapi", "com.viaversion:viaversion-api:4.3.1")
library("viavelocity", "com.viaversion:viaversion-velocity:4.3.1")
- library("jda", "net.dv8tion:JDA:5.2.0")
+ library("jda", "net.dv8tion:JDA:5.5.1")
library("msgpack", "org.msgpack:msgpack-core:0.9.8")
library("apolloprotos", "com.lunarclient:apollo-protos:1.0-SNAPSHOT")
@@ -219,6 +218,7 @@ include(
"SchematicSystem",
"SchematicSystem:SchematicSystem_8",
"SchematicSystem:SchematicSystem_15",
+ "SchematicSystem:SchematicSystem_19",
"SchematicSystem:SchematicSystem_Core"
)