From 26eff149d4b9ad543498d7c2ed35c6c46d366bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sun, 9 Aug 2026 12:35:05 +0200 Subject: [PATCH 01/10] removed deprecated use of old DimensionType constructor and updated map file paths accordingly --- .idea/compiler.xml | 7 +++++++ .../game/stateless/types/bedwars/Bedwars.java | 3 ++- .../game/stateless/types/boatRace/BoatRace.java | 3 ++- .../eu/mhsl/minenet/minigames/instance/hub/Hub.java | 6 ++---- .../mhsl/minenet/minigames/instance/room/Room.java | 3 ++- .../score/tournament/TournamentDisplay.java | 3 ++- .../minecraft/overworld}/region/r.-1.-1.mca | Bin .../minecraft/overworld}/region/r.-1.-2.mca | Bin .../minecraft/overworld}/region/r.-1.0.mca | Bin .../minecraft/overworld}/region/r.-1.1.mca | Bin .../minecraft/overworld}/region/r.-2.-1.mca | Bin .../minecraft/overworld}/region/r.-2.-2.mca | Bin .../minecraft/overworld}/region/r.-2.0.mca | Bin .../minecraft/overworld}/region/r.-2.1.mca | Bin .../minecraft/overworld}/region/r.0.-1.mca | Bin .../minecraft/overworld}/region/r.0.-2.mca | Bin .../minecraft/overworld}/region/r.0.0.mca | Bin .../minecraft/overworld}/region/r.0.1.mca | Bin .../minecraft/overworld}/region/r.1.-1.mca | Bin .../minecraft/overworld}/region/r.1.-2.mca | Bin .../minecraft/overworld}/region/r.1.0.mca | Bin .../minecraft/overworld}/region/r.1.1.mca | Bin .../minecraft/overworld}/region/r.-1.-1.mca | Bin .../minecraft/overworld}/region/r.-1.-2.mca | Bin .../minecraft/overworld}/region/r.-1.0.mca | Bin .../minecraft/overworld}/region/r.-1.1.mca | Bin .../minecraft/overworld}/region/r.-1.2.mca | Bin .../minecraft/overworld}/region/r.-2.-1.mca | Bin .../minecraft/overworld}/region/r.-2.-2.mca | Bin .../minecraft/overworld}/region/r.-2.0.mca | Bin .../minecraft/overworld}/region/r.-2.1.mca | Bin .../minecraft/overworld}/region/r.-2.2.mca | Bin .../minecraft/overworld}/region/r.0.-1.mca | Bin .../minecraft/overworld}/region/r.0.-2.mca | Bin .../minecraft/overworld}/region/r.0.0.mca | Bin .../minecraft/overworld}/region/r.0.1.mca | Bin .../minecraft/overworld}/region/r.0.2.mca | Bin .../minecraft/overworld}/region/r.1.-1.mca | Bin .../minecraft/overworld}/region/r.1.-2.mca | Bin .../minecraft/overworld}/region/r.1.0.mca | Bin .../minecraft/overworld}/region/r.1.1.mca | Bin .../minecraft/overworld}/region/r.1.2.mca | Bin .../minecraft/overworld}/region/r.-1.-1.mca | Bin .../minecraft/overworld}/region/r.-1.-2.mca | Bin .../minecraft/overworld}/region/r.-1.0.mca | Bin .../minecraft/overworld}/region/r.-1.1.mca | Bin .../minecraft/overworld}/region/r.-2.-1.mca | Bin .../minecraft/overworld}/region/r.-2.-2.mca | Bin .../minecraft/overworld}/region/r.-2.0.mca | Bin .../minecraft/overworld}/region/r.-2.1.mca | Bin .../minecraft/overworld}/region/r.0.-1.mca | Bin .../minecraft/overworld}/region/r.0.-2.mca | Bin .../minecraft/overworld}/region/r.0.0.mca | Bin .../minecraft/overworld}/region/r.0.1.mca | Bin .../minecraft/overworld}/region/r.1.-1.mca | Bin .../minecraft/overworld}/region/r.1.-2.mca | Bin .../minecraft/overworld}/region/r.1.0.mca | Bin .../minecraft/overworld}/region/r.1.1.mca | Bin .../minecraft/overworld}/region/r.-1.-1.mca | Bin .../minecraft/overworld}/region/r.-1.0.mca | Bin .../minecraft/overworld}/region/r.0.-1.mca | Bin .../minecraft/overworld}/region/r.0.0.mca | Bin .../minecraft/overworld}/region/r.-1.-1.mca | Bin .../minecraft/overworld}/region/r.-1.-2.mca | Bin .../minecraft/overworld}/region/r.-1.0.mca | Bin .../minecraft/overworld}/region/r.-1.1.mca | Bin .../minecraft/overworld}/region/r.-2.-1.mca | Bin .../minecraft/overworld}/region/r.-2.-2.mca | Bin .../minecraft/overworld}/region/r.-2.0.mca | Bin .../minecraft/overworld}/region/r.-2.1.mca | Bin .../minecraft/overworld}/region/r.0.-1.mca | Bin .../minecraft/overworld}/region/r.0.-2.mca | Bin .../minecraft/overworld}/region/r.0.0.mca | Bin .../minecraft/overworld}/region/r.0.1.mca | Bin .../minecraft/overworld}/region/r.1.-1.mca | Bin .../minecraft/overworld}/region/r.1.-2.mca | Bin .../minecraft/overworld}/region/r.1.0.mca | Bin .../minecraft/overworld}/region/r.1.1.mca | Bin 78 files changed, 17 insertions(+), 8 deletions(-) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.-1.-1.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.-1.-2.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.-1.0.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.-1.1.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.-2.-1.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.-2.-2.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.-2.0.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.-2.1.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.0.-1.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.0.-2.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.0.0.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.0.1.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.1.-1.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.1.-2.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.1.0.mca (100%) rename src/main/resources/maps/game/bedwars/test/{ => dimensions/minecraft/overworld}/region/r.1.1.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-1.-1.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-1.-2.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-1.0.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-1.1.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-1.2.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-2.-1.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-2.-2.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-2.0.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-2.1.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.-2.2.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.0.-1.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.0.-2.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.0.0.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.0.1.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.0.2.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.1.-1.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.1.-2.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.1.0.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.1.1.mca (100%) rename src/main/resources/maps/game/boatRace/woodlandMansion/{ => dimensions/minecraft/overworld}/region/r.1.2.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.-1.-1.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.-1.-2.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.-1.0.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.-1.1.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.-2.-1.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.-2.-2.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.-2.0.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.-2.1.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.0.-1.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.0.-2.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.0.0.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.0.1.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.1.-1.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.1.-2.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.1.0.mca (100%) rename src/main/resources/maps/hub/{ => dimensions/minecraft/overworld}/region/r.1.1.mca (100%) rename src/main/resources/maps/lobby/{ => dimensions/minecraft/overworld}/region/r.-1.-1.mca (100%) rename src/main/resources/maps/lobby/{ => dimensions/minecraft/overworld}/region/r.-1.0.mca (100%) rename src/main/resources/maps/lobby/{ => dimensions/minecraft/overworld}/region/r.0.-1.mca (100%) rename src/main/resources/maps/lobby/{ => dimensions/minecraft/overworld}/region/r.0.0.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.-1.-1.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.-1.-2.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.-1.0.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.-1.1.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.-2.-1.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.-2.-2.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.-2.0.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.-2.1.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.0.-1.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.0.-2.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.0.0.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.0.1.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.1.-1.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.1.-2.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.1.0.mca (100%) rename src/main/resources/maps/resultdisplay/{ => dimensions/minecraft/overworld}/region/r.1.1.mca (100%) diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b86273d..7b18ee8 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -3,4 +3,11 @@ + + + \ No newline at end of file diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/bedwars/Bedwars.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/bedwars/Bedwars.java index 68273aa..ee9aca2 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/bedwars/Bedwars.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/bedwars/Bedwars.java @@ -26,6 +26,7 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.timer.ExecutionType; import net.minestom.server.timer.TaskSchedule; +import net.minestom.server.world.DimensionType; import org.jetbrains.annotations.NotNull; import java.io.IOException; @@ -41,7 +42,7 @@ public class Bedwars extends StatelessGame { public Bedwars() throws IOException { super(Dimension.OVERWORLD.key, "Bedwars", new LastWinsScore()); - this.setChunkLoader(new AnvilLoader(Resource.GAME_MAP.getPath().resolve("bedwars/test"))); + this.setChunkLoader(new AnvilLoader(Resource.GAME_MAP.getPath().resolve("bedwars/test"), DimensionType.OVERWORLD.key())); Configuration config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(Resource.GAME_MAP.getPath().resolve("bedwars/test/config.yml").toFile()); List teamNames = config.getStringList("setup.teams"); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/boatRace/BoatRace.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/boatRace/BoatRace.java index f6b81cb..2ace4bc 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/boatRace/BoatRace.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/boatRace/BoatRace.java @@ -15,6 +15,7 @@ import net.minestom.server.entity.Player; import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.instance.anvil.AnvilLoader; import net.minestom.server.instance.block.Block; +import net.minestom.server.world.DimensionType; import org.jetbrains.annotations.NotNull; import java.util.concurrent.CompletableFuture; @@ -23,7 +24,7 @@ import java.util.concurrent.CompletableFuture; public class BoatRace extends StatelessGame { public BoatRace() { super(Dimension.OVERWORLD.key, "boatRace", new FirstWinsScore()); - this.setChunkLoader(new AnvilLoader(Resource.GAME_MAP.getPath().resolve("boatRace/woodlandMansion"))); + this.setChunkLoader(new AnvilLoader(Resource.GAME_MAP.getPath().resolve("boatRace/woodlandMansion"), DimensionType.OVERWORLD.key())); } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/hub/Hub.java b/src/main/java/eu/mhsl/minenet/minigames/instance/hub/Hub.java index 1ba0635..383c8ce 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/hub/Hub.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/hub/Hub.java @@ -12,8 +12,7 @@ import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.event.player.PlayerBlockPlaceEvent; import net.minestom.server.instance.anvil.AnvilLoader; - -import java.nio.file.Path; +import net.minestom.server.world.DimensionType; public class Hub extends MineNetInstance implements Spawnable { public static final Hub INSTANCE = new Hub(); @@ -21,7 +20,7 @@ public class Hub extends MineNetInstance implements Spawnable { static { MinecraftServer.getInstanceManager().registerInstance(INSTANCE); - INSTANCE.setChunkLoader(new AnvilLoader(Resource.HUB_MAP.getPath())); + INSTANCE.setChunkLoader(new AnvilLoader(Resource.HUB_MAP.getPath(), DimensionType.OVERWORLD.key())); INSTANCE.eventNode() .addListener(PlayerBlockBreakEvent.class, CommonEventHandles::cancel) @@ -33,7 +32,6 @@ public class Hub extends MineNetInstance implements Spawnable { private Hub() { super(Dimension.THE_END.key); - this.setChunkLoader(new AnvilLoader(Path.of("maps/hub"))); this.setTime(18000); this.defaultClock().pause(); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/room/Room.java b/src/main/java/eu/mhsl/minenet/minigames/instance/room/Room.java index 4e156ce..40cefd5 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/room/Room.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/room/Room.java @@ -18,6 +18,7 @@ import net.minestom.server.entity.Player; import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.instance.anvil.AnvilLoader; +import net.minestom.server.world.DimensionType; import java.util.*; import java.util.logging.Logger; @@ -102,7 +103,7 @@ public class Room extends MineNetInstance implements Spawnable { private void construct() { MinecraftServer.getInstanceManager().registerInstance(this); - this.setChunkLoader(new AnvilLoader(Resource.LOBBY_MAP.getPath())); + this.setChunkLoader(new AnvilLoader(Resource.LOBBY_MAP.getPath(), DimensionType.OVERWORLD.key())); this.gameSelector = new GameSelector(); this.gameSelector.setInstance(this, new Pos(0.5, 50, 19.5)); diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/tournament/TournamentDisplay.java b/src/main/java/eu/mhsl/minenet/minigames/score/tournament/TournamentDisplay.java index 16d5495..6fe9782 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/tournament/TournamentDisplay.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/tournament/TournamentDisplay.java @@ -12,6 +12,7 @@ import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.instance.anvil.AnvilLoader; +import net.minestom.server.world.DimensionType; import java.util.Comparator; import java.util.List; @@ -29,7 +30,7 @@ public class TournamentDisplay extends MineNetInstance implements Spawnable { public TournamentDisplay(Tournament tournament) { super(Dimension.OVERWORLD.key); - this.setChunkLoader(new AnvilLoader(Resource.RESULT_DISPLAY.getPath())); + this.setChunkLoader(new AnvilLoader(Resource.RESULT_DISPLAY.getPath(), DimensionType.OVERWORLD.key())); this.places = tournament.getPlaces(); this.tournament = tournament; diff --git a/src/main/resources/maps/game/bedwars/test/region/r.-1.-1.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-1.-1.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.-1.-1.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-1.-1.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.-1.-2.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-1.-2.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.-1.-2.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-1.-2.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.-1.0.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-1.0.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.-1.0.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-1.0.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.-1.1.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-1.1.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.-1.1.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-1.1.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.-2.-1.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-2.-1.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.-2.-1.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-2.-1.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.-2.-2.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-2.-2.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.-2.-2.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-2.-2.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.-2.0.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-2.0.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.-2.0.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-2.0.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.-2.1.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-2.1.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.-2.1.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.-2.1.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.0.-1.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.0.-1.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.0.-1.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.0.-1.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.0.-2.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.0.-2.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.0.-2.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.0.-2.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.0.0.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.0.0.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.0.0.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.0.0.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.0.1.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.0.1.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.0.1.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.0.1.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.1.-1.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.1.-1.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.1.-1.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.1.-1.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.1.-2.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.1.-2.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.1.-2.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.1.-2.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.1.0.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.1.0.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.1.0.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.1.0.mca diff --git a/src/main/resources/maps/game/bedwars/test/region/r.1.1.mca b/src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.1.1.mca similarity index 100% rename from src/main/resources/maps/game/bedwars/test/region/r.1.1.mca rename to src/main/resources/maps/game/bedwars/test/dimensions/minecraft/overworld/region/r.1.1.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.-1.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.-1.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.-1.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.-1.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.-2.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.-2.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.-2.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.-2.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.0.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.0.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.0.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.0.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.1.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.1.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.1.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.1.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.2.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.2.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-1.2.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-1.2.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.-1.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.-1.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.-1.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.-1.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.-2.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.-2.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.-2.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.-2.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.0.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.0.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.0.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.0.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.1.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.1.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.1.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.1.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.2.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.2.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.-2.2.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.-2.2.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.-1.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.-1.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.-1.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.-1.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.-2.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.-2.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.-2.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.-2.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.0.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.0.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.0.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.0.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.1.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.1.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.1.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.1.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.2.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.2.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.0.2.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.0.2.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.-1.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.-1.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.-1.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.-1.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.-2.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.-2.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.-2.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.-2.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.0.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.0.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.0.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.0.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.1.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.1.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.1.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.1.mca diff --git a/src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.2.mca b/src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.2.mca similarity index 100% rename from src/main/resources/maps/game/boatRace/woodlandMansion/region/r.1.2.mca rename to src/main/resources/maps/game/boatRace/woodlandMansion/dimensions/minecraft/overworld/region/r.1.2.mca diff --git a/src/main/resources/maps/hub/region/r.-1.-1.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-1.-1.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.-1.-1.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-1.-1.mca diff --git a/src/main/resources/maps/hub/region/r.-1.-2.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-1.-2.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.-1.-2.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-1.-2.mca diff --git a/src/main/resources/maps/hub/region/r.-1.0.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-1.0.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.-1.0.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-1.0.mca diff --git a/src/main/resources/maps/hub/region/r.-1.1.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-1.1.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.-1.1.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-1.1.mca diff --git a/src/main/resources/maps/hub/region/r.-2.-1.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-2.-1.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.-2.-1.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-2.-1.mca diff --git a/src/main/resources/maps/hub/region/r.-2.-2.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-2.-2.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.-2.-2.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-2.-2.mca diff --git a/src/main/resources/maps/hub/region/r.-2.0.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-2.0.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.-2.0.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-2.0.mca diff --git a/src/main/resources/maps/hub/region/r.-2.1.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-2.1.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.-2.1.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.-2.1.mca diff --git a/src/main/resources/maps/hub/region/r.0.-1.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.0.-1.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.0.-1.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.0.-1.mca diff --git a/src/main/resources/maps/hub/region/r.0.-2.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.0.-2.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.0.-2.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.0.-2.mca diff --git a/src/main/resources/maps/hub/region/r.0.0.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.0.0.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.0.0.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.0.0.mca diff --git a/src/main/resources/maps/hub/region/r.0.1.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.0.1.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.0.1.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.0.1.mca diff --git a/src/main/resources/maps/hub/region/r.1.-1.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.1.-1.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.1.-1.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.1.-1.mca diff --git a/src/main/resources/maps/hub/region/r.1.-2.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.1.-2.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.1.-2.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.1.-2.mca diff --git a/src/main/resources/maps/hub/region/r.1.0.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.1.0.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.1.0.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.1.0.mca diff --git a/src/main/resources/maps/hub/region/r.1.1.mca b/src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.1.1.mca similarity index 100% rename from src/main/resources/maps/hub/region/r.1.1.mca rename to src/main/resources/maps/hub/dimensions/minecraft/overworld/region/r.1.1.mca diff --git a/src/main/resources/maps/lobby/region/r.-1.-1.mca b/src/main/resources/maps/lobby/dimensions/minecraft/overworld/region/r.-1.-1.mca similarity index 100% rename from src/main/resources/maps/lobby/region/r.-1.-1.mca rename to src/main/resources/maps/lobby/dimensions/minecraft/overworld/region/r.-1.-1.mca diff --git a/src/main/resources/maps/lobby/region/r.-1.0.mca b/src/main/resources/maps/lobby/dimensions/minecraft/overworld/region/r.-1.0.mca similarity index 100% rename from src/main/resources/maps/lobby/region/r.-1.0.mca rename to src/main/resources/maps/lobby/dimensions/minecraft/overworld/region/r.-1.0.mca diff --git a/src/main/resources/maps/lobby/region/r.0.-1.mca b/src/main/resources/maps/lobby/dimensions/minecraft/overworld/region/r.0.-1.mca similarity index 100% rename from src/main/resources/maps/lobby/region/r.0.-1.mca rename to src/main/resources/maps/lobby/dimensions/minecraft/overworld/region/r.0.-1.mca diff --git a/src/main/resources/maps/lobby/region/r.0.0.mca b/src/main/resources/maps/lobby/dimensions/minecraft/overworld/region/r.0.0.mca similarity index 100% rename from src/main/resources/maps/lobby/region/r.0.0.mca rename to src/main/resources/maps/lobby/dimensions/minecraft/overworld/region/r.0.0.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.-1.-1.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-1.-1.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.-1.-1.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-1.-1.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.-1.-2.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-1.-2.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.-1.-2.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-1.-2.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.-1.0.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-1.0.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.-1.0.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-1.0.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.-1.1.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-1.1.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.-1.1.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-1.1.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.-2.-1.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-2.-1.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.-2.-1.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-2.-1.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.-2.-2.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-2.-2.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.-2.-2.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-2.-2.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.-2.0.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-2.0.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.-2.0.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-2.0.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.-2.1.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-2.1.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.-2.1.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.-2.1.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.0.-1.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.0.-1.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.0.-1.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.0.-1.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.0.-2.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.0.-2.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.0.-2.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.0.-2.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.0.0.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.0.0.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.0.0.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.0.0.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.0.1.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.0.1.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.0.1.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.0.1.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.1.-1.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.1.-1.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.1.-1.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.1.-1.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.1.-2.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.1.-2.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.1.-2.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.1.-2.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.1.0.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.1.0.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.1.0.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.1.0.mca diff --git a/src/main/resources/maps/resultdisplay/region/r.1.1.mca b/src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.1.1.mca similarity index 100% rename from src/main/resources/maps/resultdisplay/region/r.1.1.mca rename to src/main/resources/maps/resultdisplay/dimensions/minecraft/overworld/region/r.1.1.mca From 75cd304bda987552dc5a2bcd242a2c61b1ac9189 Mon Sep 17 00:00:00 2001 From: jannis Date: Fri, 16 Oct 2026 20:43:14 +0200 Subject: [PATCH 02/10] fixed issues in BuildBattle --- .../stateless/types/buildBattle/BuildBattle.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java index 95ce16c..8145ad8 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java @@ -97,11 +97,11 @@ public class BuildBattle extends StatelessGame { ); this.spawnPositions.put(player, plotCenter); - if(this.spawnPosx >= rowCount) { + if(this.spawnPosx >= rowCount - 1) { this.spawnPosx = 0; this.spawnPosz++; - } - this.spawnPosx++; + } else this.spawnPosx ++; + player.setGameMode(GameMode.ADVENTURE); this.scheduler().scheduleNextTick(() -> player.teleport(plotCenter.add(0, 1.5, 0))); return super.onPlayerJoin(player); @@ -164,12 +164,14 @@ public class BuildBattle extends StatelessGame { } private void finishRound() { - int sum = this.currentVotes.values().stream().mapToInt(Integer::intValue).sum(); - this.getPlayers().forEach(p -> p.getInventory().clear()); + int voteSum = this.currentVotes.values().stream() + .mapToInt(Integer::intValue) + .sum(); + int score = (int) Math.round((double) voteSum / this.getPlayers().size()); - Player owner = this.currentOwner; + this.getPlayers().forEach(p -> p.getInventory().clear()); + this.getScore().insertResult(this.currentOwner, score); this.currentOwner = null; - this.getScore().insertResult(owner, sum); } private boolean isInArea(Point block, Player player) { From 8dc165952a8c11594947e6503826e17bd9377174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sat, 17 Oct 2026 22:41:48 +0200 Subject: [PATCH 03/10] Optionally drop chat locally when the proxy distributes it (velocity.chat-via-proxy) --- .../minigames/handler/global/ChatFormatHandler.java | 8 ++++++++ src/main/resources/config.yml | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/eu/mhsl/minenet/minigames/handler/global/ChatFormatHandler.java b/src/main/java/eu/mhsl/minenet/minigames/handler/global/ChatFormatHandler.java index 94ea02b..72c251a 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/handler/global/ChatFormatHandler.java +++ b/src/main/java/eu/mhsl/minenet/minigames/handler/global/ChatFormatHandler.java @@ -1,5 +1,6 @@ package eu.mhsl.minenet.minigames.handler.global; +import eu.mhsl.minenet.minigames.Main; import eu.mhsl.minenet.minigames.message.Icon; import eu.mhsl.minenet.minigames.message.type.ChatMessage; import net.kyori.adventure.text.Component; @@ -9,6 +10,9 @@ import net.minestom.server.event.player.PlayerChatEvent; import org.jetbrains.annotations.NotNull; public class ChatFormatHandler implements EventListener { + // Verteilt der Proxy den Chat (chat-bridge bei CraftAttack), darf er hier nicht noch einmal erscheinen + private final boolean chatViaProxy = Main.globalConfig.node("velocity", "chat-via-proxy").getBoolean(false); + @Override public @NotNull Class eventType() { return PlayerChatEvent.class; @@ -16,6 +20,10 @@ public class ChatFormatHandler implements EventListener { @Override public @NotNull Result run(@NotNull PlayerChatEvent event) { + if(this.chatViaProxy) { + event.setCancelled(true); + return Result.SUCCESS; + } NamedTextColor color = event.getPlayer().getPermissionLevel() > 0 ? NamedTextColor.AQUA : NamedTextColor.GRAY; event.setFormattedMessage( new ChatMessage(Icon.CHAT) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 39956b0..f7c93d6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -9,6 +9,8 @@ bungeecord: velocity: enabled: false + # Chat nur über den Proxy verteilen, hier verwerfen (chat-bridge) + chat-via-proxy: false secret: '' api: From a18a6b0dcaaa9a75e3472e731c33d79c92b51d0f Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Oct 2026 00:17:33 +0200 Subject: [PATCH 04/10] fixed placement issues in BuildBattle and added isInArea methode to Position.java --- .../buildBattle/BlockPlacementHelper.java | 896 ++++++++++++++++++ .../types/buildBattle/BuildBattle.java | 59 +- .../types/buildBattle/FluidFlowHelper.java | 268 ++++++ .../mhsl/minenet/minigames/util/Position.java | 13 + 4 files changed, 1227 insertions(+), 9 deletions(-) create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/FluidFlowHelper.java diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java new file mode 100644 index 0000000..8d661a3 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java @@ -0,0 +1,896 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle; + +import net.minestom.server.coordinate.BlockVec; +import net.minestom.server.coordinate.Point; +import net.minestom.server.entity.Player; +import net.minestom.server.event.player.PlayerBlockBreakEvent; +import net.minestom.server.event.player.PlayerBlockInteractEvent; +import net.minestom.server.event.player.PlayerBlockPlaceEvent; +import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; +import net.minestom.server.instance.block.BlockFace; +import net.minestom.server.utils.Direction; + +import java.util.Map; +import java.util.Set; + +public final class BlockPlacementHelper { + private BlockPlacementHelper() {} + + private static final Set SIX_DIR = Set.of( + "observer", "dispenser", "dropper", "piston", "sticky_piston", + "amethyst_cluster", "small_amethyst_bud", "medium_amethyst_bud", "large_amethyst_bud", + "end_rod", "lightning_rod", "shulker_box" + ); + + public static void apply(PlayerBlockPlaceEvent event) { + Block block = event.getBlock(); + BlockFace face = event.getBlockFace(); + BlockVec pos = event.getBlockPosition(); + Point cursor = event.getCursorPosition(); + Player player = event.getPlayer(); + Instance instance = event.getInstance(); + + String path = block.key().value(); + + Block existing = instance.getBlock(pos); + if ((path.endsWith("_candle") || path.equals("candle")) && existing.compare(block)) { + int n = parseIntOr(existing.getProperty("candles"), 1); + event.setBlock(n < 4 ? existing.withProperty("candles", String.valueOf(n + 1)) : existing); + return; + } + if (path.equals("snow") && existing.compare(block)) { + int n = parseIntOr(existing.getProperty("layers"), 1); + event.setBlock(n < 8 ? existing.withProperty("layers", String.valueOf(n + 1)) : existing); + return; + } + if (path.equals("sea_pickle") && existing.compare(block)) { + int n = parseIntOr(existing.getProperty("pickles"), 1); + event.setBlock(n < 4 ? existing.withProperty("pickles", String.valueOf(n + 1)) : existing); + return; + } + if (path.equals("turtle_egg") && existing.compare(block)) { + int n = parseIntOr(existing.getProperty("eggs"), 1); + event.setBlock(n < 4 ? existing.withProperty("eggs", String.valueOf(n + 1)) : existing); + return; + } + + Block oriented = orient(block, path, face, cursor, player, instance, pos); + if (oriented != block) event.setBlock(oriented); + + Block finalOriented = oriented; + String finalPath = finalOriented.key().value(); + + if (path.endsWith("_door")) { + Block lower = event.getBlock(); + String facing = lower.getProperty("facing"); + String hinge = lower.getProperty("hinge"); + Block upper = lower.withProperty("half", "upper").withProperty("facing", facing).withProperty("hinge", hinge); + instance.scheduler().scheduleNextTick(() -> instance.setBlock(pos.add(0, 1, 0), upper)); + } + + if (path.endsWith("_bed")) { + String facing = finalOriented.getProperty("facing"); + Direction d = facingToDirection(facing); + Block head = finalOriented.withProperty("part", "head"); + BlockVec headPos = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + instance.scheduler().scheduleNextTick(() -> instance.setBlock(headPos, head)); + } + + if (path.equals("big_dripleaf")) { + Block upper = finalOriented; + Block lower = Block.BIG_DRIPLEAF_STEM.withProperty("facing", finalOriented.getProperty("facing")); + instance.scheduler().scheduleNextTick(() -> instance.setBlock(pos.add(0, 1, 0), upper.withProperty("half", "upper"))); + } + + if (isConnecting(path)) { + instance.scheduler().scheduleNextTick(() -> { + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = instance.getBlock(np); + if (isConnecting(nb.key().value())) instance.setBlock(np, computeConnections(nb, nb.key().value(), instance, np)); + } + Block self = instance.getBlock(pos); + if (isConnecting(self.key().value())) instance.setBlock(pos, computeConnections(self, self.key().value(), instance, pos)); + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = instance.getBlock(np); + if (nb.key().value().endsWith("_fence_gate")) { + instance.setBlock(np, updateFenceGateInWall(nb, instance, np)); + } + } + }); + } + + if (path.endsWith("_fence_gate")) { + instance.scheduler().scheduleNextTick(() -> instance.setBlock(pos, updateFenceGateInWall(instance.getBlock(pos), instance, pos))); + } + + if (path.equals("redstone_wire")) { + instance.scheduler().scheduleNextTick(() -> { + updateRedstoneWire(instance, pos); + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + if (instance.getBlock(np).key().value().equals("redstone_wire")) updateRedstoneWire(instance, np); + } + }); + } + + if (isRail(path)) { + instance.scheduler().scheduleNextTick(() -> updateRailShape(instance, pos)); + } + + if (path.equals("scaffolding")) { + instance.scheduler().scheduleNextTick(() -> updateScaffolding(instance, pos)); + } + + if (finalPath.equals("chest") || finalPath.equals("trapped_chest")) { + instance.scheduler().scheduleNextTick(() -> updateChestPair(instance, pos)); + } + } + + private static Block orient(Block block, String path, BlockFace face, Point cursor, Player player, + Instance instance, BlockVec pos) { + Map props = block.properties(); + Block result = block; + + if (props.containsKey("axis")) { + result = result.withProperty("axis", switch (face) { + case TOP, BOTTOM -> "y"; + case NORTH, SOUTH -> "z"; + case EAST, WEST -> "x"; + }); + } + + if (props.containsKey("type") && path.endsWith("_slab")) { + Block existing = instance.getBlock(pos); + if (existing.compare(block)) { + result = result.withProperty("type", "double"); + } else { + boolean top = face == BlockFace.BOTTOM || (face != BlockFace.TOP && cursor.y() > 0.5); + result = result.withProperty("type", top ? "top" : "bottom"); + } + } + + if (path.endsWith("_stairs")) { + String facing = yawToFacing(player.getPosition().yaw()); + boolean top = face == BlockFace.BOTTOM || (face != BlockFace.TOP && cursor.y() > 0.5); + result = result.withProperty("facing", facing).withProperty("half", top ? "top" : "bottom"); + result = applyStairShape(result, instance, pos, facing, top); + } + + if (path.endsWith("_trapdoor")) { + String facing; + boolean top; + if (face == BlockFace.TOP) { top = false; facing = yawToFacing(player.getPosition().yaw() + 180); } + else if (face == BlockFace.BOTTOM) { top = true; facing = yawToFacing(player.getPosition().yaw() + 180); } + else { top = cursor.y() > 0.5; facing = oppositeFacing(faceName(face)); } + result = result.withProperty("facing", facing).withProperty("half", top ? "top" : "bottom") + .withProperty("open", "false").withProperty("powered", "false"); + } + + if (path.endsWith("_door")) { + String facing = yawToFacing(player.getPosition().yaw()); + String hinge = doorHinge(facing, cursor, instance, pos, path); + result = result.withProperty("facing", facing) + .withProperty("half", "lower") + .withProperty("hinge", hinge) + .withProperty("open", "false") + .withProperty("powered", "false"); + } + + if (path.endsWith("_fence_gate")) { + String facing = yawToFacing(player.getPosition().yaw()); + result = result.withProperty("facing", facing).withProperty("open", "false") + .withProperty("powered", "false").withProperty("in_wall", "false"); + } + + if (path.endsWith("_bed")) { + String facing = yawToFacing(player.getPosition().yaw()); + result = result.withProperty("facing", facing).withProperty("part", "foot").withProperty("occupied", "false"); + } + + if (path.endsWith("_button") || path.equals("lever") || path.equals("grindstone")) { + String attachFace; String facing; + if (face == BlockFace.TOP) { attachFace = "floor"; facing = yawToFacing(player.getPosition().yaw()); } + else if (face == BlockFace.BOTTOM) { attachFace = "ceiling"; facing = yawToFacing(player.getPosition().yaw()); } + else { attachFace = "wall"; facing = oppositeFacing(faceName(face)); } + result = result.withProperty("face", attachFace).withProperty("facing", facing); + } + + if (path.equals("bell")) { + String attachment; String facing; + if (face == BlockFace.TOP) { attachment = "floor"; facing = yawToFacing(player.getPosition().yaw()); } + else if (face == BlockFace.BOTTOM) { attachment = "ceiling"; facing = yawToFacing(player.getPosition().yaw()); } + else { + attachment = "single_wall"; + facing = oppositeFacing(faceName(face)); + } + result = result.withProperty("attachment", attachment).withProperty("facing", facing); + } + + if (path.equals("lantern") || path.equals("soul_lantern")) { + result = result.withProperty("hanging", face == BlockFace.BOTTOM ? "true" : "false"); + } + + if (path.equals("tripwire_hook")) { + String facing = face != BlockFace.TOP && face != BlockFace.BOTTOM + ? oppositeFacing(faceName(face)) + : yawToFacing(player.getPosition().yaw()); + result = result.withProperty("facing", facing).withProperty("attached", "false").withProperty("powered", "false"); + } + + if (path.equals("hopper")) { + String facing = face == BlockFace.TOP ? "down" : (face == BlockFace.BOTTOM ? "down" : oppositeFacing(faceName(face))); + result = result.withProperty("facing", facing).withProperty("enabled", "true"); + } + + if (path.equals("campfire") || path.equals("soul_campfire")) { + Block below = instance.getBlock(new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ())); + String signalFire = below.key().value().equals("hay_block") ? "true" : "false"; + result = result.withProperty("facing", yawToFacing(player.getPosition().yaw())) + .withProperty("lit", "true").withProperty("signal_fire", signalFire); + } + + if (path.equals("pointed_dripstone")) { + String dir = face == BlockFace.BOTTOM ? "down" : "up"; + result = result.withProperty("vertical_direction", dir).withProperty("thickness", "tip"); + } + + if (path.equals("chorus_flower")) { + result = result.withProperty("age", "0"); + } + + if (path.equals("end_portal_frame") || path.equals("respawn_anchor")) { + if (props.containsKey("facing")) { + result = result.withProperty("facing", yawToFacing(player.getPosition().yaw())); + } + if (props.containsKey("eye")) result = result.withProperty("eye", "false"); + } + + if ((path.equals("torch") || path.equals("soul_torch") || path.equals("redstone_torch") || path.equals("copper_torch")) + && face != BlockFace.TOP && face != BlockFace.BOTTOM) { + Block wall = switch (path) { + case "torch" -> Block.WALL_TORCH; + case "soul_torch" -> Block.SOUL_WALL_TORCH; + case "redstone_torch" -> Block.REDSTONE_WALL_TORCH; + case "copper_torch" -> Block.COPPER_WALL_TORCH; + default -> null; + }; + if (wall != null) result = wall.withProperty("facing", oppositeFacing(faceName(face))); + } + + if (path.endsWith("_skull") || path.endsWith("_head")) { + if (face != BlockFace.TOP && face != BlockFace.BOTTOM) { + String wallName = path.endsWith("_skull") ? path.replace("_skull", "_wall_skull") : path.replace("_head", "_wall_head"); + Block wall = Block.fromKey("minecraft:" + wallName); + if (wall != null) result = wall.withProperty("facing", oppositeFacing(faceName(face))); + } else if (face == BlockFace.TOP && result.properties().containsKey("rotation")) { + int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; + result = result.withProperty("rotation", String.valueOf(rot)); + } + } + + if (path.endsWith("_sign") && !path.endsWith("_wall_sign") && !path.contains("hanging") + && face != BlockFace.TOP && face != BlockFace.BOTTOM) { + Block wallSign = Block.fromKey("minecraft:" + path.replace("_sign", "_wall_sign")); + if (wallSign != null) result = wallSign.withProperty("facing", oppositeFacing(faceName(face))); + } else if (path.endsWith("_sign") && !path.endsWith("_wall_sign") && !path.contains("hanging") + && face == BlockFace.TOP) { + int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; + if (result.properties().containsKey("rotation")) result = result.withProperty("rotation", String.valueOf(rot)); + } + + if (path.endsWith("_hanging_sign") && !path.contains("_wall_") + && face != BlockFace.TOP && face != BlockFace.BOTTOM) { + Block wallHang = Block.fromKey("minecraft:" + path.replace("_hanging_sign", "_wall_hanging_sign")); + if (wallHang != null) result = wallHang.withProperty("facing", oppositeFacing(faceName(face))); + } else if (path.endsWith("_hanging_sign") && !path.contains("_wall_")) { + int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; + if (result.properties().containsKey("rotation")) result = result.withProperty("rotation", String.valueOf(rot)); + if (result.properties().containsKey("attached")) result = result.withProperty("attached", face == BlockFace.BOTTOM ? "true" : "false"); + } + + if (isBanner(path)) { + if (face != BlockFace.TOP && face != BlockFace.BOTTOM) { + Block wallBanner = Block.fromKey("minecraft:" + path.replace("_banner", "_wall_banner")); + if (wallBanner != null) result = wallBanner.withProperty("facing", oppositeFacing(faceName(face))); + } else if (face == BlockFace.TOP) { + int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; + if (result.properties().containsKey("rotation")) result = result.withProperty("rotation", String.valueOf(rot)); + } + } + + if (path.equals("vine")) { + Block existing = instance.getBlock(pos); + Block base = existing.compare(block) ? existing : result.withProperty("up", "false") + .withProperty("north", "false").withProperty("south", "false") + .withProperty("east", "false").withProperty("west", "false"); + String side = switch (face) { + case BOTTOM -> "up"; + case NORTH -> "south"; + case SOUTH -> "north"; + case EAST -> "west"; + case WEST -> "east"; + default -> null; + }; + result = side != null ? base.withProperty(side, "true") : base; + } + + if (path.equals("glow_lichen") || path.equals("sculk_vein") || path.equals("resin_clump")) { + Block existing = instance.getBlock(pos); + Block base = existing.compare(block) ? existing : result + .withProperty("up", "false").withProperty("down", "false") + .withProperty("north", "false").withProperty("south", "false") + .withProperty("east", "false").withProperty("west", "false"); + String side = switch (face) { + case TOP -> "down"; + case BOTTOM -> "up"; + case NORTH -> "south"; + case SOUTH -> "north"; + case EAST -> "west"; + case WEST -> "east"; + }; + result = base.withProperty(side, "true"); + } + + if (path.equals("red_mushroom_block") || path.equals("brown_mushroom_block") || path.equals("mushroom_stem")) { + result = result.withProperty("up", "true").withProperty("down", "true") + .withProperty("north", "true").withProperty("south", "true") + .withProperty("east", "true").withProperty("west", "true"); + String hiddenFace = faceName(face); + if (result.properties().containsKey(hiddenFace)) result = result.withProperty(hiddenFace, "false"); + } + + if (props.containsKey("facing") && !path.endsWith("_stairs") && !path.endsWith("_door") + && !path.endsWith("_trapdoor") && !path.endsWith("_fence_gate") && !path.endsWith("_button") + && !path.equals("lever") && !path.equals("grindstone") && !path.equals("bell") + && !path.equals("hopper") && !path.equals("campfire") && !path.equals("soul_campfire") + && !path.equals("tripwire_hook") + && !path.endsWith("wall_torch") && !path.endsWith("_bed") && !path.endsWith("_sign") + && !path.endsWith("_hanging_sign") && !path.endsWith("_banner") && !path.endsWith("_wall_banner") + && !path.endsWith("_skull") && !path.endsWith("_head") + && !path.equals("end_portal_frame") && !path.equals("respawn_anchor")) { + Direction fdir = faceDirection(face); + String facing; + if (fdir != null && SIX_DIR.contains(path)) { + facing = fdir.opposite().name().toLowerCase(); + } else if (path.equals("repeater") || path.equals("comparator")) { + facing = oppositeFacing(yawToFacing(player.getPosition().yaw())); + } else { + facing = yawToFacing(player.getPosition().yaw()); + } + try { result = result.withProperty("facing", facing); } catch (Exception ignored) {} + } + + if (isConnecting(path)) result = computeConnections(result, path, instance, pos); + + if (props.containsKey("waterlogged") && Block.WATER.compare(instance.getBlock(pos))) { + try { result = result.withProperty("waterlogged", "true"); } catch (Exception ignored) {} + } + + return result; + } + + private static boolean isBanner(String path) { + return path.endsWith("_banner") && !path.endsWith("_wall_banner"); + } + + private static Block applyStairShape(Block stair, Instance instance, BlockVec pos, String facing, boolean top) { + Direction f = facingToDirection(facing); + Block front = instance.getBlock(new BlockVec(pos.blockX() + f.normalX(), pos.blockY(), pos.blockZ() + f.normalZ())); + if (front.key().value().endsWith("_stairs") && top == isTopStair(front)) { + Direction frontFacing = facingToDirection(front.getProperty("facing")); + if (frontFacing != f && frontFacing != f.opposite()) { + if (frontFacing == rotateCW(f)) return stair.withProperty("shape", "outer_right"); + else return stair.withProperty("shape", "outer_left"); + } + } + Block back = instance.getBlock(new BlockVec(pos.blockX() - f.normalX(), pos.blockY(), pos.blockZ() - f.normalZ())); + if (back.key().value().endsWith("_stairs") && top == isTopStair(back)) { + Direction backFacing = facingToDirection(back.getProperty("facing")); + if (backFacing != f && backFacing != f.opposite()) { + if (backFacing == rotateCW(f)) return stair.withProperty("shape", "inner_right"); + else return stair.withProperty("shape", "inner_left"); + } + } + return stair.withProperty("shape", "straight"); + } + + private static boolean isTopStair(Block b) { return "top".equals(b.getProperty("half")); } + + private static Block computeConnections(Block block, String path, Instance instance, BlockVec pos) { + boolean isWall = path.endsWith("_wall") && !path.endsWith("head_wall") && !path.endsWith("_wall_sign") && !path.endsWith("_wall_banner"); + if (path.endsWith("_fence_gate")) return block; + + Block result = block; + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = instance.getBlock(np); + boolean connect = canConnectTo(nb, path, d); + String propName = d.name().toLowerCase(); + if (isWall) { + boolean tall = connect && isSolidAbove(instance, pos); + result = result.withProperty(propName, connect ? (tall ? "tall" : "low") : "none"); + } else { + result = result.withProperty(propName, connect ? "true" : "false"); + } + } + if (isWall && result.properties().containsKey("up")) { + boolean up = computeWallUp(result, instance, pos); + result = result.withProperty("up", up ? "true" : "false"); + } + return result; + } + + private static boolean isSolidAbove(Instance instance, BlockVec pos) { + Block above = instance.getBlock(new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ())); + return above.isSolid(); + } + + private static boolean computeWallUp(Block wall, Instance instance, BlockVec pos) { + boolean n = !"none".equals(wall.getProperty("north")); + boolean s = !"none".equals(wall.getProperty("south")); + boolean e = !"none".equals(wall.getProperty("east")); + boolean w = !"none".equals(wall.getProperty("west")); + boolean straight = (n && s && !e && !w) || (!n && !s && e && w); + if (!straight) return true; + return isSolidAbove(instance, pos); + } + + private static boolean canConnectTo(Block neighbor, String selfPath, Direction toward) { + if (neighbor.isAir()) return false; + String np = neighbor.key().value(); + if (np.endsWith("_fence_gate")) { + String facing = neighbor.getProperty("facing"); + if (facing != null) { + Direction f = facingToDirection(facing); + return toward != f && toward != f.opposite(); + } + return true; + } + if (selfPath.endsWith("_fence") && np.endsWith("_fence")) { + boolean selfNether = selfPath.contains("nether_brick"); + boolean nNether = np.contains("nether_brick"); + return selfNether == nNether; + } + if (selfPath.endsWith("_wall") && np.endsWith("_wall")) return true; + if ((selfPath.equals("glass_pane") || selfPath.endsWith("_stained_glass_pane") || selfPath.equals("iron_bars")) + && (np.equals("glass_pane") || np.endsWith("_stained_glass_pane") || np.equals("iron_bars"))) return true; + return neighbor.isSolid(); + } + + private static boolean isConnecting(String path) { + return path.endsWith("_fence") || (path.endsWith("_wall") && !path.endsWith("head_wall") + && !path.endsWith("_wall_sign") && !path.endsWith("_wall_banner") && !path.endsWith("_wall_torch") + && !path.endsWith("_wall_skull") && !path.endsWith("_wall_head") && !path.endsWith("_wall_hanging_sign")) + || path.equals("iron_bars") || path.equals("glass_pane") || path.endsWith("_stained_glass_pane"); + } + + private static Block updateFenceGateInWall(Block gate, Instance instance, BlockVec pos) { + if (!gate.key().value().endsWith("_fence_gate")) return gate; + String facing = gate.getProperty("facing"); + if (facing == null) return gate; + Direction f = facingToDirection(facing); + Direction left = rotateCCW(f); + Direction right = rotateCW(f); + Block l = instance.getBlock(new BlockVec(pos.blockX() + left.normalX(), pos.blockY(), pos.blockZ() + left.normalZ())); + Block r = instance.getBlock(new BlockVec(pos.blockX() + right.normalX(), pos.blockY(), pos.blockZ() + right.normalZ())); + boolean inWall = l.key().value().endsWith("_wall") || r.key().value().endsWith("_wall"); + return gate.withProperty("in_wall", inWall ? "true" : "false"); + } + + private static void updateRedstoneWire(Instance instance, BlockVec pos) { + Block wire = instance.getBlock(pos); + if (!wire.key().value().equals("redstone_wire")) return; + Block result = wire; + for (Direction d : Direction.HORIZONTAL) { + BlockVec side = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block sideBlock = instance.getBlock(side); + Block upBlock = instance.getBlock(new BlockVec(side.blockX(), side.blockY() + 1, side.blockZ())); + String state; + if (upBlock.key().value().equals("redstone_wire")) state = "up"; + else if (isRedstoneConnectable(sideBlock) + || instance.getBlock(new BlockVec(side.blockX(), side.blockY() - 1, side.blockZ())).key().value().equals("redstone_wire")) state = "side"; + else state = "none"; + result = result.withProperty(d.name().toLowerCase(), state); + } + instance.setBlock(pos, result); + } + + private static boolean isRedstoneConnectable(Block b) { + String p = b.key().value(); + return p.equals("redstone_wire") || p.equals("lever") || p.endsWith("_button") + || p.equals("repeater") || p.equals("comparator") || p.equals("redstone_torch") + || p.equals("redstone_wall_torch") || p.equals("observer") || p.equals("daylight_detector") + || p.endsWith("_pressure_plate") || p.equals("target") || p.equals("redstone_block") + || p.equals("tripwire_hook"); + } + + private static boolean isRail(String path) { + return path.equals("rail") || path.equals("powered_rail") || path.equals("detector_rail") || path.equals("activator_rail"); + } + + private static void updateRailShape(Instance instance, BlockVec pos) { + Block rail = instance.getBlock(pos); + String path = rail.key().value(); + if (!isRail(path)) return; + boolean canCurve = path.equals("rail"); + boolean[] adj = new boolean[4]; + boolean[] ascAdj = new boolean[4]; + Direction[] dirs = {Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}; + for (int i = 0; i < 4; i++) { + BlockVec np = new BlockVec(pos.blockX() + dirs[i].normalX(), pos.blockY(), pos.blockZ() + dirs[i].normalZ()); + adj[i] = isRail(instance.getBlock(np).key().value()); + BlockVec upNp = new BlockVec(np.blockX(), np.blockY() + 1, np.blockZ()); + ascAdj[i] = isRail(instance.getBlock(upNp).key().value()); + } + String shape; + if (canCurve) { + if (adj[0] && adj[1]) shape = "north_east"; + else if (adj[1] && adj[2]) shape = "south_east"; + else if (adj[2] && adj[3]) shape = "south_west"; + else if (adj[3] && adj[0]) shape = "north_west"; + else if (ascAdj[0]) shape = "ascending_north"; + else if (ascAdj[1]) shape = "ascending_east"; + else if (ascAdj[2]) shape = "ascending_south"; + else if (ascAdj[3]) shape = "ascending_west"; + else if (adj[1] || adj[3]) shape = "east_west"; + else shape = "north_south"; + } else { + if (ascAdj[0]) shape = "ascending_north"; + else if (ascAdj[1]) shape = "ascending_east"; + else if (ascAdj[2]) shape = "ascending_south"; + else if (ascAdj[3]) shape = "ascending_west"; + else if (adj[1] || adj[3]) shape = "east_west"; + else shape = "north_south"; + } + instance.setBlock(pos, rail.withProperty("shape", shape)); + } + + private static void updateScaffolding(Instance instance, BlockVec pos) { + Block s = instance.getBlock(pos); + if (!s.key().value().equals("scaffolding")) return; + Block below = instance.getBlock(new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ())); + boolean bottom; + int distance; + if (below.isSolid() && !below.key().value().equals("scaffolding")) { bottom = false; distance = 0; } + else if (below.key().value().equals("scaffolding")) { bottom = false; distance = 0; } + else { + int min = 7; + for (Direction d : Direction.HORIZONTAL) { + Block n = instance.getBlock(new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ())); + if (n.key().value().equals("scaffolding")) min = Math.min(min, parseIntOr(n.getProperty("distance"), 7) + 1); + } + bottom = true; + distance = min; + } + instance.setBlock(pos, s.withProperty("bottom", String.valueOf(bottom)).withProperty("distance", String.valueOf(distance))); + } + + private static void updateChestPair(Instance instance, BlockVec pos) { + Block chest = instance.getBlock(pos); + String path = chest.key().value(); + if (!(path.equals("chest") || path.equals("trapped_chest"))) return; + String facing = chest.getProperty("facing"); + if (facing == null) return; + Direction f = facingToDirection(facing); + Direction left = rotateCCW(f); + Direction right = rotateCW(f); + BlockVec leftPos = new BlockVec(pos.blockX() + left.normalX(), pos.blockY(), pos.blockZ() + left.normalZ()); + BlockVec rightPos = new BlockVec(pos.blockX() + right.normalX(), pos.blockY(), pos.blockZ() + right.normalZ()); + Block leftBlock = instance.getBlock(leftPos); + Block rightBlock = instance.getBlock(rightPos); + if (leftBlock.key().value().equals(path) && facing.equals(leftBlock.getProperty("facing")) + && "single".equals(leftBlock.getProperty("type"))) { + instance.setBlock(pos, chest.withProperty("type", "right")); + instance.setBlock(leftPos, leftBlock.withProperty("type", "left")); + return; + } + if (rightBlock.key().value().equals(path) && facing.equals(rightBlock.getProperty("facing")) + && "single".equals(rightBlock.getProperty("type"))) { + instance.setBlock(pos, chest.withProperty("type", "left")); + instance.setBlock(rightPos, rightBlock.withProperty("type", "right")); + } + } + + private static String yawToFacing(float yaw) { + float y = ((yaw % 360) + 360) % 360; + if (y >= 315 || y < 45) return "south"; + if (y < 135) return "west"; + if (y < 225) return "north"; + return "east"; + } + + private static String faceName(BlockFace face) { + return switch (face) { + case NORTH -> "north"; + case SOUTH -> "south"; + case EAST -> "east"; + case WEST -> "west"; + case TOP -> "up"; + case BOTTOM -> "down"; + }; + } + + private static String oppositeFacing(String f) { + return switch (f) { + case "north" -> "south"; + case "south" -> "north"; + case "east" -> "west"; + case "west" -> "east"; + case "up" -> "down"; + case "down" -> "up"; + default -> f; + }; + } + + private static Direction faceDirection(BlockFace face) { + return switch (face) { + case NORTH -> Direction.NORTH; + case SOUTH -> Direction.SOUTH; + case EAST -> Direction.EAST; + case WEST -> Direction.WEST; + case TOP -> Direction.UP; + case BOTTOM -> Direction.DOWN; + }; + } + + private static Direction facingToDirection(String f) { + if (f == null) return Direction.NORTH; + return switch (f) { + case "north" -> Direction.NORTH; + case "south" -> Direction.SOUTH; + case "east" -> Direction.EAST; + case "west" -> Direction.WEST; + case "up" -> Direction.UP; + case "down" -> Direction.DOWN; + default -> Direction.NORTH; + }; + } + + private static Direction rotateCW(Direction d) { + return switch (d) { + case NORTH -> Direction.EAST; + case EAST -> Direction.SOUTH; + case SOUTH -> Direction.WEST; + case WEST -> Direction.NORTH; + default -> d; + }; + } + + private static Direction rotateCCW(Direction d) { + return switch (d) { + case NORTH -> Direction.WEST; + case WEST -> Direction.SOUTH; + case SOUTH -> Direction.EAST; + case EAST -> Direction.NORTH; + default -> d; + }; + } + + private static String doorHinge(String facing, Point cursor, Instance instance, BlockVec pos, String path) { + Direction f = facingToDirection(facing); + Direction left = rotateCCW(f); + BlockVec leftPos = new BlockVec(pos.blockX() + left.normalX(), pos.blockY(), pos.blockZ() + left.normalZ()); + Block leftBlock = instance.getBlock(leftPos); + if (leftBlock.key().value().equals(path) && facing.equals(leftBlock.getProperty("facing"))) { + return "right"; + } + double x = cursor.x() - 0.5; + double z = cursor.z() - 0.5; + return switch (facing) { + case "north" -> x < 0 ? "right" : "left"; + case "south" -> x > 0 ? "right" : "left"; + case "west" -> z > 0 ? "right" : "left"; + case "east" -> z < 0 ? "right" : "left"; + default -> "left"; + }; + } + + public static void onInteract(PlayerBlockInteractEvent event) { + Block block = event.getBlock(); + String path = block.key().value(); + Instance instance = event.getInstance(); + BlockVec pos = event.getBlockPosition(); + + if (path.endsWith("_door")) { + String half = block.getProperty("half"); + BlockVec lowerPos = "upper".equals(half) + ? new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()) + : pos; + BlockVec upperPos = new BlockVec(lowerPos.blockX(), lowerPos.blockY() + 1, lowerPos.blockZ()); + Block lower = instance.getBlock(lowerPos); + Block upper = instance.getBlock(upperPos); + if (!lower.key().value().equals(path) || !upper.key().value().equals(path)) return; + boolean open = !"true".equals(lower.getProperty("open")); + instance.setBlock(lowerPos, lower.withProperty("open", String.valueOf(open))); + instance.setBlock(upperPos, upper.withProperty("open", String.valueOf(open))); + + String facing = lower.getProperty("facing"); + String hinge = lower.getProperty("hinge"); + if (facing != null && hinge != null) { + Direction f = facingToDirection(facing); + Direction side = "left".equals(hinge) ? rotateCW(f) : rotateCCW(f); + BlockVec partnerPos = new BlockVec(lowerPos.blockX() + side.normalX(), lowerPos.blockY(), lowerPos.blockZ() + side.normalZ()); + Block partner = instance.getBlock(partnerPos); + if (partner.key().value().equals(path) && facing.equals(partner.getProperty("facing")) + && !hinge.equals(partner.getProperty("hinge"))) { + Block partnerUpper = instance.getBlock(new BlockVec(partnerPos.blockX(), partnerPos.blockY() + 1, partnerPos.blockZ())); + instance.setBlock(partnerPos, partner.withProperty("open", String.valueOf(open))); + if (partnerUpper.key().value().equals(path)) { + instance.setBlock(new BlockVec(partnerPos.blockX(), partnerPos.blockY() + 1, partnerPos.blockZ()), + partnerUpper.withProperty("open", String.valueOf(open))); + } + } + } + event.setBlockingItemUse(true); + return; + } + + if (path.endsWith("_fence_gate")) { + boolean open = !"true".equals(block.getProperty("open")); + Block updated = block.withProperty("open", String.valueOf(open)); + if (open) { + String facing = block.getProperty("facing"); + if (facing != null) { + Direction f = facingToDirection(facing); + Direction playerDir = horizontalFacingToDirection(yawToFacing(event.getPlayer().getPosition().yaw())); + if (playerDir == f) updated = updated.withProperty("facing", oppositeFacing(facing)); + } + } + instance.setBlock(pos, updated); + event.setBlockingItemUse(true); + return; + } + + if (path.endsWith("_trapdoor")) { + boolean open = !"true".equals(block.getProperty("open")); + instance.setBlock(pos, block.withProperty("open", String.valueOf(open))); + event.setBlockingItemUse(true); + } + } + + private static Direction horizontalFacingToDirection(String f) { + return facingToDirection(f); + } + + public static void onBreak(PlayerBlockBreakEvent event) { + Instance instance = event.getInstance(); + BlockVec pos = event.getBlockPosition(); + Block broken = event.getBlock(); + String path = broken.key().value(); + + if (path.endsWith("_door")) { + String half = broken.getProperty("half"); + BlockVec other = "upper".equals(half) + ? new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()) + : new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); + instance.scheduler().scheduleNextTick(() -> { + Block ob = instance.getBlock(other); + if (ob.key().value().equals(path)) instance.setBlock(other, Block.AIR); + }); + } + + if (path.endsWith("_bed")) { + String part = broken.getProperty("part"); + String facing = broken.getProperty("facing"); + if (facing != null) { + Direction d = facingToDirection(facing); + if ("foot".equals(part)) { + BlockVec headPos = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + instance.scheduler().scheduleNextTick(() -> { + if (instance.getBlock(headPos).key().value().equals(path)) instance.setBlock(headPos, Block.AIR); + }); + } else if ("head".equals(part)) { + BlockVec footPos = new BlockVec(pos.blockX() - d.normalX(), pos.blockY(), pos.blockZ() - d.normalZ()); + instance.scheduler().scheduleNextTick(() -> { + if (instance.getBlock(footPos).key().value().equals(path)) instance.setBlock(footPos, Block.AIR); + }); + } + } + } + + if (path.equals("big_dripleaf") || path.equals("big_dripleaf_stem")) { + String half = broken.getProperty("half"); + BlockVec other = "upper".equals(half) + ? new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()) + : new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); + instance.scheduler().scheduleNextTick(() -> { + String op = instance.getBlock(other).key().value(); + if (op.equals("big_dripleaf") || op.equals("big_dripleaf_stem")) instance.setBlock(other, Block.AIR); + }); + } + + instance.scheduler().scheduleNextTick(() -> { + if (isConnecting(path)) { + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = instance.getBlock(np); + if (isConnecting(nb.key().value())) instance.setBlock(np, computeConnections(nb, nb.key().value(), instance, np)); + if (nb.key().value().endsWith("_fence_gate")) instance.setBlock(np, updateFenceGateInWall(nb, instance, np)); + } + } + + if (path.endsWith("_wall")) { + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = instance.getBlock(np); + if (nb.key().value().endsWith("_fence_gate")) instance.setBlock(np, updateFenceGateInWall(nb, instance, np)); + } + } + + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = instance.getBlock(np); + String npath = nb.key().value(); + if (npath.equals("redstone_wire")) updateRedstoneWire(instance, np); + if (isRail(npath)) updateRailShape(instance, np); + } + BlockVec above = new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); + if (instance.getBlock(above).key().value().equals("redstone_wire")) updateRedstoneWire(instance, above); + BlockVec belowRail = new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()); + if (isRail(instance.getBlock(belowRail).key().value())) updateRailShape(instance, belowRail); + + if (path.equals("scaffolding") || isAnyScaffoldingAround(instance, pos)) { + recomputeScaffoldingColumn(instance, pos); + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + if (instance.getBlock(np).key().value().equals("scaffolding")) recomputeScaffoldingColumn(instance, np); + } + } + + if (path.equals("chest") || path.equals("trapped_chest")) { + String facing = broken.getProperty("facing"); + if (facing != null) { + Direction f = facingToDirection(facing); + for (Direction d : new Direction[]{rotateCW(f), rotateCCW(f)}) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = instance.getBlock(np); + if (nb.key().value().equals(path) && facing.equals(nb.getProperty("facing"))) { + String t = nb.getProperty("type"); + if ("left".equals(t) || "right".equals(t)) instance.setBlock(np, nb.withProperty("type", "single")); + } + } + } + } + + if (isStairLike(path)) { + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = instance.getBlock(np); + if (nb.key().value().endsWith("_stairs")) { + String nf = nb.getProperty("facing"); + boolean nt = isTopStair(nb); + instance.setBlock(np, applyStairShape(nb, instance, np, nf, nt)); + } + } + } + }); + } + + private static boolean isStairLike(String path) { return path.endsWith("_stairs"); } + + private static boolean isAnyScaffoldingAround(Instance instance, BlockVec pos) { + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + if (instance.getBlock(np).key().value().equals("scaffolding")) return true; + } + BlockVec above = new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); + return instance.getBlock(above).key().value().equals("scaffolding"); + } + + private static void recomputeScaffoldingColumn(Instance instance, BlockVec start) { + int x = start.blockX(), z = start.blockZ(); + for (int y = start.blockY(); y < start.blockY() + 32; y++) { + BlockVec p = new BlockVec(x, y, z); + if (!instance.getBlock(p).key().value().equals("scaffolding")) break; + updateScaffolding(instance, p); + } + } + + private static int parseIntOr(String s, int d) { + if (s == null) return d; + try { return Integer.parseInt(s); } catch (NumberFormatException e) { return d; } + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java index 8145ad8..03c6db2 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java @@ -11,8 +11,10 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; import net.minestom.server.event.player.PlayerBlockBreakEvent; +import net.minestom.server.event.player.PlayerBlockInteractEvent; import net.minestom.server.event.player.PlayerBlockPlaceEvent; import net.minestom.server.event.player.PlayerUseItemEvent; +import net.minestom.server.event.player.PlayerUseItemOnBlockEvent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.timer.TaskSchedule; @@ -61,6 +63,10 @@ public class BuildBattle extends StatelessGame { this.seconds = seconds; this.setGenerator(new BuildBattleChunkgenerator(height)); this.eventNode().addListener(PlayerUseItemEvent.class, this::onRatingItemUse); + this.eventNode().addListener(PlayerUseItemOnBlockEvent.class, e -> FluidFlowHelper.onBucketUse(e, p -> this.isInArea(p, e.getPlayer()))); + this.eventNode().addListener(PlayerBlockInteractEvent.class, e -> { + if (this.isInArea(e.getBlockPosition(), e.getPlayer())) BlockPlacementHelper.onInteract(e); + }); } @Override @@ -76,6 +82,21 @@ public class BuildBattle extends StatelessGame { this.getPlayers().forEach(player -> player.setGameMode(GameMode.CREATIVE)); this.scheduler().scheduleTask(this::endBuildPhase, TaskSchedule.seconds(this.seconds), TaskSchedule.stop()); + this.scheduleCountdown(); + } + + private void scheduleCountdown() { + int[] marks = {30, 10, 5, 4, 3, 2, 1}; + for (int m : marks) { + if (this.seconds <= m) continue; + int remaining = m; + this.scheduler().scheduleTask(() -> { + NamedTextColor color = remaining <= 5 ? NamedTextColor.RED : (remaining <= 10 ? NamedTextColor.GOLD : NamedTextColor.YELLOW); + this.sendMessage(Component.text("Noch ", NamedTextColor.GRAY) + .append(Component.text(remaining, color)) + .append(Component.text(" Sekunde" + (remaining == 1 ? "" : "n") + " Bauzeit!", NamedTextColor.GRAY))); + }, TaskSchedule.seconds(this.seconds - m), TaskSchedule.stop()); + } } private void endBuildPhase() { @@ -109,12 +130,34 @@ public class BuildBattle extends StatelessGame { @Override protected void onBlockBreak(@NotNull PlayerBlockBreakEvent event) { - event.setCancelled(!this.isInArea(event.getBlockPosition(), event.getPlayer())); + if (!this.isInArea(event.getBlockPosition(), event.getPlayer())) { + event.setCancelled(true); + return; + } + BlockPlacementHelper.onBreak(event); + FluidFlowHelper.onBreak(event); } @Override protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent event) { - event.setCancelled(!this.isInArea(event.getBlockPosition(), event.getPlayer())); + if (!this.isInArea(event.getBlockPosition(), event.getPlayer())) { + event.setCancelled(true); + return; + } + BlockPlacementHelper.apply(event); + FluidFlowHelper.onPlace(event); + } + + private Pos safeSpawn(Player owner) { + Pos center = this.spawnPositions.get(owner); + int topY = center.blockY(); + for (int y = 300; y >= center.blockY(); y--) { + if (!this.getBlock(center.blockX(), y, center.blockZ()).isAir()) { + topY = y; + break; + } + } + return new Pos(center.x(), topY + 3, center.z()).withView(center.yaw(), center.pitch()); } private void rating() { @@ -136,7 +179,7 @@ public class BuildBattle extends StatelessGame { this.currentOwner = owner; this.currentVotes.clear(); - Pos plot = this.spawnPositions.get(owner).add(0, 1.5, 0); + Pos plot = this.safeSpawn(owner); this.sendMessage(Component.text("Bewerte das Grundstück von " + owner.getUsername() + "!")); this.getPlayers().forEach(p -> { p.teleport(plot); @@ -176,11 +219,9 @@ public class BuildBattle extends StatelessGame { private boolean isInArea(Point block, Player player) { Pos center = this.spawnPositions.get(player); - double dx = block.x() - center.x(); - double dy = block.y() - center.y(); - double dz = block.z() - center.z(); - return dx >= -plotHalf && dx < plotHalf - && dy >= 1 && dy <= 300 - && dz >= -plotHalf && dz < plotHalf; + if (center == null) return false; + Pos min = new Pos(center.x() - plotHalf, center.y() + 1, center.z() - plotHalf); + Pos max = new Pos(center.x() + plotHalf - 1, 300, center.z() + plotHalf - 1); + return eu.mhsl.minenet.minigames.util.Position.isInArea(block, min, max); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/FluidFlowHelper.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/FluidFlowHelper.java new file mode 100644 index 0000000..598cbc6 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/FluidFlowHelper.java @@ -0,0 +1,268 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle; + +import net.minestom.server.coordinate.BlockVec; +import net.minestom.server.coordinate.Point; +import net.minestom.server.entity.Player; +import net.minestom.server.event.player.PlayerBlockBreakEvent; +import net.minestom.server.event.player.PlayerBlockPlaceEvent; +import net.minestom.server.event.player.PlayerUseItemOnBlockEvent; +import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; +import net.minestom.server.item.Material; +import net.minestom.server.timer.TaskSchedule; +import net.minestom.server.utils.Direction; + +import java.util.ArrayDeque; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Predicate; + +public final class FluidFlowHelper { + private FluidFlowHelper() {} + + private static final int WATER_TICK = 5; + private static final int LAVA_TICK = 30; + private static final int WATER_RANGE = 7; + private static final int LAVA_RANGE = 3; + private static final int FALLING = 8; + + public static void onBucketUse(PlayerUseItemOnBlockEvent event, Predicate inArea) { + Material m = event.getItemStack().material(); + Instance inst = event.getPlayer().getInstance(); + if (inst == null) return; + Point hit = event.getPosition(); + var face = event.getBlockFace(); + BlockVec placePos = new BlockVec( + hit.blockX() + face.toDirection().normalX(), + hit.blockY() + face.toDirection().normalY(), + hit.blockZ() + face.toDirection().normalZ() + ); + if (!inArea.test(placePos)) return; + + if (m == Material.WATER_BUCKET) { + inst.setBlock(placePos, Block.WATER.withProperty("level", "0")); + scheduleFlow(inst, placePos, true); + } else if (m == Material.LAVA_BUCKET) { + inst.setBlock(placePos, Block.LAVA.withProperty("level", "0")); + scheduleFlow(inst, placePos, false); + } else if (m == Material.BUCKET) { + Block existing = inst.getBlock(placePos); + if (isWater(existing) || isLava(existing)) inst.setBlock(placePos, Block.AIR); + } + } + + public static void onPlace(PlayerBlockPlaceEvent event) { + Block b = event.getBlock(); + if (isWater(b) || isLava(b)) { + Instance inst = event.getInstance(); + BlockVec pos = event.getBlockPosition(); + scheduleFlow(inst, pos, isWater(b)); + } + triggerNeighbors(event.getInstance(), event.getBlockPosition()); + } + + public static void onBreak(PlayerBlockBreakEvent event) { + triggerNeighbors(event.getInstance(), event.getBlockPosition()); + } + + private static void triggerNeighbors(Instance inst, BlockVec pos) { + for (Direction d : Direction.values()) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY() + d.normalY(), pos.blockZ() + d.normalZ()); + Block nb = inst.getBlock(np); + if (isWater(nb) || isLava(nb)) scheduleFlow(inst, np, isWater(nb)); + } + } + + private static void scheduleFlow(Instance inst, BlockVec pos, boolean water) { + int delay = water ? WATER_TICK : LAVA_TICK; + inst.scheduler().buildTask(() -> step(inst, pos, water)).delay(TaskSchedule.tick(delay)).schedule(); + } + + private static void step(Instance inst, BlockVec pos, boolean water) { + Block self = inst.getBlock(pos); + if (water ? !isWater(self) : !isLava(self)) return; + + int level = parseLevel(self); + boolean source = level == 0; + boolean falling = level >= FALLING; + int flowLevel = source ? 1 : (falling ? 1 : level + 1); + int maxRange = water ? WATER_RANGE : LAVA_RANGE; + + if (!source && !falling) { + int newLevel = computeIncomingLevel(inst, pos, water, maxRange); + if (newLevel == -1) { + inst.setBlock(pos, Block.AIR); + triggerNeighbors(inst, pos); + return; + } + if (newLevel != level) { + inst.setBlock(pos, (water ? Block.WATER : Block.LAVA).withProperty("level", String.valueOf(newLevel))); + level = newLevel; + flowLevel = level + 1; + } + } + + if (water && !source && countAdjacentSources(inst, pos, true) >= 2 + && hasSolidBelow(inst, pos)) { + inst.setBlock(pos, Block.WATER.withProperty("level", "0")); + scheduleFlow(inst, pos, true); + triggerNeighbors(inst, pos); + return; + } + + BlockVec below = new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()); + Block belowBlock = inst.getBlock(below); + if (isReplaceable(belowBlock) || (water ? isWater(belowBlock) : isLava(belowBlock))) { + if (handleFluidCollision(inst, below, water)) { + triggerNeighbors(inst, below); + return; + } + Block target = (water ? Block.WATER : Block.LAVA).withProperty("level", String.valueOf(FALLING)); + if (!belowBlock.compare(target) || !target.getProperty("level").equals(belowBlock.getProperty("level"))) { + if (!(isWater(belowBlock) && parseLevel(belowBlock) == 0) + && !(isLava(belowBlock) && parseLevel(belowBlock) == 0)) { + inst.setBlock(below, target); + scheduleFlow(inst, below, water); + triggerNeighbors(inst, below); + } + } + if (!hasSolidBelow(inst, pos) && !source) return; + } + + if (flowLevel > maxRange) return; + + Set targets = findFlowTargets(inst, pos, water, maxRange - (source ? 0 : level)); + for (Direction d : Direction.HORIZONTAL) { + if (!targets.contains(d)) continue; + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = inst.getBlock(np); + if (handleFluidCollision(inst, np, water)) continue; + if (!isReplaceable(nb) && !(water ? isWater(nb) : isLava(nb))) continue; + int existingLevel = (water ? isWater(nb) : isLava(nb)) ? parseLevel(nb) : Integer.MAX_VALUE; + if (existingLevel == 0) continue; + if (flowLevel < existingLevel) { + inst.setBlock(np, (water ? Block.WATER : Block.LAVA).withProperty("level", String.valueOf(flowLevel))); + scheduleFlow(inst, np, water); + triggerNeighbors(inst, np); + } + } + } + + private static int computeIncomingLevel(Instance inst, BlockVec pos, boolean water, int maxRange) { + int min = Integer.MAX_VALUE; + BlockVec above = new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); + Block ab = inst.getBlock(above); + if ((water ? isWater(ab) : isLava(ab))) return FALLING; + for (Direction d : Direction.HORIZONTAL) { + BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); + Block nb = inst.getBlock(np); + if (water ? isWater(nb) : isLava(nb)) { + int nl = parseLevel(nb); + if (nl >= FALLING) nl = 0; + if (nl < min) min = nl; + } + } + if (min == Integer.MAX_VALUE) return -1; + int result = min + 1; + if (result > maxRange) return -1; + return result; + } + + private static Set findFlowTargets(Instance inst, BlockVec pos, boolean water, int remaining) { + Set result = new HashSet<>(); + if (remaining <= 0) return result; + int bestDist = Integer.MAX_VALUE; + int[] dist = new int[4]; + Direction[] dirs = {Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}; + for (int i = 0; i < 4; i++) { + BlockVec np = new BlockVec(pos.blockX() + dirs[i].normalX(), pos.blockY(), pos.blockZ() + dirs[i].normalZ()); + Block nb = inst.getBlock(np); + if (!isReplaceable(nb) && !(water ? isWater(nb) : isLava(nb))) { dist[i] = Integer.MAX_VALUE; continue; } + dist[i] = bfsDownhill(inst, np, water, remaining); + if (dist[i] < bestDist) bestDist = dist[i]; + } + if (bestDist == Integer.MAX_VALUE) { + for (int i = 0; i < 4; i++) { + if (dist[i] < Integer.MAX_VALUE) result.add(dirs[i]); + } + } else { + for (int i = 0; i < 4; i++) { + if (dist[i] == bestDist) result.add(dirs[i]); + } + } + return result; + } + + private static int bfsDownhill(Instance inst, BlockVec start, boolean water, int remaining) { + ArrayDeque queue = new ArrayDeque<>(); + Set visited = new HashSet<>(); + queue.add(new int[]{start.blockX(), start.blockY(), start.blockZ(), 0}); + visited.add(key(start.blockX(), start.blockY(), start.blockZ())); + while (!queue.isEmpty()) { + int[] c = queue.poll(); + BlockVec cp = new BlockVec(c[0], c[1], c[2]); + Block below = inst.getBlock(new BlockVec(c[0], c[1] - 1, c[2])); + if (isReplaceable(below) && !(water ? isWater(below) : isLava(below))) return c[3]; + if (c[3] >= remaining) continue; + for (Direction d : Direction.HORIZONTAL) { + int nx = c[0] + d.normalX(), nz = c[2] + d.normalZ(); + long k = key(nx, c[1], nz); + if (visited.contains(k)) continue; + Block nb = inst.getBlock(new BlockVec(nx, c[1], nz)); + if (!isReplaceable(nb) && !(water ? isWater(nb) : isLava(nb))) continue; + visited.add(k); + queue.add(new int[]{nx, c[1], nz, c[3] + 1}); + } + } + return Integer.MAX_VALUE; + } + + private static long key(int x, int y, int z) { + return ((long) x & 0x3FFFFFFL) | (((long) z & 0x3FFFFFFL) << 26) | (((long) y & 0xFFFL) << 52); + } + + private static int countAdjacentSources(Instance inst, BlockVec pos, boolean water) { + int c = 0; + for (Direction d : Direction.HORIZONTAL) { + Block nb = inst.getBlock(new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ())); + if ((water ? isWater(nb) : isLava(nb)) && parseLevel(nb) == 0) c++; + } + return c; + } + + private static boolean hasSolidBelow(Instance inst, BlockVec pos) { + Block below = inst.getBlock(new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ())); + return below.isSolid(); + } + + private static boolean handleFluidCollision(Instance inst, BlockVec pos, boolean incomingIsWater) { + Block target = inst.getBlock(pos); + if (incomingIsWater && isLava(target)) { + boolean lavaSource = parseLevel(target) == 0; + inst.setBlock(pos, lavaSource ? Block.OBSIDIAN : Block.COBBLESTONE); + return true; + } + if (!incomingIsWater && isWater(target)) { + inst.setBlock(pos, Block.STONE); + return true; + } + return false; + } + + private static boolean isReplaceable(Block b) { + if (b.isAir()) return true; + String p = b.key().value(); + return p.equals("short_grass") || p.equals("tall_grass") || p.equals("fern") || p.equals("large_fern") + || p.equals("dead_bush") || p.equals("seagrass") || p.equals("tall_seagrass") || p.equals("vine") + || p.equals("snow") || p.equals("fire") || p.equals("soul_fire"); + } + + private static boolean isWater(Block b) { return b.compare(Block.WATER); } + private static boolean isLava(Block b) { return b.compare(Block.LAVA); } + + private static int parseLevel(Block b) { + String s = b.getProperty("level"); + if (s == null) return 0; + try { return Integer.parseInt(s); } catch (NumberFormatException e) { return 0; } + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/util/Position.java b/src/main/java/eu/mhsl/minenet/minigames/util/Position.java index bb5dc2e..e9d0d50 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/util/Position.java +++ b/src/main/java/eu/mhsl/minenet/minigames/util/Position.java @@ -44,4 +44,17 @@ public class Position { public static boolean hasPositionChanged(Pos oldPos, Pos newPos) { return !oldPos.withView(0, 0).equals(newPos.withView(0, 0)); } + + public static boolean isInArea(Point point, Point pos1, Point pos2) { + double minX = Math.min(pos1.x(), pos2.x()); + double maxX = Math.max(pos1.x(), pos2.x()); + double minY = Math.min(pos1.y(), pos2.y()); + double maxY = Math.max(pos1.y(), pos2.y()); + double minZ = Math.min(pos1.z(), pos2.z()); + double maxZ = Math.max(pos1.z(), pos2.z()); + + return point.x() >= minX && point.x() <= maxX + && point.y() >= minY && point.y() <= maxY + && point.z() >= minZ && point.z() <= maxZ; + } } From 7424d6b929580395dc923204111fd46d64904dc2 Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Oct 2026 00:18:01 +0200 Subject: [PATCH 05/10] fixed placement issues in BuildBattle and added isInArea methode to Position.java --- .../game/stateless/types/buildBattle/FluidFlowHelper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/FluidFlowHelper.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/FluidFlowHelper.java index 598cbc6..2e80a38 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/FluidFlowHelper.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/FluidFlowHelper.java @@ -2,7 +2,6 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle; import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; -import net.minestom.server.entity.Player; import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.minestom.server.event.player.PlayerBlockPlaceEvent; import net.minestom.server.event.player.PlayerUseItemOnBlockEvent; From 89b81a3288526e0a921dc594daa073a0d2f08072 Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Oct 2026 16:35:48 +0100 Subject: [PATCH 06/10] fixed spawning issues in tetris --- .../minigames/instance/game/stateless/types/tetris/Tetris.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 0f3336f..b293b61 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -147,10 +147,10 @@ class Tetris extends StatelessGame { TetrisGame tetrisGame = this.tetrisGames.get(p); - p.teleport(tetrisGame.getPlayerSpawnPosition()); tetrisGame.sidebar.addViewer(p); MinecraftServer.getSchedulerManager().scheduleTask(() -> { + p.teleport(tetrisGame.getPlayerSpawnPosition()); Entity ghostBlock = new Entity(EntityType.BLOCK_DISPLAY); ((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(Block.AIR); ghostBlock.setNoGravity(true); @@ -159,7 +159,6 @@ class Tetris extends StatelessGame { return TaskSchedule.stop(); }, TaskSchedule.nextTick()); - return super.onPlayerJoin(p); } From f23495ecdd3300df525a3807dc16dde4a49d26ca Mon Sep 17 00:00:00 2001 From: jannis Date: Sun, 25 Oct 2026 17:01:20 +0100 Subject: [PATCH 07/10] fixed knockback issue in high ground --- .../stateless/types/highGround/HighGround.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/highGround/HighGround.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/highGround/HighGround.java index 193ec36..712f8c4 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/highGround/HighGround.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/highGround/HighGround.java @@ -51,15 +51,18 @@ class HighGround extends StatelessGame { this.eventNode().addListener( EntityKnockbackEvent.class, - entityKnockbackEvent -> entityKnockbackEvent.setSettings( + entityKnockbackEvent -> { + if(entityKnockbackEvent.getEntity().getVelocity().y() > 4) { entityKnockbackEvent.setCancelled(true); return; } + entityKnockbackEvent.setSettings( KnockbackSettings.builder() .horizontal(1.1) - .vertical(KnockbackSettings.DEFAULT.vertical()) - .verticalLimit(KnockbackSettings.DEFAULT.verticalLimit()) - .extraHorizontal(KnockbackSettings.DEFAULT.extraHorizontal()) - .extraVertical(KnockbackSettings.DEFAULT.extraVertical()) + .vertical(0) + .verticalLimit(0) + .extraHorizontal(0.5) + .extraVertical(0) .build() - ) + ); + } ); this.eventNode().addListener(InstanceTickEvent.class, instanceTickEvent -> { From 331efa9ffd9716672a956eabf0cc57071bc7556a Mon Sep 17 00:00:00 2001 From: jannis Date: Wed, 28 Oct 2026 21:56:28 +0100 Subject: [PATCH 08/10] replaced BlockPlacementHelper in BuildBattle with blocks-and-stuff placement rules --- build.gradle | 4 + .../buildBattle/BlockPlacementHelper.java | 896 ------------------ .../types/buildBattle/BuildBattle.java | 5 +- .../buildBattle/BuildBattleBlockRules.java | 85 ++ 4 files changed, 91 insertions(+), 899 deletions(-) delete mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattleBlockRules.java diff --git a/build.gradle b/build.gradle index a216060..9a890d3 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ version '1.0-SNAPSHOT' repositories { mavenCentral() + maven { url = 'https://mvn.everbuild.org/public' } } java { @@ -38,6 +39,9 @@ dependencies { //PvP implementation 'io.github.togar2:MinestomPvP:2026.05.30-26.1.1' + + //Block placement + implementation 'org.everbuild.blocksandstuff:blocksandstuff-blocks:1.10.2-SNAPSHOT' } tasks { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java deleted file mode 100644 index 8d661a3..0000000 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BlockPlacementHelper.java +++ /dev/null @@ -1,896 +0,0 @@ -package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle; - -import net.minestom.server.coordinate.BlockVec; -import net.minestom.server.coordinate.Point; -import net.minestom.server.entity.Player; -import net.minestom.server.event.player.PlayerBlockBreakEvent; -import net.minestom.server.event.player.PlayerBlockInteractEvent; -import net.minestom.server.event.player.PlayerBlockPlaceEvent; -import net.minestom.server.instance.Instance; -import net.minestom.server.instance.block.Block; -import net.minestom.server.instance.block.BlockFace; -import net.minestom.server.utils.Direction; - -import java.util.Map; -import java.util.Set; - -public final class BlockPlacementHelper { - private BlockPlacementHelper() {} - - private static final Set SIX_DIR = Set.of( - "observer", "dispenser", "dropper", "piston", "sticky_piston", - "amethyst_cluster", "small_amethyst_bud", "medium_amethyst_bud", "large_amethyst_bud", - "end_rod", "lightning_rod", "shulker_box" - ); - - public static void apply(PlayerBlockPlaceEvent event) { - Block block = event.getBlock(); - BlockFace face = event.getBlockFace(); - BlockVec pos = event.getBlockPosition(); - Point cursor = event.getCursorPosition(); - Player player = event.getPlayer(); - Instance instance = event.getInstance(); - - String path = block.key().value(); - - Block existing = instance.getBlock(pos); - if ((path.endsWith("_candle") || path.equals("candle")) && existing.compare(block)) { - int n = parseIntOr(existing.getProperty("candles"), 1); - event.setBlock(n < 4 ? existing.withProperty("candles", String.valueOf(n + 1)) : existing); - return; - } - if (path.equals("snow") && existing.compare(block)) { - int n = parseIntOr(existing.getProperty("layers"), 1); - event.setBlock(n < 8 ? existing.withProperty("layers", String.valueOf(n + 1)) : existing); - return; - } - if (path.equals("sea_pickle") && existing.compare(block)) { - int n = parseIntOr(existing.getProperty("pickles"), 1); - event.setBlock(n < 4 ? existing.withProperty("pickles", String.valueOf(n + 1)) : existing); - return; - } - if (path.equals("turtle_egg") && existing.compare(block)) { - int n = parseIntOr(existing.getProperty("eggs"), 1); - event.setBlock(n < 4 ? existing.withProperty("eggs", String.valueOf(n + 1)) : existing); - return; - } - - Block oriented = orient(block, path, face, cursor, player, instance, pos); - if (oriented != block) event.setBlock(oriented); - - Block finalOriented = oriented; - String finalPath = finalOriented.key().value(); - - if (path.endsWith("_door")) { - Block lower = event.getBlock(); - String facing = lower.getProperty("facing"); - String hinge = lower.getProperty("hinge"); - Block upper = lower.withProperty("half", "upper").withProperty("facing", facing).withProperty("hinge", hinge); - instance.scheduler().scheduleNextTick(() -> instance.setBlock(pos.add(0, 1, 0), upper)); - } - - if (path.endsWith("_bed")) { - String facing = finalOriented.getProperty("facing"); - Direction d = facingToDirection(facing); - Block head = finalOriented.withProperty("part", "head"); - BlockVec headPos = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - instance.scheduler().scheduleNextTick(() -> instance.setBlock(headPos, head)); - } - - if (path.equals("big_dripleaf")) { - Block upper = finalOriented; - Block lower = Block.BIG_DRIPLEAF_STEM.withProperty("facing", finalOriented.getProperty("facing")); - instance.scheduler().scheduleNextTick(() -> instance.setBlock(pos.add(0, 1, 0), upper.withProperty("half", "upper"))); - } - - if (isConnecting(path)) { - instance.scheduler().scheduleNextTick(() -> { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (isConnecting(nb.key().value())) instance.setBlock(np, computeConnections(nb, nb.key().value(), instance, np)); - } - Block self = instance.getBlock(pos); - if (isConnecting(self.key().value())) instance.setBlock(pos, computeConnections(self, self.key().value(), instance, pos)); - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (nb.key().value().endsWith("_fence_gate")) { - instance.setBlock(np, updateFenceGateInWall(nb, instance, np)); - } - } - }); - } - - if (path.endsWith("_fence_gate")) { - instance.scheduler().scheduleNextTick(() -> instance.setBlock(pos, updateFenceGateInWall(instance.getBlock(pos), instance, pos))); - } - - if (path.equals("redstone_wire")) { - instance.scheduler().scheduleNextTick(() -> { - updateRedstoneWire(instance, pos); - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - if (instance.getBlock(np).key().value().equals("redstone_wire")) updateRedstoneWire(instance, np); - } - }); - } - - if (isRail(path)) { - instance.scheduler().scheduleNextTick(() -> updateRailShape(instance, pos)); - } - - if (path.equals("scaffolding")) { - instance.scheduler().scheduleNextTick(() -> updateScaffolding(instance, pos)); - } - - if (finalPath.equals("chest") || finalPath.equals("trapped_chest")) { - instance.scheduler().scheduleNextTick(() -> updateChestPair(instance, pos)); - } - } - - private static Block orient(Block block, String path, BlockFace face, Point cursor, Player player, - Instance instance, BlockVec pos) { - Map props = block.properties(); - Block result = block; - - if (props.containsKey("axis")) { - result = result.withProperty("axis", switch (face) { - case TOP, BOTTOM -> "y"; - case NORTH, SOUTH -> "z"; - case EAST, WEST -> "x"; - }); - } - - if (props.containsKey("type") && path.endsWith("_slab")) { - Block existing = instance.getBlock(pos); - if (existing.compare(block)) { - result = result.withProperty("type", "double"); - } else { - boolean top = face == BlockFace.BOTTOM || (face != BlockFace.TOP && cursor.y() > 0.5); - result = result.withProperty("type", top ? "top" : "bottom"); - } - } - - if (path.endsWith("_stairs")) { - String facing = yawToFacing(player.getPosition().yaw()); - boolean top = face == BlockFace.BOTTOM || (face != BlockFace.TOP && cursor.y() > 0.5); - result = result.withProperty("facing", facing).withProperty("half", top ? "top" : "bottom"); - result = applyStairShape(result, instance, pos, facing, top); - } - - if (path.endsWith("_trapdoor")) { - String facing; - boolean top; - if (face == BlockFace.TOP) { top = false; facing = yawToFacing(player.getPosition().yaw() + 180); } - else if (face == BlockFace.BOTTOM) { top = true; facing = yawToFacing(player.getPosition().yaw() + 180); } - else { top = cursor.y() > 0.5; facing = oppositeFacing(faceName(face)); } - result = result.withProperty("facing", facing).withProperty("half", top ? "top" : "bottom") - .withProperty("open", "false").withProperty("powered", "false"); - } - - if (path.endsWith("_door")) { - String facing = yawToFacing(player.getPosition().yaw()); - String hinge = doorHinge(facing, cursor, instance, pos, path); - result = result.withProperty("facing", facing) - .withProperty("half", "lower") - .withProperty("hinge", hinge) - .withProperty("open", "false") - .withProperty("powered", "false"); - } - - if (path.endsWith("_fence_gate")) { - String facing = yawToFacing(player.getPosition().yaw()); - result = result.withProperty("facing", facing).withProperty("open", "false") - .withProperty("powered", "false").withProperty("in_wall", "false"); - } - - if (path.endsWith("_bed")) { - String facing = yawToFacing(player.getPosition().yaw()); - result = result.withProperty("facing", facing).withProperty("part", "foot").withProperty("occupied", "false"); - } - - if (path.endsWith("_button") || path.equals("lever") || path.equals("grindstone")) { - String attachFace; String facing; - if (face == BlockFace.TOP) { attachFace = "floor"; facing = yawToFacing(player.getPosition().yaw()); } - else if (face == BlockFace.BOTTOM) { attachFace = "ceiling"; facing = yawToFacing(player.getPosition().yaw()); } - else { attachFace = "wall"; facing = oppositeFacing(faceName(face)); } - result = result.withProperty("face", attachFace).withProperty("facing", facing); - } - - if (path.equals("bell")) { - String attachment; String facing; - if (face == BlockFace.TOP) { attachment = "floor"; facing = yawToFacing(player.getPosition().yaw()); } - else if (face == BlockFace.BOTTOM) { attachment = "ceiling"; facing = yawToFacing(player.getPosition().yaw()); } - else { - attachment = "single_wall"; - facing = oppositeFacing(faceName(face)); - } - result = result.withProperty("attachment", attachment).withProperty("facing", facing); - } - - if (path.equals("lantern") || path.equals("soul_lantern")) { - result = result.withProperty("hanging", face == BlockFace.BOTTOM ? "true" : "false"); - } - - if (path.equals("tripwire_hook")) { - String facing = face != BlockFace.TOP && face != BlockFace.BOTTOM - ? oppositeFacing(faceName(face)) - : yawToFacing(player.getPosition().yaw()); - result = result.withProperty("facing", facing).withProperty("attached", "false").withProperty("powered", "false"); - } - - if (path.equals("hopper")) { - String facing = face == BlockFace.TOP ? "down" : (face == BlockFace.BOTTOM ? "down" : oppositeFacing(faceName(face))); - result = result.withProperty("facing", facing).withProperty("enabled", "true"); - } - - if (path.equals("campfire") || path.equals("soul_campfire")) { - Block below = instance.getBlock(new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ())); - String signalFire = below.key().value().equals("hay_block") ? "true" : "false"; - result = result.withProperty("facing", yawToFacing(player.getPosition().yaw())) - .withProperty("lit", "true").withProperty("signal_fire", signalFire); - } - - if (path.equals("pointed_dripstone")) { - String dir = face == BlockFace.BOTTOM ? "down" : "up"; - result = result.withProperty("vertical_direction", dir).withProperty("thickness", "tip"); - } - - if (path.equals("chorus_flower")) { - result = result.withProperty("age", "0"); - } - - if (path.equals("end_portal_frame") || path.equals("respawn_anchor")) { - if (props.containsKey("facing")) { - result = result.withProperty("facing", yawToFacing(player.getPosition().yaw())); - } - if (props.containsKey("eye")) result = result.withProperty("eye", "false"); - } - - if ((path.equals("torch") || path.equals("soul_torch") || path.equals("redstone_torch") || path.equals("copper_torch")) - && face != BlockFace.TOP && face != BlockFace.BOTTOM) { - Block wall = switch (path) { - case "torch" -> Block.WALL_TORCH; - case "soul_torch" -> Block.SOUL_WALL_TORCH; - case "redstone_torch" -> Block.REDSTONE_WALL_TORCH; - case "copper_torch" -> Block.COPPER_WALL_TORCH; - default -> null; - }; - if (wall != null) result = wall.withProperty("facing", oppositeFacing(faceName(face))); - } - - if (path.endsWith("_skull") || path.endsWith("_head")) { - if (face != BlockFace.TOP && face != BlockFace.BOTTOM) { - String wallName = path.endsWith("_skull") ? path.replace("_skull", "_wall_skull") : path.replace("_head", "_wall_head"); - Block wall = Block.fromKey("minecraft:" + wallName); - if (wall != null) result = wall.withProperty("facing", oppositeFacing(faceName(face))); - } else if (face == BlockFace.TOP && result.properties().containsKey("rotation")) { - int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; - result = result.withProperty("rotation", String.valueOf(rot)); - } - } - - if (path.endsWith("_sign") && !path.endsWith("_wall_sign") && !path.contains("hanging") - && face != BlockFace.TOP && face != BlockFace.BOTTOM) { - Block wallSign = Block.fromKey("minecraft:" + path.replace("_sign", "_wall_sign")); - if (wallSign != null) result = wallSign.withProperty("facing", oppositeFacing(faceName(face))); - } else if (path.endsWith("_sign") && !path.endsWith("_wall_sign") && !path.contains("hanging") - && face == BlockFace.TOP) { - int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; - if (result.properties().containsKey("rotation")) result = result.withProperty("rotation", String.valueOf(rot)); - } - - if (path.endsWith("_hanging_sign") && !path.contains("_wall_") - && face != BlockFace.TOP && face != BlockFace.BOTTOM) { - Block wallHang = Block.fromKey("minecraft:" + path.replace("_hanging_sign", "_wall_hanging_sign")); - if (wallHang != null) result = wallHang.withProperty("facing", oppositeFacing(faceName(face))); - } else if (path.endsWith("_hanging_sign") && !path.contains("_wall_")) { - int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; - if (result.properties().containsKey("rotation")) result = result.withProperty("rotation", String.valueOf(rot)); - if (result.properties().containsKey("attached")) result = result.withProperty("attached", face == BlockFace.BOTTOM ? "true" : "false"); - } - - if (isBanner(path)) { - if (face != BlockFace.TOP && face != BlockFace.BOTTOM) { - Block wallBanner = Block.fromKey("minecraft:" + path.replace("_banner", "_wall_banner")); - if (wallBanner != null) result = wallBanner.withProperty("facing", oppositeFacing(faceName(face))); - } else if (face == BlockFace.TOP) { - int rot = (int) Math.floor(((player.getPosition().yaw() + 180.0) * 16.0 / 360.0) + 0.5) & 15; - if (result.properties().containsKey("rotation")) result = result.withProperty("rotation", String.valueOf(rot)); - } - } - - if (path.equals("vine")) { - Block existing = instance.getBlock(pos); - Block base = existing.compare(block) ? existing : result.withProperty("up", "false") - .withProperty("north", "false").withProperty("south", "false") - .withProperty("east", "false").withProperty("west", "false"); - String side = switch (face) { - case BOTTOM -> "up"; - case NORTH -> "south"; - case SOUTH -> "north"; - case EAST -> "west"; - case WEST -> "east"; - default -> null; - }; - result = side != null ? base.withProperty(side, "true") : base; - } - - if (path.equals("glow_lichen") || path.equals("sculk_vein") || path.equals("resin_clump")) { - Block existing = instance.getBlock(pos); - Block base = existing.compare(block) ? existing : result - .withProperty("up", "false").withProperty("down", "false") - .withProperty("north", "false").withProperty("south", "false") - .withProperty("east", "false").withProperty("west", "false"); - String side = switch (face) { - case TOP -> "down"; - case BOTTOM -> "up"; - case NORTH -> "south"; - case SOUTH -> "north"; - case EAST -> "west"; - case WEST -> "east"; - }; - result = base.withProperty(side, "true"); - } - - if (path.equals("red_mushroom_block") || path.equals("brown_mushroom_block") || path.equals("mushroom_stem")) { - result = result.withProperty("up", "true").withProperty("down", "true") - .withProperty("north", "true").withProperty("south", "true") - .withProperty("east", "true").withProperty("west", "true"); - String hiddenFace = faceName(face); - if (result.properties().containsKey(hiddenFace)) result = result.withProperty(hiddenFace, "false"); - } - - if (props.containsKey("facing") && !path.endsWith("_stairs") && !path.endsWith("_door") - && !path.endsWith("_trapdoor") && !path.endsWith("_fence_gate") && !path.endsWith("_button") - && !path.equals("lever") && !path.equals("grindstone") && !path.equals("bell") - && !path.equals("hopper") && !path.equals("campfire") && !path.equals("soul_campfire") - && !path.equals("tripwire_hook") - && !path.endsWith("wall_torch") && !path.endsWith("_bed") && !path.endsWith("_sign") - && !path.endsWith("_hanging_sign") && !path.endsWith("_banner") && !path.endsWith("_wall_banner") - && !path.endsWith("_skull") && !path.endsWith("_head") - && !path.equals("end_portal_frame") && !path.equals("respawn_anchor")) { - Direction fdir = faceDirection(face); - String facing; - if (fdir != null && SIX_DIR.contains(path)) { - facing = fdir.opposite().name().toLowerCase(); - } else if (path.equals("repeater") || path.equals("comparator")) { - facing = oppositeFacing(yawToFacing(player.getPosition().yaw())); - } else { - facing = yawToFacing(player.getPosition().yaw()); - } - try { result = result.withProperty("facing", facing); } catch (Exception ignored) {} - } - - if (isConnecting(path)) result = computeConnections(result, path, instance, pos); - - if (props.containsKey("waterlogged") && Block.WATER.compare(instance.getBlock(pos))) { - try { result = result.withProperty("waterlogged", "true"); } catch (Exception ignored) {} - } - - return result; - } - - private static boolean isBanner(String path) { - return path.endsWith("_banner") && !path.endsWith("_wall_banner"); - } - - private static Block applyStairShape(Block stair, Instance instance, BlockVec pos, String facing, boolean top) { - Direction f = facingToDirection(facing); - Block front = instance.getBlock(new BlockVec(pos.blockX() + f.normalX(), pos.blockY(), pos.blockZ() + f.normalZ())); - if (front.key().value().endsWith("_stairs") && top == isTopStair(front)) { - Direction frontFacing = facingToDirection(front.getProperty("facing")); - if (frontFacing != f && frontFacing != f.opposite()) { - if (frontFacing == rotateCW(f)) return stair.withProperty("shape", "outer_right"); - else return stair.withProperty("shape", "outer_left"); - } - } - Block back = instance.getBlock(new BlockVec(pos.blockX() - f.normalX(), pos.blockY(), pos.blockZ() - f.normalZ())); - if (back.key().value().endsWith("_stairs") && top == isTopStair(back)) { - Direction backFacing = facingToDirection(back.getProperty("facing")); - if (backFacing != f && backFacing != f.opposite()) { - if (backFacing == rotateCW(f)) return stair.withProperty("shape", "inner_right"); - else return stair.withProperty("shape", "inner_left"); - } - } - return stair.withProperty("shape", "straight"); - } - - private static boolean isTopStair(Block b) { return "top".equals(b.getProperty("half")); } - - private static Block computeConnections(Block block, String path, Instance instance, BlockVec pos) { - boolean isWall = path.endsWith("_wall") && !path.endsWith("head_wall") && !path.endsWith("_wall_sign") && !path.endsWith("_wall_banner"); - if (path.endsWith("_fence_gate")) return block; - - Block result = block; - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - boolean connect = canConnectTo(nb, path, d); - String propName = d.name().toLowerCase(); - if (isWall) { - boolean tall = connect && isSolidAbove(instance, pos); - result = result.withProperty(propName, connect ? (tall ? "tall" : "low") : "none"); - } else { - result = result.withProperty(propName, connect ? "true" : "false"); - } - } - if (isWall && result.properties().containsKey("up")) { - boolean up = computeWallUp(result, instance, pos); - result = result.withProperty("up", up ? "true" : "false"); - } - return result; - } - - private static boolean isSolidAbove(Instance instance, BlockVec pos) { - Block above = instance.getBlock(new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ())); - return above.isSolid(); - } - - private static boolean computeWallUp(Block wall, Instance instance, BlockVec pos) { - boolean n = !"none".equals(wall.getProperty("north")); - boolean s = !"none".equals(wall.getProperty("south")); - boolean e = !"none".equals(wall.getProperty("east")); - boolean w = !"none".equals(wall.getProperty("west")); - boolean straight = (n && s && !e && !w) || (!n && !s && e && w); - if (!straight) return true; - return isSolidAbove(instance, pos); - } - - private static boolean canConnectTo(Block neighbor, String selfPath, Direction toward) { - if (neighbor.isAir()) return false; - String np = neighbor.key().value(); - if (np.endsWith("_fence_gate")) { - String facing = neighbor.getProperty("facing"); - if (facing != null) { - Direction f = facingToDirection(facing); - return toward != f && toward != f.opposite(); - } - return true; - } - if (selfPath.endsWith("_fence") && np.endsWith("_fence")) { - boolean selfNether = selfPath.contains("nether_brick"); - boolean nNether = np.contains("nether_brick"); - return selfNether == nNether; - } - if (selfPath.endsWith("_wall") && np.endsWith("_wall")) return true; - if ((selfPath.equals("glass_pane") || selfPath.endsWith("_stained_glass_pane") || selfPath.equals("iron_bars")) - && (np.equals("glass_pane") || np.endsWith("_stained_glass_pane") || np.equals("iron_bars"))) return true; - return neighbor.isSolid(); - } - - private static boolean isConnecting(String path) { - return path.endsWith("_fence") || (path.endsWith("_wall") && !path.endsWith("head_wall") - && !path.endsWith("_wall_sign") && !path.endsWith("_wall_banner") && !path.endsWith("_wall_torch") - && !path.endsWith("_wall_skull") && !path.endsWith("_wall_head") && !path.endsWith("_wall_hanging_sign")) - || path.equals("iron_bars") || path.equals("glass_pane") || path.endsWith("_stained_glass_pane"); - } - - private static Block updateFenceGateInWall(Block gate, Instance instance, BlockVec pos) { - if (!gate.key().value().endsWith("_fence_gate")) return gate; - String facing = gate.getProperty("facing"); - if (facing == null) return gate; - Direction f = facingToDirection(facing); - Direction left = rotateCCW(f); - Direction right = rotateCW(f); - Block l = instance.getBlock(new BlockVec(pos.blockX() + left.normalX(), pos.blockY(), pos.blockZ() + left.normalZ())); - Block r = instance.getBlock(new BlockVec(pos.blockX() + right.normalX(), pos.blockY(), pos.blockZ() + right.normalZ())); - boolean inWall = l.key().value().endsWith("_wall") || r.key().value().endsWith("_wall"); - return gate.withProperty("in_wall", inWall ? "true" : "false"); - } - - private static void updateRedstoneWire(Instance instance, BlockVec pos) { - Block wire = instance.getBlock(pos); - if (!wire.key().value().equals("redstone_wire")) return; - Block result = wire; - for (Direction d : Direction.HORIZONTAL) { - BlockVec side = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block sideBlock = instance.getBlock(side); - Block upBlock = instance.getBlock(new BlockVec(side.blockX(), side.blockY() + 1, side.blockZ())); - String state; - if (upBlock.key().value().equals("redstone_wire")) state = "up"; - else if (isRedstoneConnectable(sideBlock) - || instance.getBlock(new BlockVec(side.blockX(), side.blockY() - 1, side.blockZ())).key().value().equals("redstone_wire")) state = "side"; - else state = "none"; - result = result.withProperty(d.name().toLowerCase(), state); - } - instance.setBlock(pos, result); - } - - private static boolean isRedstoneConnectable(Block b) { - String p = b.key().value(); - return p.equals("redstone_wire") || p.equals("lever") || p.endsWith("_button") - || p.equals("repeater") || p.equals("comparator") || p.equals("redstone_torch") - || p.equals("redstone_wall_torch") || p.equals("observer") || p.equals("daylight_detector") - || p.endsWith("_pressure_plate") || p.equals("target") || p.equals("redstone_block") - || p.equals("tripwire_hook"); - } - - private static boolean isRail(String path) { - return path.equals("rail") || path.equals("powered_rail") || path.equals("detector_rail") || path.equals("activator_rail"); - } - - private static void updateRailShape(Instance instance, BlockVec pos) { - Block rail = instance.getBlock(pos); - String path = rail.key().value(); - if (!isRail(path)) return; - boolean canCurve = path.equals("rail"); - boolean[] adj = new boolean[4]; - boolean[] ascAdj = new boolean[4]; - Direction[] dirs = {Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}; - for (int i = 0; i < 4; i++) { - BlockVec np = new BlockVec(pos.blockX() + dirs[i].normalX(), pos.blockY(), pos.blockZ() + dirs[i].normalZ()); - adj[i] = isRail(instance.getBlock(np).key().value()); - BlockVec upNp = new BlockVec(np.blockX(), np.blockY() + 1, np.blockZ()); - ascAdj[i] = isRail(instance.getBlock(upNp).key().value()); - } - String shape; - if (canCurve) { - if (adj[0] && adj[1]) shape = "north_east"; - else if (adj[1] && adj[2]) shape = "south_east"; - else if (adj[2] && adj[3]) shape = "south_west"; - else if (adj[3] && adj[0]) shape = "north_west"; - else if (ascAdj[0]) shape = "ascending_north"; - else if (ascAdj[1]) shape = "ascending_east"; - else if (ascAdj[2]) shape = "ascending_south"; - else if (ascAdj[3]) shape = "ascending_west"; - else if (adj[1] || adj[3]) shape = "east_west"; - else shape = "north_south"; - } else { - if (ascAdj[0]) shape = "ascending_north"; - else if (ascAdj[1]) shape = "ascending_east"; - else if (ascAdj[2]) shape = "ascending_south"; - else if (ascAdj[3]) shape = "ascending_west"; - else if (adj[1] || adj[3]) shape = "east_west"; - else shape = "north_south"; - } - instance.setBlock(pos, rail.withProperty("shape", shape)); - } - - private static void updateScaffolding(Instance instance, BlockVec pos) { - Block s = instance.getBlock(pos); - if (!s.key().value().equals("scaffolding")) return; - Block below = instance.getBlock(new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ())); - boolean bottom; - int distance; - if (below.isSolid() && !below.key().value().equals("scaffolding")) { bottom = false; distance = 0; } - else if (below.key().value().equals("scaffolding")) { bottom = false; distance = 0; } - else { - int min = 7; - for (Direction d : Direction.HORIZONTAL) { - Block n = instance.getBlock(new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ())); - if (n.key().value().equals("scaffolding")) min = Math.min(min, parseIntOr(n.getProperty("distance"), 7) + 1); - } - bottom = true; - distance = min; - } - instance.setBlock(pos, s.withProperty("bottom", String.valueOf(bottom)).withProperty("distance", String.valueOf(distance))); - } - - private static void updateChestPair(Instance instance, BlockVec pos) { - Block chest = instance.getBlock(pos); - String path = chest.key().value(); - if (!(path.equals("chest") || path.equals("trapped_chest"))) return; - String facing = chest.getProperty("facing"); - if (facing == null) return; - Direction f = facingToDirection(facing); - Direction left = rotateCCW(f); - Direction right = rotateCW(f); - BlockVec leftPos = new BlockVec(pos.blockX() + left.normalX(), pos.blockY(), pos.blockZ() + left.normalZ()); - BlockVec rightPos = new BlockVec(pos.blockX() + right.normalX(), pos.blockY(), pos.blockZ() + right.normalZ()); - Block leftBlock = instance.getBlock(leftPos); - Block rightBlock = instance.getBlock(rightPos); - if (leftBlock.key().value().equals(path) && facing.equals(leftBlock.getProperty("facing")) - && "single".equals(leftBlock.getProperty("type"))) { - instance.setBlock(pos, chest.withProperty("type", "right")); - instance.setBlock(leftPos, leftBlock.withProperty("type", "left")); - return; - } - if (rightBlock.key().value().equals(path) && facing.equals(rightBlock.getProperty("facing")) - && "single".equals(rightBlock.getProperty("type"))) { - instance.setBlock(pos, chest.withProperty("type", "left")); - instance.setBlock(rightPos, rightBlock.withProperty("type", "right")); - } - } - - private static String yawToFacing(float yaw) { - float y = ((yaw % 360) + 360) % 360; - if (y >= 315 || y < 45) return "south"; - if (y < 135) return "west"; - if (y < 225) return "north"; - return "east"; - } - - private static String faceName(BlockFace face) { - return switch (face) { - case NORTH -> "north"; - case SOUTH -> "south"; - case EAST -> "east"; - case WEST -> "west"; - case TOP -> "up"; - case BOTTOM -> "down"; - }; - } - - private static String oppositeFacing(String f) { - return switch (f) { - case "north" -> "south"; - case "south" -> "north"; - case "east" -> "west"; - case "west" -> "east"; - case "up" -> "down"; - case "down" -> "up"; - default -> f; - }; - } - - private static Direction faceDirection(BlockFace face) { - return switch (face) { - case NORTH -> Direction.NORTH; - case SOUTH -> Direction.SOUTH; - case EAST -> Direction.EAST; - case WEST -> Direction.WEST; - case TOP -> Direction.UP; - case BOTTOM -> Direction.DOWN; - }; - } - - private static Direction facingToDirection(String f) { - if (f == null) return Direction.NORTH; - return switch (f) { - case "north" -> Direction.NORTH; - case "south" -> Direction.SOUTH; - case "east" -> Direction.EAST; - case "west" -> Direction.WEST; - case "up" -> Direction.UP; - case "down" -> Direction.DOWN; - default -> Direction.NORTH; - }; - } - - private static Direction rotateCW(Direction d) { - return switch (d) { - case NORTH -> Direction.EAST; - case EAST -> Direction.SOUTH; - case SOUTH -> Direction.WEST; - case WEST -> Direction.NORTH; - default -> d; - }; - } - - private static Direction rotateCCW(Direction d) { - return switch (d) { - case NORTH -> Direction.WEST; - case WEST -> Direction.SOUTH; - case SOUTH -> Direction.EAST; - case EAST -> Direction.NORTH; - default -> d; - }; - } - - private static String doorHinge(String facing, Point cursor, Instance instance, BlockVec pos, String path) { - Direction f = facingToDirection(facing); - Direction left = rotateCCW(f); - BlockVec leftPos = new BlockVec(pos.blockX() + left.normalX(), pos.blockY(), pos.blockZ() + left.normalZ()); - Block leftBlock = instance.getBlock(leftPos); - if (leftBlock.key().value().equals(path) && facing.equals(leftBlock.getProperty("facing"))) { - return "right"; - } - double x = cursor.x() - 0.5; - double z = cursor.z() - 0.5; - return switch (facing) { - case "north" -> x < 0 ? "right" : "left"; - case "south" -> x > 0 ? "right" : "left"; - case "west" -> z > 0 ? "right" : "left"; - case "east" -> z < 0 ? "right" : "left"; - default -> "left"; - }; - } - - public static void onInteract(PlayerBlockInteractEvent event) { - Block block = event.getBlock(); - String path = block.key().value(); - Instance instance = event.getInstance(); - BlockVec pos = event.getBlockPosition(); - - if (path.endsWith("_door")) { - String half = block.getProperty("half"); - BlockVec lowerPos = "upper".equals(half) - ? new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()) - : pos; - BlockVec upperPos = new BlockVec(lowerPos.blockX(), lowerPos.blockY() + 1, lowerPos.blockZ()); - Block lower = instance.getBlock(lowerPos); - Block upper = instance.getBlock(upperPos); - if (!lower.key().value().equals(path) || !upper.key().value().equals(path)) return; - boolean open = !"true".equals(lower.getProperty("open")); - instance.setBlock(lowerPos, lower.withProperty("open", String.valueOf(open))); - instance.setBlock(upperPos, upper.withProperty("open", String.valueOf(open))); - - String facing = lower.getProperty("facing"); - String hinge = lower.getProperty("hinge"); - if (facing != null && hinge != null) { - Direction f = facingToDirection(facing); - Direction side = "left".equals(hinge) ? rotateCW(f) : rotateCCW(f); - BlockVec partnerPos = new BlockVec(lowerPos.blockX() + side.normalX(), lowerPos.blockY(), lowerPos.blockZ() + side.normalZ()); - Block partner = instance.getBlock(partnerPos); - if (partner.key().value().equals(path) && facing.equals(partner.getProperty("facing")) - && !hinge.equals(partner.getProperty("hinge"))) { - Block partnerUpper = instance.getBlock(new BlockVec(partnerPos.blockX(), partnerPos.blockY() + 1, partnerPos.blockZ())); - instance.setBlock(partnerPos, partner.withProperty("open", String.valueOf(open))); - if (partnerUpper.key().value().equals(path)) { - instance.setBlock(new BlockVec(partnerPos.blockX(), partnerPos.blockY() + 1, partnerPos.blockZ()), - partnerUpper.withProperty("open", String.valueOf(open))); - } - } - } - event.setBlockingItemUse(true); - return; - } - - if (path.endsWith("_fence_gate")) { - boolean open = !"true".equals(block.getProperty("open")); - Block updated = block.withProperty("open", String.valueOf(open)); - if (open) { - String facing = block.getProperty("facing"); - if (facing != null) { - Direction f = facingToDirection(facing); - Direction playerDir = horizontalFacingToDirection(yawToFacing(event.getPlayer().getPosition().yaw())); - if (playerDir == f) updated = updated.withProperty("facing", oppositeFacing(facing)); - } - } - instance.setBlock(pos, updated); - event.setBlockingItemUse(true); - return; - } - - if (path.endsWith("_trapdoor")) { - boolean open = !"true".equals(block.getProperty("open")); - instance.setBlock(pos, block.withProperty("open", String.valueOf(open))); - event.setBlockingItemUse(true); - } - } - - private static Direction horizontalFacingToDirection(String f) { - return facingToDirection(f); - } - - public static void onBreak(PlayerBlockBreakEvent event) { - Instance instance = event.getInstance(); - BlockVec pos = event.getBlockPosition(); - Block broken = event.getBlock(); - String path = broken.key().value(); - - if (path.endsWith("_door")) { - String half = broken.getProperty("half"); - BlockVec other = "upper".equals(half) - ? new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()) - : new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); - instance.scheduler().scheduleNextTick(() -> { - Block ob = instance.getBlock(other); - if (ob.key().value().equals(path)) instance.setBlock(other, Block.AIR); - }); - } - - if (path.endsWith("_bed")) { - String part = broken.getProperty("part"); - String facing = broken.getProperty("facing"); - if (facing != null) { - Direction d = facingToDirection(facing); - if ("foot".equals(part)) { - BlockVec headPos = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - instance.scheduler().scheduleNextTick(() -> { - if (instance.getBlock(headPos).key().value().equals(path)) instance.setBlock(headPos, Block.AIR); - }); - } else if ("head".equals(part)) { - BlockVec footPos = new BlockVec(pos.blockX() - d.normalX(), pos.blockY(), pos.blockZ() - d.normalZ()); - instance.scheduler().scheduleNextTick(() -> { - if (instance.getBlock(footPos).key().value().equals(path)) instance.setBlock(footPos, Block.AIR); - }); - } - } - } - - if (path.equals("big_dripleaf") || path.equals("big_dripleaf_stem")) { - String half = broken.getProperty("half"); - BlockVec other = "upper".equals(half) - ? new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()) - : new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); - instance.scheduler().scheduleNextTick(() -> { - String op = instance.getBlock(other).key().value(); - if (op.equals("big_dripleaf") || op.equals("big_dripleaf_stem")) instance.setBlock(other, Block.AIR); - }); - } - - instance.scheduler().scheduleNextTick(() -> { - if (isConnecting(path)) { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (isConnecting(nb.key().value())) instance.setBlock(np, computeConnections(nb, nb.key().value(), instance, np)); - if (nb.key().value().endsWith("_fence_gate")) instance.setBlock(np, updateFenceGateInWall(nb, instance, np)); - } - } - - if (path.endsWith("_wall")) { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (nb.key().value().endsWith("_fence_gate")) instance.setBlock(np, updateFenceGateInWall(nb, instance, np)); - } - } - - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - String npath = nb.key().value(); - if (npath.equals("redstone_wire")) updateRedstoneWire(instance, np); - if (isRail(npath)) updateRailShape(instance, np); - } - BlockVec above = new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); - if (instance.getBlock(above).key().value().equals("redstone_wire")) updateRedstoneWire(instance, above); - BlockVec belowRail = new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()); - if (isRail(instance.getBlock(belowRail).key().value())) updateRailShape(instance, belowRail); - - if (path.equals("scaffolding") || isAnyScaffoldingAround(instance, pos)) { - recomputeScaffoldingColumn(instance, pos); - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - if (instance.getBlock(np).key().value().equals("scaffolding")) recomputeScaffoldingColumn(instance, np); - } - } - - if (path.equals("chest") || path.equals("trapped_chest")) { - String facing = broken.getProperty("facing"); - if (facing != null) { - Direction f = facingToDirection(facing); - for (Direction d : new Direction[]{rotateCW(f), rotateCCW(f)}) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (nb.key().value().equals(path) && facing.equals(nb.getProperty("facing"))) { - String t = nb.getProperty("type"); - if ("left".equals(t) || "right".equals(t)) instance.setBlock(np, nb.withProperty("type", "single")); - } - } - } - } - - if (isStairLike(path)) { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - Block nb = instance.getBlock(np); - if (nb.key().value().endsWith("_stairs")) { - String nf = nb.getProperty("facing"); - boolean nt = isTopStair(nb); - instance.setBlock(np, applyStairShape(nb, instance, np, nf, nt)); - } - } - } - }); - } - - private static boolean isStairLike(String path) { return path.endsWith("_stairs"); } - - private static boolean isAnyScaffoldingAround(Instance instance, BlockVec pos) { - for (Direction d : Direction.HORIZONTAL) { - BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()); - if (instance.getBlock(np).key().value().equals("scaffolding")) return true; - } - BlockVec above = new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ()); - return instance.getBlock(above).key().value().equals("scaffolding"); - } - - private static void recomputeScaffoldingColumn(Instance instance, BlockVec start) { - int x = start.blockX(), z = start.blockZ(); - for (int y = start.blockY(); y < start.blockY() + 32; y++) { - BlockVec p = new BlockVec(x, y, z); - if (!instance.getBlock(p).key().value().equals("scaffolding")) break; - updateScaffolding(instance, p); - } - } - - private static int parseIntOr(String s, int d) { - if (s == null) return d; - try { return Integer.parseInt(s); } catch (NumberFormatException e) { return d; } - } -} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java index 03c6db2..ccb2a25 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattle.java @@ -62,10 +62,11 @@ public class BuildBattle extends StatelessGame { super(Dimension.THE_END.key, "BuildBattle", new PointsWinScore()); this.seconds = seconds; this.setGenerator(new BuildBattleChunkgenerator(height)); + BuildBattleBlockRules.register(); this.eventNode().addListener(PlayerUseItemEvent.class, this::onRatingItemUse); this.eventNode().addListener(PlayerUseItemOnBlockEvent.class, e -> FluidFlowHelper.onBucketUse(e, p -> this.isInArea(p, e.getPlayer()))); this.eventNode().addListener(PlayerBlockInteractEvent.class, e -> { - if (this.isInArea(e.getBlockPosition(), e.getPlayer())) BlockPlacementHelper.onInteract(e); + if (this.isInArea(e.getBlockPosition(), e.getPlayer())) BuildBattleBlockRules.onInteract(e); }); } @@ -134,7 +135,6 @@ public class BuildBattle extends StatelessGame { event.setCancelled(true); return; } - BlockPlacementHelper.onBreak(event); FluidFlowHelper.onBreak(event); } @@ -144,7 +144,6 @@ public class BuildBattle extends StatelessGame { event.setCancelled(true); return; } - BlockPlacementHelper.apply(event); FluidFlowHelper.onPlace(event); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattleBlockRules.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattleBlockRules.java new file mode 100644 index 0000000..5ab090c --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/buildBattle/BuildBattleBlockRules.java @@ -0,0 +1,85 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle; + +import net.minestom.server.MinecraftServer; +import net.minestom.server.event.player.PlayerBlockInteractEvent; +import net.minestom.server.instance.block.Block; +import net.minestom.server.instance.block.BlockHandler; +import net.minestom.server.instance.block.rule.BlockPlacementRule; +import org.everbuild.blocksandstuff.blocks.group.VanillaBlockBehaviour; +import org.everbuild.blocksandstuff.blocks.group.VanillaPlacementRules; +import org.everbuild.blocksandstuff.blocks.group.behaviour.BehaviourGroup; +import org.everbuild.blocksandstuff.blocks.group.placement.PlacementGroup; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public final class BuildBattleBlockRules { + private BuildBattleBlockRules() {} + + private static final ThreadLocal interactingInBuildBattle = ThreadLocal.withInitial(() -> false); + private static final Map behaviours = new HashMap<>(); + private static boolean registered = false; + + public static synchronized void register() { + if (registered) return; + registered = true; + + var blockManager = MinecraftServer.getBlockManager(); + for (PlacementGroup group : VanillaPlacementRules.INSTANCE.getALL()) { + for (Block block : group.getBlockGroup().allMatching()) { + blockManager.registerBlockPlacementRule(new BuildBattleOnlyRule(group.createRule(block))); + } + } + + for (BehaviourGroup group : VanillaBlockBehaviour.INSTANCE.getALL()) { + for (Block block : group.getBlockGroup().allMatching()) { + behaviours.put(block.id(), group.createHandler(block)); + } + } + + MinecraftServer.getGlobalEventHandler().addListener(PlayerBlockInteractEvent.class, + e -> interactingInBuildBattle.set(e.getInstance() instanceof BuildBattle)); + } + + public static void onInteract(PlayerBlockInteractEvent event) { + BlockHandler handler = behaviours.get(event.getBlock().id()); + if (handler == null) return; + boolean continueItemUse = handler.onInteract(new BlockHandler.Interaction( + event.getBlock(), event.getInstance(), event.getBlockFace(), event.getBlockPosition(), + event.getCursorPosition(), event.getPlayer(), event.getHand() + )); + if (!continueItemUse) event.setBlockingItemUse(true); + } + + private static final class BuildBattleOnlyRule extends BlockPlacementRule { + private final BlockPlacementRule delegate; + + private BuildBattleOnlyRule(BlockPlacementRule delegate) { + super(delegate.getBlock()); + this.delegate = delegate; + } + + @Override + public @Nullable Block blockPlace(PlacementState placementState) { + if (!(placementState.instance() instanceof BuildBattle)) return placementState.block(); + return this.delegate.blockPlace(placementState); + } + + @Override + public Block blockUpdate(UpdateState updateState) { + if (!(updateState.instance() instanceof BuildBattle)) return updateState.currentBlock(); + return this.delegate.blockUpdate(updateState); + } + + @Override + public boolean isSelfReplaceable(Replacement replacement) { + return interactingInBuildBattle.get() && this.delegate.isSelfReplaceable(replacement); + } + + @Override + public int maxUpdateDistance() { + return this.delegate.maxUpdateDistance(); + } + } +} From 9d779a4879dbad2c0d18d5c4a6ad9179549e879a Mon Sep 17 00:00:00 2001 From: jannis Date: Wed, 28 Oct 2026 22:07:45 +0100 Subject: [PATCH 09/10] fixed root cause of knockback issue in high ground --- .../types/highGround/HighGround.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/highGround/HighGround.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/highGround/HighGround.java index 712f8c4..e13986e 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/highGround/HighGround.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/highGround/HighGround.java @@ -9,6 +9,7 @@ import io.github.togar2.pvp.events.FinalAttackEvent; import io.github.togar2.pvp.events.PrepareAttackEvent; import io.github.togar2.pvp.feature.CombatFeatures; import io.github.togar2.pvp.feature.knockback.KnockbackSettings; +import net.minestom.server.ServerFlag; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Player; import net.minestom.server.event.instance.InstanceTickEvent; @@ -52,16 +53,16 @@ class HighGround extends StatelessGame { this.eventNode().addListener( EntityKnockbackEvent.class, entityKnockbackEvent -> { - if(entityKnockbackEvent.getEntity().getVelocity().y() > 4) { entityKnockbackEvent.setCancelled(true); return; } + double tps = ServerFlag.SERVER_TICKS_PER_SECOND; entityKnockbackEvent.setSettings( - KnockbackSettings.builder() - .horizontal(1.1) - .vertical(0) - .verticalLimit(0) - .extraHorizontal(0.5) - .extraVertical(0) - .build() - ); + KnockbackSettings.builder() + .horizontal(1.1) + .vertical(KnockbackSettings.DEFAULT.vertical() / tps) + .verticalLimit(KnockbackSettings.DEFAULT.verticalLimit() / tps) + .extraHorizontal(KnockbackSettings.DEFAULT.extraHorizontal() / tps) + .extraVertical(KnockbackSettings.DEFAULT.extraVertical() / tps) + .build() + ); } ); From 1ef1d760edb2b86d085f0f2bdd9933e80a603bfe Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 30 Oct 2026 00:16:42 +0100 Subject: [PATCH 10/10] fixed tetris game tick delay too low at high levels --- .../instance/game/stateless/types/tetris/game/TetrisGame.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 5098939..e50c7ba 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -92,7 +92,7 @@ public class TetrisGame { int standardTickDelay = 40; if(this.isFast) standardTickDelay = 20; - TaskSchedule nextTick = TaskSchedule.tick(Math.round((float) standardTickDelay / this.level)); + TaskSchedule nextTick = TaskSchedule.tick(Math.max(Math.round((float) standardTickDelay / this.level), 1)); if(this.paused) return nextTick; this.tick(); return nextTick;