From c87d31842125f8443581b89581ca6dcd196b1d04 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 2 Sep 2025 18:22:14 +0200 Subject: [PATCH 01/27] started turtleGame --- .../types/turtleGame/TurtleGame.java | 11 ++++++++++ .../types/turtleGame/TurtleGameFactory.java | 22 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java new file mode 100644 index 0000000..69435c7 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -0,0 +1,11 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame; + +import eu.mhsl.minenet.minigames.instance.Dimension; +import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import eu.mhsl.minenet.minigames.score.PointsWinScore; + +class TurtleGame extends StatelessGame { + public TurtleGame() { + super(Dimension.OVERWORLD.key, "Tetris", new PointsWinScore()); + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java new file mode 100644 index 0000000..0ea7728 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -0,0 +1,22 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame; + +import eu.mhsl.minenet.minigames.instance.game.Game; +import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory; +import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option; +import eu.mhsl.minenet.minigames.instance.room.Room; +import eu.mhsl.minenet.minigames.message.component.TranslatedComponent; + +import java.util.Map; + +public class TurtleGameFactory implements GameFactory { + + @Override + public TranslatedComponent name() { + return TranslatedComponent.byId("game_TurtleGame#name"); + } + + @Override + public Game manufacture(Room parent, Map> configuration) throws Exception { + return new TurtleGame(); + } +} From d98cebd86f77273112a03ab18af7fb487a43bcd8 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 2 Sep 2025 22:29:47 +0200 Subject: [PATCH 02/27] added turtleGame playfield and movement --- .../minigames/instance/game/GameList.java | 2 + .../types/turtleGame/TurtleGame.java | 61 ++++++++++++++++++- .../types/turtleGame/TurtleGameFactory.java | 21 ++++++- .../turtleGame/game/TurtleGameInstance.java | 53 ++++++++++++++++ 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java index 6fc6d6d..f6236c1 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java @@ -18,6 +18,7 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.types.sumo.SumoFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.tntrun.TntRunFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.TowerdefenseFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.trafficlightrace.TrafficLightRaceFactory; +import eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.TurtleGameFactory; public enum GameList { DEATHCUBE(new DeathcubeFactory(), GameType.JUMPNRUN), @@ -28,6 +29,7 @@ public enum GameList { BEDWARS(new BedwarsFactory(), GameType.PROTOTYPE), BACKROOMS(new BackroomsFactory(), GameType.PROTOTYPE), BOWSPLEEF(new BowSpleefFactory(), GameType.PROTOTYPE), + TURTLEGAME(new TurtleGameFactory(), GameType.PROTOTYPE), TETRIS(new TetrisFactory(), GameType.OTHER), TNTRUN(new TntRunFactory(), GameType.OTHER), ANVILRUN(new AnvilRunFactory(), GameType.PVE), diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 69435c7..3e93cd5 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -2,10 +2,69 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.game.TurtleGameInstance; import eu.mhsl.minenet.minigames.score.PointsWinScore; +import net.kyori.adventure.text.Component; +import net.minestom.server.MinecraftServer; +import net.minestom.server.entity.EntityCreature; +import net.minestom.server.entity.Player; +import net.minestom.server.entity.attribute.Attribute; +import net.minestom.server.event.player.PlayerMoveEvent; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.WeakHashMap; class TurtleGame extends StatelessGame { - public TurtleGame() { + private final boolean firstPerson; + private final Map gameInstances = new WeakHashMap<>(); + + public TurtleGame(boolean firstPerson) { super(Dimension.OVERWORLD.key, "Tetris", new PointsWinScore()); + this.firstPerson = firstPerson; + + this.eventNode() + .addListener(PlayerMoveEvent.class, this::onPlayerMove); + } + + protected void onPlayerMove(@NotNull PlayerMoveEvent event) { + TurtleGameInstance gameInstance = this.gameInstances.get(event.getPlayer()); + gameInstance.getTurtle().setView(event.getPlayer().getPosition().yaw(), gameInstance.getTurtle().getPosition().pitch()); + if(this.isRunning()) gameInstance.moveTurtle(event.getPlayer().getPosition().direction()); + } + + @Override + protected boolean onPlayerJoin(Player p) { + p.getInventory().setItemStack(0, ItemStack.builder(Material.BARRIER).customName(Component.text("Reset")).build()); + + if(this.gameInstances.get(p) == null) { + this.gameInstances.put(p, new TurtleGameInstance( + this, + this.getSpawn().sub(6, 8, 15).add(this.gameInstances.size()*50, 0, 0) + )); + this.gameInstances.get(p).generate(); + } + + TurtleGameInstance gameInstance = this.gameInstances.get(p); + + p.teleport(gameInstance.getPlayerSpawnPosition()); + + EntityCreature turtle = gameInstance.getTurtle(); + MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { + turtle.setInstance(this); + turtle.teleport(gameInstance.getPlayerSpawnPosition()); + turtle.addPassenger(p); + turtle.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.15); + }); + + return super.onPlayerJoin(p); + } + + @Override + protected void onStart() { + this.gameInstances.forEach(((player, gameInstance) -> gameInstance.moveTurtle(player.getPosition().direction()))); +// this.gameInstances.forEach(((player, turtleGameInstance) -> turtleGameInstance.start())); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index 0ea7728..d2b9a20 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -1,10 +1,13 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame; import eu.mhsl.minenet.minigames.instance.game.Game; +import eu.mhsl.minenet.minigames.instance.game.stateless.config.ConfigManager; import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option; +import eu.mhsl.minenet.minigames.instance.game.stateless.config.common.BoolOption; import eu.mhsl.minenet.minigames.instance.room.Room; import eu.mhsl.minenet.minigames.message.component.TranslatedComponent; +import net.minestom.server.item.Material; import java.util.Map; @@ -15,8 +18,24 @@ public class TurtleGameFactory implements GameFactory { return TranslatedComponent.byId("game_TurtleGame#name"); } + @Override + public TranslatedComponent description() { + return TranslatedComponent.byId("game_TurtleGame#description"); + } + + @Override + public ConfigManager configuration() { + return new ConfigManager() + .addOption(new BoolOption("firstPerson", Material.SPYGLASS, TranslatedComponent.byId("game_TurtleGame#firstPerson"))); + } + @Override public Game manufacture(Room parent, Map> configuration) throws Exception { - return new TurtleGame(); + return new TurtleGame(configuration.get("firstPerson").getAsBoolean()); + } + + @Override + public Material symbol() { + return Material.TURTLE_EGG; } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java new file mode 100644 index 0000000..38216e9 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java @@ -0,0 +1,53 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.game; + +import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import eu.mhsl.minenet.minigames.util.BatchUtil; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.EntityCreature; +import net.minestom.server.entity.EntityType; +import net.minestom.server.instance.batch.AbsoluteBlockBatch; +import net.minestom.server.instance.block.Block; + +import java.awt.*; + +public class TurtleGameInstance { + private final StatelessGame instance; + private final Pos startPosition; + private final EntityCreature turtle = new EntityCreature(EntityType.TURTLE); + + public TurtleGameInstance(StatelessGame instance, Pos startPosition) { + this.instance = instance; + this.startPosition = startPosition; + } + + public void moveTurtle(Vec direction) { + Vec targetDirection = direction.withY(0).normalize().mul(100); + Pos targetPosition = this.turtle.getPosition().add(targetDirection); + this.turtle.getNavigator().setPathTo(targetPosition); + } + + public void generate() { + AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); + + for (int z = -1; z < 66; z++) { + for (int x = -1; x < 44; x++) { + if(z < 0 || z >= 65 || x < 0 || x >= 43) { + batch.setBlock(this.startPosition.add(x, 1, z), Block.STONE); + batch.setBlock(this.startPosition.add(x, 2, z), Block.STONE_SLAB); + } + batch.setBlock(this.startPosition.add(x, 0, z), Block.SAND); + } + } + + BatchUtil.loadAndApplyBatch(batch, this.instance, () -> {}); + } + + public Pos getPlayerSpawnPosition() { + return this.startPosition.add(20, 1, 30); + } + + public EntityCreature getTurtle() { + return this.turtle; + } +} From abcb23d96ae44458a6b175bb46163db903f8eb01 Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 3 Oct 2025 18:47:11 +0200 Subject: [PATCH 03/27] made turtle movement clean --- .../game/stateless/types/turtleGame/TurtleGame.java | 12 ++++++------ .../types/turtleGame/game/TurtleGameInstance.java | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 3e93cd5..50484c7 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -9,7 +9,7 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.entity.EntityCreature; import net.minestom.server.entity.Player; import net.minestom.server.entity.attribute.Attribute; -import net.minestom.server.event.player.PlayerMoveEvent; +import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import org.jetbrains.annotations.NotNull; @@ -22,22 +22,22 @@ class TurtleGame extends StatelessGame { private final Map gameInstances = new WeakHashMap<>(); public TurtleGame(boolean firstPerson) { - super(Dimension.OVERWORLD.key, "Tetris", new PointsWinScore()); + super(Dimension.OVERWORLD.key, "Turtle Game", new PointsWinScore()); this.firstPerson = firstPerson; this.eventNode() - .addListener(PlayerMoveEvent.class, this::onPlayerMove); + .addListener(PlayerTickEvent.class, this::onPlayerTick); } - protected void onPlayerMove(@NotNull PlayerMoveEvent event) { + protected void onPlayerTick(@NotNull PlayerTickEvent event) { TurtleGameInstance gameInstance = this.gameInstances.get(event.getPlayer()); - gameInstance.getTurtle().setView(event.getPlayer().getPosition().yaw(), gameInstance.getTurtle().getPosition().pitch()); + gameInstance.getTurtle().teleport(gameInstance.getTurtle().getPosition().withView(event.getPlayer().getPosition())); if(this.isRunning()) gameInstance.moveTurtle(event.getPlayer().getPosition().direction()); } @Override protected boolean onPlayerJoin(Player p) { - p.getInventory().setItemStack(0, ItemStack.builder(Material.BARRIER).customName(Component.text("Reset")).build()); + p.getInventory().setItemStack(0, ItemStack.builder(Material.BARRIER).customName(Component.text("Reset Snack")).build()); if(this.gameInstances.get(p) == null) { this.gameInstances.put(p, new TurtleGameInstance( diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java index 38216e9..9bf83d4 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java @@ -15,6 +15,7 @@ public class TurtleGameInstance { private final StatelessGame instance; private final Pos startPosition; private final EntityCreature turtle = new EntityCreature(EntityType.TURTLE); + private double speed = 2; public TurtleGameInstance(StatelessGame instance, Pos startPosition) { this.instance = instance; @@ -22,9 +23,8 @@ public class TurtleGameInstance { } public void moveTurtle(Vec direction) { - Vec targetDirection = direction.withY(0).normalize().mul(100); - Pos targetPosition = this.turtle.getPosition().add(targetDirection); - this.turtle.getNavigator().setPathTo(targetPosition); + Vec targetDirection = direction.withY(0).normalize().mul(speed); + this.turtle.setVelocity(targetDirection); } public void generate() { From f2fc4835c305e5ce48934a8ce35109b3f9e12e10 Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 3 Oct 2025 19:32:52 +0200 Subject: [PATCH 04/27] started random snack generation --- .../game/stateless/types/turtleGame/TurtleGame.java | 3 +++ .../stateless/types/turtleGame/TurtleGameFactory.java | 4 +++- .../types/turtleGame/game/TurtleGameInstance.java | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 50484c7..4e49edf 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -15,11 +15,13 @@ import net.minestom.server.item.Material; import org.jetbrains.annotations.NotNull; import java.util.Map; +import java.util.Random; import java.util.WeakHashMap; class TurtleGame extends StatelessGame { private final boolean firstPerson; private final Map gameInstances = new WeakHashMap<>(); + private final Random random = new Random(); public TurtleGame(boolean firstPerson) { super(Dimension.OVERWORLD.key, "Turtle Game", new PointsWinScore()); @@ -39,6 +41,7 @@ class TurtleGame extends StatelessGame { protected boolean onPlayerJoin(Player p) { p.getInventory().setItemStack(0, ItemStack.builder(Material.BARRIER).customName(Component.text("Reset Snack")).build()); + // TODO: instance auflösen, ein großer Kreis if(this.gameInstances.get(p) == null) { this.gameInstances.put(p, new TurtleGameInstance( this, diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index d2b9a20..f3f673a 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -5,6 +5,7 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.config.ConfigManager; import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option; import eu.mhsl.minenet.minigames.instance.game.stateless.config.common.BoolOption; +import eu.mhsl.minenet.minigames.instance.game.stateless.config.common.NumericOption; import eu.mhsl.minenet.minigames.instance.room.Room; import eu.mhsl.minenet.minigames.message.component.TranslatedComponent; import net.minestom.server.item.Material; @@ -26,7 +27,8 @@ public class TurtleGameFactory implements GameFactory { @Override public ConfigManager configuration() { return new ConfigManager() - .addOption(new BoolOption("firstPerson", Material.SPYGLASS, TranslatedComponent.byId("game_TurtleGame#firstPerson"))); + .addOption(new BoolOption("firstPerson", Material.SPYGLASS, TranslatedComponent.byId("game_TurtleGame#firstPerson"))) + .addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 10, 20, 30, 40)); } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java index 9bf83d4..438f8af 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java @@ -27,6 +27,15 @@ public class TurtleGameInstance { this.turtle.setVelocity(targetDirection); } + // TODO: kleine display entities, die rotieren und so +// public void generateNewSnack() { +// int z, x; +// do { +// z = random.nextInt(0, 66); +// x = random.nextInt(0, 44); +// } while (!this.instance.getBlock(this.startPosition.add(x, 1, z)).isAir()); +// } + public void generate() { AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); From 81524cfecf55108781981073e7c13b028392944e Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 00:09:19 +0200 Subject: [PATCH 05/27] added snacks with collision, switched to multiplayer arena --- .../types/turtleGame/TurtleGame.java | 123 ++++++++++++++---- .../types/turtleGame/TurtleGameFactory.java | 2 +- .../turtleGame/game/TurtleGameInstance.java | 62 --------- 3 files changed, 99 insertions(+), 88 deletions(-) delete mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 4e49edf..bc4fbe7 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -2,62 +2,95 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; -import eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.game.TurtleGameInstance; import eu.mhsl.minenet.minigames.score.PointsWinScore; import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityCreature; +import net.minestom.server.entity.EntityType; import net.minestom.server.entity.Player; import net.minestom.server.entity.attribute.Attribute; +import net.minestom.server.entity.metadata.other.FallingBlockMeta; import net.minestom.server.event.player.PlayerTickEvent; +import net.minestom.server.instance.block.Block; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import org.jetbrains.annotations.NotNull; -import java.util.Map; -import java.util.Random; -import java.util.WeakHashMap; +import java.util.*; +import java.util.concurrent.CompletableFuture; class TurtleGame extends StatelessGame { private final boolean firstPerson; - private final Map gameInstances = new WeakHashMap<>(); - private final Random random = new Random(); + private final int radius; + private final Map turtlePlayerMap = new WeakHashMap<>(); + private final ArrayList snacks = new ArrayList<>(); + private final double speed = 2; - public TurtleGame(boolean firstPerson) { + public TurtleGame(boolean firstPerson, int radius) { super(Dimension.OVERWORLD.key, "Turtle Game", new PointsWinScore()); this.firstPerson = firstPerson; + this.radius = radius; this.eventNode() .addListener(PlayerTickEvent.class, this::onPlayerTick); } + @Override + protected void onLoad(@NotNull CompletableFuture callback) { + this.generatePlatform(); + } + + private void generatePlatform() { + for(int x = -this.radius - 1; x <= this.radius + 1; x++) { + for(int z = -this.radius - 1; z <= this.radius + 1; z++) { + double distance = new Pos(x, 0, z).distance(new Pos(0, 0, 0)); + if(distance <= this.radius) { + boolean isEdge = this.radius - 1 < distance; + this.setBlock(x, 0, z, Block.SAND); + this.setBlock(x, 1, z, isEdge ? Block.STONE : Block.AIR); + this.setBlock(x, 2, z, isEdge ? Block.STONE_SLAB : Block.AIR); + } else { + this.setBlock(x, 0, z, Block.AIR); + } + } + } + } + protected void onPlayerTick(@NotNull PlayerTickEvent event) { - TurtleGameInstance gameInstance = this.gameInstances.get(event.getPlayer()); - gameInstance.getTurtle().teleport(gameInstance.getTurtle().getPosition().withView(event.getPlayer().getPosition())); - if(this.isRunning()) gameInstance.moveTurtle(event.getPlayer().getPosition().direction()); + EntityCreature turtle = this.turtlePlayerMap.get(event.getPlayer()); + turtle.teleport(turtle.getPosition().withView(event.getPlayer().getPosition())); + Vec direction = event.getPlayer().getPosition().direction(); + if(this.isRunning()) { + Vec targetDirection = direction.withY(0).normalize().mul(this.speed); + turtle.setVelocity(targetDirection); + + List hit = this.snacks.stream() + .filter(snack -> snack.getBoundingBox().intersectBox(turtle.getPosition().sub(snack.getPosition()), turtle.getBoundingBox())) + .toList(); + hit.forEach(snack -> { + this.snacks.remove(snack); + snack.remove(); + this.generateNewSnack(); + }); + } } @Override protected boolean onPlayerJoin(Player p) { p.getInventory().setItemStack(0, ItemStack.builder(Material.BARRIER).customName(Component.text("Reset Snack")).build()); - // TODO: instance auflösen, ein großer Kreis - if(this.gameInstances.get(p) == null) { - this.gameInstances.put(p, new TurtleGameInstance( - this, - this.getSpawn().sub(6, 8, 15).add(this.gameInstances.size()*50, 0, 0) - )); - this.gameInstances.get(p).generate(); + if(this.turtlePlayerMap.get(p) == null) { + EntityCreature turtle = new EntityCreature(EntityType.TURTLE); + this.turtlePlayerMap.put(p, turtle); } - TurtleGameInstance gameInstance = this.gameInstances.get(p); - - p.teleport(gameInstance.getPlayerSpawnPosition()); - - EntityCreature turtle = gameInstance.getTurtle(); + EntityCreature turtle = this.turtlePlayerMap.get(p); MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { turtle.setInstance(this); - turtle.teleport(gameInstance.getPlayerSpawnPosition()); + turtle.teleport(p.getPosition()); turtle.addPassenger(p); turtle.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.15); }); @@ -65,9 +98,49 @@ class TurtleGame extends StatelessGame { return super.onPlayerJoin(p); } + @Override + protected void onPlayerLeave(Player p) { + EntityCreature turtle = this.turtlePlayerMap.get(p); + turtle.remove(); + } + + @Override + public Pos getSpawn() { + double theta = this.rnd.nextDouble() * 2 * Math.PI; + + double spawnRadius = this.radius - 4; + double x = spawnRadius * Math.cos(theta); + double z = spawnRadius * Math.sin(theta); + + return new Pos(x, 1, z).withLookAt(new Pos(0, 0, 0)); + } + + private void generateNewSnack() { + Pos spawnPosition; + boolean isInRadius, isEmpty; + int counter = 0; + do { + if(counter > 200) return; + int x = this.rnd.nextInt(-this.radius+2, this.radius-2); + int z = this.rnd.nextInt(-this.radius+2, this.radius-2); + spawnPosition = new Pos(x, 1, z); + isInRadius = new Pos(x, 1, z).distance(0, 1, 0) < this.radius-2; + isEmpty = this.snacks.stream().noneMatch(entity -> entity.getPosition().sameBlock(x, 1, z)); + counter++; + } while (!(isEmpty && isInRadius)); + + Entity snack = new Entity(EntityType.FALLING_BLOCK); + FallingBlockMeta meta = (FallingBlockMeta) snack.getEntityMeta(); + meta.setBlock(Block.CHORUS_FLOWER); + snack.setInstance(this); + snack.teleport(spawnPosition.add(0.5, 0, 0.5)); + this.snacks.add(snack); + } + @Override protected void onStart() { - this.gameInstances.forEach(((player, gameInstance) -> gameInstance.moveTurtle(player.getPosition().direction()))); -// this.gameInstances.forEach(((player, turtleGameInstance) -> turtleGameInstance.start())); + for (int i = 0; i < 3; i++) { + this.generateNewSnack(); + } } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index f3f673a..b47f82a 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -33,7 +33,7 @@ public class TurtleGameFactory implements GameFactory { @Override public Game manufacture(Room parent, Map> configuration) throws Exception { - return new TurtleGame(configuration.get("firstPerson").getAsBoolean()); + return new TurtleGame(configuration.get("firstPerson").getAsBoolean(), configuration.get("radius").getAsInt()); } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java deleted file mode 100644 index 438f8af..0000000 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/game/TurtleGameInstance.java +++ /dev/null @@ -1,62 +0,0 @@ -package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.game; - -import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; -import eu.mhsl.minenet.minigames.util.BatchUtil; -import net.minestom.server.coordinate.Pos; -import net.minestom.server.coordinate.Vec; -import net.minestom.server.entity.EntityCreature; -import net.minestom.server.entity.EntityType; -import net.minestom.server.instance.batch.AbsoluteBlockBatch; -import net.minestom.server.instance.block.Block; - -import java.awt.*; - -public class TurtleGameInstance { - private final StatelessGame instance; - private final Pos startPosition; - private final EntityCreature turtle = new EntityCreature(EntityType.TURTLE); - private double speed = 2; - - public TurtleGameInstance(StatelessGame instance, Pos startPosition) { - this.instance = instance; - this.startPosition = startPosition; - } - - public void moveTurtle(Vec direction) { - Vec targetDirection = direction.withY(0).normalize().mul(speed); - this.turtle.setVelocity(targetDirection); - } - - // TODO: kleine display entities, die rotieren und so -// public void generateNewSnack() { -// int z, x; -// do { -// z = random.nextInt(0, 66); -// x = random.nextInt(0, 44); -// } while (!this.instance.getBlock(this.startPosition.add(x, 1, z)).isAir()); -// } - - public void generate() { - AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); - - for (int z = -1; z < 66; z++) { - for (int x = -1; x < 44; x++) { - if(z < 0 || z >= 65 || x < 0 || x >= 43) { - batch.setBlock(this.startPosition.add(x, 1, z), Block.STONE); - batch.setBlock(this.startPosition.add(x, 2, z), Block.STONE_SLAB); - } - batch.setBlock(this.startPosition.add(x, 0, z), Block.SAND); - } - } - - BatchUtil.loadAndApplyBatch(batch, this.instance, () -> {}); - } - - public Pos getPlayerSpawnPosition() { - return this.startPosition.add(20, 1, 30); - } - - public EntityCreature getTurtle() { - return this.turtle; - } -} From f26c3a9e6d09e519da4745978219d22c6ab6583e Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 00:36:50 +0200 Subject: [PATCH 06/27] improved entity collision check while generating --- .../types/turtleGame/TurtleGame.java | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index bc4fbe7..71d073f 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -117,29 +117,36 @@ class TurtleGame extends StatelessGame { private void generateNewSnack() { Pos spawnPosition; - boolean isInRadius, isEmpty; + boolean isInRadius, collides; int counter = 0; - do { - if(counter > 200) return; - int x = this.rnd.nextInt(-this.radius+2, this.radius-2); - int z = this.rnd.nextInt(-this.radius+2, this.radius-2); - spawnPosition = new Pos(x, 1, z); - isInRadius = new Pos(x, 1, z).distance(0, 1, 0) < this.radius-2; - isEmpty = this.snacks.stream().noneMatch(entity -> entity.getPosition().sameBlock(x, 1, z)); - counter++; - } while (!(isEmpty && isInRadius)); - Entity snack = new Entity(EntityType.FALLING_BLOCK); FallingBlockMeta meta = (FallingBlockMeta) snack.getEntityMeta(); meta.setBlock(Block.CHORUS_FLOWER); snack.setInstance(this); - snack.teleport(spawnPosition.add(0.5, 0, 0.5)); + + do { + if(counter > 200) { + snack.remove(); + return; + } + int x = this.rnd.nextInt(-this.radius+2, this.radius-2); + int z = this.rnd.nextInt(-this.radius+2, this.radius-2); + spawnPosition = new Pos(x, 1, z).add(0.5, 0, 0.5); + Pos checkPosition = spawnPosition; + isInRadius = checkPosition.distance(0, 1, 0) < this.radius-3; + collides = this.getEntities().stream() + .filter(entity -> !entity.equals(snack)) + .anyMatch(entity -> snack.getBoundingBox().intersectBox(entity.getPosition().sub(checkPosition), entity.getBoundingBox())); + counter++; + } while (!isInRadius || collides); + + snack.teleport(spawnPosition); this.snacks.add(snack); } @Override protected void onStart() { - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 100; i++) { this.generateNewSnack(); } } From 2c92553a8a25f645c46f855da5f571f58b909e9e Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 13:15:57 +0200 Subject: [PATCH 07/27] added bombs --- .../types/turtleGame/TurtleGame.java | 97 ++++++++++++++----- .../types/turtleGame/TurtleGameFactory.java | 4 +- 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 71d073f..3b45fb7 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -7,10 +7,7 @@ import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; -import net.minestom.server.entity.Entity; -import net.minestom.server.entity.EntityCreature; -import net.minestom.server.entity.EntityType; -import net.minestom.server.entity.Player; +import net.minestom.server.entity.*; import net.minestom.server.entity.attribute.Attribute; import net.minestom.server.entity.metadata.other.FallingBlockMeta; import net.minestom.server.event.player.PlayerTickEvent; @@ -18,20 +15,21 @@ import net.minestom.server.instance.block.Block; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.CompletableFuture; class TurtleGame extends StatelessGame { - private final boolean firstPerson; private final int radius; private final Map turtlePlayerMap = new WeakHashMap<>(); + private final Map scoreMap = new WeakHashMap<>(); private final ArrayList snacks = new ArrayList<>(); - private final double speed = 2; + private final ArrayList bombs = new ArrayList<>(); + private double speed = 2; - public TurtleGame(boolean firstPerson, int radius) { + public TurtleGame(int radius) { super(Dimension.OVERWORLD.key, "Turtle Game", new PointsWinScore()); - this.firstPerson = firstPerson; this.radius = radius; this.eventNode() @@ -60,20 +58,39 @@ class TurtleGame extends StatelessGame { } protected void onPlayerTick(@NotNull PlayerTickEvent event) { - EntityCreature turtle = this.turtlePlayerMap.get(event.getPlayer()); - turtle.teleport(turtle.getPosition().withView(event.getPlayer().getPosition())); - Vec direction = event.getPlayer().getPosition().direction(); + Player p = event.getPlayer(); + if(p.getGameMode() == GameMode.SPECTATOR) return; + EntityCreature turtle = this.turtlePlayerMap.get(p); + turtle.teleport(turtle.getPosition().withView(p.getPosition())); + Vec direction = p.getPosition().direction(); if(this.isRunning()) { Vec targetDirection = direction.withY(0).normalize().mul(this.speed); turtle.setVelocity(targetDirection); - List hit = this.snacks.stream() + List hitSnacks = this.snacks.stream() .filter(snack -> snack.getBoundingBox().intersectBox(turtle.getPosition().sub(snack.getPosition()), turtle.getBoundingBox())) .toList(); - hit.forEach(snack -> { + List hitBombs = this.bombs.stream() + .filter(bomb -> bomb.getBoundingBox().intersectBox(turtle.getPosition().sub(bomb.getPosition()), turtle.getBoundingBox())) + .toList(); + + hitSnacks.forEach(snack -> { this.snacks.remove(snack); snack.remove(); this.generateNewSnack(); + this.scoreMap.put(p, this.scoreMap.get(p) + 1); + }); + hitBombs.forEach(bomb -> { + p.setGameMode(GameMode.SPECTATOR); + p.setFlying(true); + turtle.removePassenger(p); + turtle.remove(); + turtle.kill(); + this.bombs.remove(bomb); + bomb.remove(); + this.generateNewBomb(); + this.getScore().insertResult(p, this.scoreMap.get(p)); + this.speed += 0.5; }); } } @@ -86,6 +103,7 @@ class TurtleGame extends StatelessGame { EntityCreature turtle = new EntityCreature(EntityType.TURTLE); this.turtlePlayerMap.put(p, turtle); } + this.scoreMap.putIfAbsent(p, 0); EntityCreature turtle = this.turtlePlayerMap.get(p); MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { @@ -116,18 +134,46 @@ class TurtleGame extends StatelessGame { } private void generateNewSnack() { - Pos spawnPosition; - boolean isInRadius, collides; - int counter = 0; Entity snack = new Entity(EntityType.FALLING_BLOCK); FallingBlockMeta meta = (FallingBlockMeta) snack.getEntityMeta(); - meta.setBlock(Block.CHORUS_FLOWER); + meta.setBlock(Block.SUNFLOWER.withProperty("half", "upper")); snack.setInstance(this); + Pos spawnPosition = this.newSpawnPosition(snack); + if(spawnPosition == null) { + snack.remove(); + return; + } + snack.teleport(spawnPosition); + this.snacks.add(snack); + } + private void generateNewBomb() { + Entity bomb = new Entity(EntityType.FALLING_BLOCK); + FallingBlockMeta meta = (FallingBlockMeta) bomb.getEntityMeta(); + meta.setBlock(Block.TNT); + bomb.setInstance(this); + Pos spawnPosition = this.newSpawnPosition(bomb, 2); + if(spawnPosition == null) { + bomb.remove(); + return; + } + bomb.teleport(spawnPosition); + this.bombs.add(bomb); + } + + @Nullable + private Pos newSpawnPosition(Entity entity) { + return this.newSpawnPosition(entity, 0); + } + + @Nullable + private Pos newSpawnPosition(Entity entity, double border) { + Pos spawnPosition; + int counter = 0; + boolean isInRadius, collides; do { if(counter > 200) { - snack.remove(); - return; + return null; } int x = this.rnd.nextInt(-this.radius+2, this.radius-2); int z = this.rnd.nextInt(-this.radius+2, this.radius-2); @@ -135,19 +181,20 @@ class TurtleGame extends StatelessGame { Pos checkPosition = spawnPosition; isInRadius = checkPosition.distance(0, 1, 0) < this.radius-3; collides = this.getEntities().stream() - .filter(entity -> !entity.equals(snack)) - .anyMatch(entity -> snack.getBoundingBox().intersectBox(entity.getPosition().sub(checkPosition), entity.getBoundingBox())); + .filter(e -> !e.equals(entity)) + .anyMatch(e -> entity.getBoundingBox().growSymmetrically(border, border, border).intersectBox(e.getPosition().sub(checkPosition), e.getBoundingBox())); counter++; } while (!isInRadius || collides); - - snack.teleport(spawnPosition); - this.snacks.add(snack); + return spawnPosition; } @Override protected void onStart() { - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 10; i++) { this.generateNewSnack(); } + for (int i = 0; i < 5; i++) { + this.generateNewBomb(); + } } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index b47f82a..ffbe591 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -4,7 +4,6 @@ import eu.mhsl.minenet.minigames.instance.game.Game; import eu.mhsl.minenet.minigames.instance.game.stateless.config.ConfigManager; import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option; -import eu.mhsl.minenet.minigames.instance.game.stateless.config.common.BoolOption; import eu.mhsl.minenet.minigames.instance.game.stateless.config.common.NumericOption; import eu.mhsl.minenet.minigames.instance.room.Room; import eu.mhsl.minenet.minigames.message.component.TranslatedComponent; @@ -27,13 +26,12 @@ public class TurtleGameFactory implements GameFactory { @Override public ConfigManager configuration() { return new ConfigManager() - .addOption(new BoolOption("firstPerson", Material.SPYGLASS, TranslatedComponent.byId("game_TurtleGame#firstPerson"))) .addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 10, 20, 30, 40)); } @Override public Game manufacture(Room parent, Map> configuration) throws Exception { - return new TurtleGame(configuration.get("firstPerson").getAsBoolean(), configuration.get("radius").getAsInt()); + return new TurtleGame(configuration.get("radius").getAsInt()); } @Override From 8bd0ab1974d9a270c5c8fb8c2cb25180ddae0a09 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 13:39:57 +0200 Subject: [PATCH 08/27] fixed error after game ends --- .../types/turtleGame/TurtleGame.java | 22 +++++++++++++------ .../types/turtleGame/TurtleGameFactory.java | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 3b45fb7..1272b43 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -88,7 +88,7 @@ class TurtleGame extends StatelessGame { turtle.kill(); this.bombs.remove(bomb); bomb.remove(); - this.generateNewBomb(); + this.generateNewBomb(2); this.getScore().insertResult(p, this.scoreMap.get(p)); this.speed += 0.5; }); @@ -133,6 +133,12 @@ class TurtleGame extends StatelessGame { return new Pos(x, 1, z).withLookAt(new Pos(0, 0, 0)); } + private void generateNewSnack(int count) { + for (int i = 0; i < count; i++) { + this.generateNewSnack(); + } + } + private void generateNewSnack() { Entity snack = new Entity(EntityType.FALLING_BLOCK); FallingBlockMeta meta = (FallingBlockMeta) snack.getEntityMeta(); @@ -147,6 +153,12 @@ class TurtleGame extends StatelessGame { this.snacks.add(snack); } + private void generateNewBomb(int count) { + for (int i = 0; i < count; i++) { + this.generateNewBomb(); + } + } + private void generateNewBomb() { Entity bomb = new Entity(EntityType.FALLING_BLOCK); FallingBlockMeta meta = (FallingBlockMeta) bomb.getEntityMeta(); @@ -190,11 +202,7 @@ class TurtleGame extends StatelessGame { @Override protected void onStart() { - for (int i = 0; i < 10; i++) { - this.generateNewSnack(); - } - for (int i = 0; i < 5; i++) { - this.generateNewBomb(); - } + this.generateNewSnack((int) Math.ceil(this.turtlePlayerMap.size() * 1.5)); + this.generateNewBomb((int) Math.ceil(this.snacks.size() * 0.5)); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index ffbe591..1913bb0 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -31,7 +31,7 @@ public class TurtleGameFactory implements GameFactory { @Override public Game manufacture(Room parent, Map> configuration) throws Exception { - return new TurtleGame(configuration.get("radius").getAsInt()); + return new TurtleGame(configuration.get("radius").getAsInt()).setParent(parent); } @Override From abf907af24a93677463413daf8ff2d3d99e4a766 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 13:49:49 +0200 Subject: [PATCH 09/27] added todos --- .../instance/game/stateless/types/turtleGame/TurtleGame.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 1272b43..34ed183 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -20,6 +20,8 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.CompletableFuture; +// TODO: Sound Effects, Partikel und Info für Score + class TurtleGame extends StatelessGame { private final int radius; private final Map turtlePlayerMap = new WeakHashMap<>(); @@ -27,6 +29,7 @@ class TurtleGame extends StatelessGame { private final ArrayList snacks = new ArrayList<>(); private final ArrayList bombs = new ArrayList<>(); private double speed = 2; + private double maxSpeed = 10; public TurtleGame(int radius) { super(Dimension.OVERWORLD.key, "Turtle Game", new PointsWinScore()); @@ -90,6 +93,7 @@ class TurtleGame extends StatelessGame { bomb.remove(); this.generateNewBomb(2); this.getScore().insertResult(p, this.scoreMap.get(p)); + // TODO: Speed in Einstellungen anpassbar machen und je nach Spieleranzahl erhöhen this.speed += 0.5; }); } From 382d85060543151e2b5eeb5ac6b6168683ced542 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 14:03:44 +0200 Subject: [PATCH 10/27] added better speed mechanic --- .../game/stateless/types/turtleGame/TurtleGame.java | 11 ++++++----- .../stateless/types/turtleGame/TurtleGameFactory.java | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 34ed183..0b7f781 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -28,12 +28,14 @@ class TurtleGame extends StatelessGame { private final Map scoreMap = new WeakHashMap<>(); private final ArrayList snacks = new ArrayList<>(); private final ArrayList bombs = new ArrayList<>(); - private double speed = 2; - private double maxSpeed = 10; + private double speed; + private final double maxSpeedIncrease; - public TurtleGame(int radius) { + public TurtleGame(int radius, int startSpeed) { super(Dimension.OVERWORLD.key, "Turtle Game", new PointsWinScore()); this.radius = radius; + this.speed = startSpeed; + this.maxSpeedIncrease = (double) this.radius / 4; this.eventNode() .addListener(PlayerTickEvent.class, this::onPlayerTick); @@ -93,8 +95,7 @@ class TurtleGame extends StatelessGame { bomb.remove(); this.generateNewBomb(2); this.getScore().insertResult(p, this.scoreMap.get(p)); - // TODO: Speed in Einstellungen anpassbar machen und je nach Spieleranzahl erhöhen - this.speed += 0.5; + this.speed += this.maxSpeedIncrease / this.getPlayers().size(); }); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index 1913bb0..f5194f0 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -26,12 +26,13 @@ public class TurtleGameFactory implements GameFactory { @Override public ConfigManager configuration() { return new ConfigManager() - .addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 10, 20, 30, 40)); + .addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 10, 20, 30, 40)) + .addOption(new NumericOption("startSpeed", Material.LEATHER_BOOTS, TranslatedComponent.byId("game_TurtleGame#startSpeed"), 2, 4, 6)); } @Override public Game manufacture(Room parent, Map> configuration) throws Exception { - return new TurtleGame(configuration.get("radius").getAsInt()).setParent(parent); + return new TurtleGame(configuration.get("radius").getAsInt(), configuration.get("startSpeed").getAsInt()).setParent(parent); } @Override From 2a6f2f2a44e8834afbf46794aa7a42fcc7d1cd9f Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 15:39:19 +0200 Subject: [PATCH 11/27] added particle effects and sounds --- .../types/turtleGame/TurtleGame.java | 74 ++++++++++++------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 0b7f781..e14476b 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -3,7 +3,7 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; import eu.mhsl.minenet.minigames.score.PointsWinScore; -import net.kyori.adventure.text.Component; +import net.kyori.adventure.sound.Sound; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; @@ -14,13 +14,16 @@ import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.instance.block.Block; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.network.packet.server.play.ParticlePacket; +import net.minestom.server.particle.Particle; +import net.minestom.server.sound.SoundEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.CompletableFuture; -// TODO: Sound Effects, Partikel und Info für Score +// TODO: Info für Score class TurtleGame extends StatelessGame { private final int radius; @@ -28,6 +31,7 @@ class TurtleGame extends StatelessGame { private final Map scoreMap = new WeakHashMap<>(); private final ArrayList snacks = new ArrayList<>(); private final ArrayList bombs = new ArrayList<>(); + private final Block snackBlock = Block.SUNFLOWER.withProperty("half", "upper"); private double speed; private final double maxSpeedIncrease; @@ -72,38 +76,52 @@ class TurtleGame extends StatelessGame { Vec targetDirection = direction.withY(0).normalize().mul(this.speed); turtle.setVelocity(targetDirection); - List hitSnacks = this.snacks.stream() + this.snacks.stream() .filter(snack -> snack.getBoundingBox().intersectBox(turtle.getPosition().sub(snack.getPosition()), turtle.getBoundingBox())) - .toList(); - List hitBombs = this.bombs.stream() + .toList() + .forEach(snack -> { + this.eat(p, snack); + this.generateNewSnack(); + if(this.scoreMap.values().stream().mapToInt(Integer::intValue).sum() % 3 == 0) this.generateNewBomb(); + }); + this.bombs.stream() .filter(bomb -> bomb.getBoundingBox().intersectBox(turtle.getPosition().sub(bomb.getPosition()), turtle.getBoundingBox())) - .toList(); - - hitSnacks.forEach(snack -> { - this.snacks.remove(snack); - snack.remove(); - this.generateNewSnack(); - this.scoreMap.put(p, this.scoreMap.get(p) + 1); - }); - hitBombs.forEach(bomb -> { - p.setGameMode(GameMode.SPECTATOR); - p.setFlying(true); - turtle.removePassenger(p); - turtle.remove(); - turtle.kill(); - this.bombs.remove(bomb); - bomb.remove(); - this.generateNewBomb(2); - this.getScore().insertResult(p, this.scoreMap.get(p)); - this.speed += this.maxSpeedIncrease / this.getPlayers().size(); - }); + .toList() + .forEach(bomb -> { + this.explode(p, bomb); + this.generateNewBomb(2); + this.speed += this.maxSpeedIncrease / this.getPlayers().size(); + }); } } + protected void eat(Player p, Entity snack) { + p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EAT, Sound.Source.MASTER, 1f, 1f), snack.getPosition()); + Material snackMaterial = this.snackBlock.registry().material(); + if(snackMaterial == null) snackMaterial = Material.DIRT; + p.sendPacket(new ParticlePacket(Particle.ITEM.withItem(ItemStack.of(snackMaterial)), p.getPosition(), new Pos(0.5, 0.5, 0.5), 0, 8)); + this.snacks.remove(snack); + snack.remove(); + this.scoreMap.put(p, this.scoreMap.get(p) + 1); + } + + protected void explode(Player p, Entity bomb) { + EntityCreature turtle = this.turtlePlayerMap.get(p); + p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.MASTER, 2f, 1f), bomb.getPosition()); + p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.MASTER, 2f, 1f), bomb.getPosition()); + p.sendPacket(new ParticlePacket(Particle.EXPLOSION, p.getPosition(), new Pos(0.5, 0.5, 0.5), 0, 8)); + p.setGameMode(GameMode.SPECTATOR); + p.setFlying(true); + turtle.removePassenger(p); + turtle.remove(); + turtle.kill(); + this.getScore().insertResult(p, this.scoreMap.get(p)); + this.bombs.remove(bomb); + bomb.remove(); + } + @Override protected boolean onPlayerJoin(Player p) { - p.getInventory().setItemStack(0, ItemStack.builder(Material.BARRIER).customName(Component.text("Reset Snack")).build()); - if(this.turtlePlayerMap.get(p) == null) { EntityCreature turtle = new EntityCreature(EntityType.TURTLE); this.turtlePlayerMap.put(p, turtle); @@ -147,7 +165,7 @@ class TurtleGame extends StatelessGame { private void generateNewSnack() { Entity snack = new Entity(EntityType.FALLING_BLOCK); FallingBlockMeta meta = (FallingBlockMeta) snack.getEntityMeta(); - meta.setBlock(Block.SUNFLOWER.withProperty("half", "upper")); + meta.setBlock(this.snackBlock.withProperty("half", "upper")); snack.setInstance(this); Pos spawnPosition = this.newSpawnPosition(snack); if(spawnPosition == null) { From 2fac287e1e1118f792bd5f0cf9930b6dbff95182 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 16:11:10 +0200 Subject: [PATCH 12/27] added sidebar --- .../types/turtleGame/TurtleGame.java | 29 +++++++++++++++++-- .../types/turtleGame/TurtleGameFactory.java | 2 +- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index e14476b..0d32701 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -4,6 +4,8 @@ import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; import eu.mhsl.minenet.minigames.score.PointsWinScore; import net.kyori.adventure.sound.Sound; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; @@ -16,6 +18,7 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.network.packet.server.play.ParticlePacket; import net.minestom.server.particle.Particle; +import net.minestom.server.scoreboard.Sidebar; import net.minestom.server.sound.SoundEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,12 +26,11 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.CompletableFuture; -// TODO: Info für Score - class TurtleGame extends StatelessGame { private final int radius; private final Map turtlePlayerMap = new WeakHashMap<>(); private final Map scoreMap = new WeakHashMap<>(); + private final Map sidebarMap = new HashMap<>(); private final ArrayList snacks = new ArrayList<>(); private final ArrayList bombs = new ArrayList<>(); private final Block snackBlock = Block.SUNFLOWER.withProperty("half", "upper"); @@ -91,6 +93,7 @@ class TurtleGame extends StatelessGame { this.explode(p, bomb); this.generateNewBomb(2); this.speed += this.maxSpeedIncrease / this.getPlayers().size(); + this.sidebarMap.values().forEach(sidebar -> sidebar.updateLineScore("1", (int) this.speed)); }); } } @@ -103,6 +106,7 @@ class TurtleGame extends StatelessGame { this.snacks.remove(snack); snack.remove(); this.scoreMap.put(p, this.scoreMap.get(p) + 1); + this.sidebarMap.get(p).updateLineScore("0", this.scoreMap.get(p)); } protected void explode(Player p, Entity bomb) { @@ -118,6 +122,7 @@ class TurtleGame extends StatelessGame { this.getScore().insertResult(p, this.scoreMap.get(p)); this.bombs.remove(bomb); bomb.remove(); + this.sidebarMap.values().forEach(sidebar -> sidebar.updateLineScore("2", (int) this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).count())); } @Override @@ -127,6 +132,25 @@ class TurtleGame extends StatelessGame { this.turtlePlayerMap.put(p, turtle); } this.scoreMap.putIfAbsent(p, 0); + this.sidebarMap.putIfAbsent(p, new Sidebar(Component.text("Info:").color(NamedTextColor.GOLD))); + Sidebar sidebar = this.sidebarMap.get(p); + sidebar.createLine(new Sidebar.ScoreboardLine( + "0", + Component.text("Score: ").color(NamedTextColor.DARK_GREEN), + this.scoreMap.get(p) + )); + sidebar.createLine(new Sidebar.ScoreboardLine( + "1", + Component.text("Speed: ").color(NamedTextColor.DARK_BLUE), + (int) this.speed + )); + sidebar.createLine(new Sidebar.ScoreboardLine( + "2", + Component.text("Players: ").color(NamedTextColor.AQUA), + this.turtlePlayerMap.size() + )); + sidebar.addViewer(p); + this.sidebarMap.values().forEach(bar -> bar.updateLineScore("2", this.turtlePlayerMap.size())); EntityCreature turtle = this.turtlePlayerMap.get(p); MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { @@ -143,6 +167,7 @@ class TurtleGame extends StatelessGame { protected void onPlayerLeave(Player p) { EntityCreature turtle = this.turtlePlayerMap.get(p); turtle.remove(); + this.sidebarMap.get(p).removeViewer(p); } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index f5194f0..014260f 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -27,7 +27,7 @@ public class TurtleGameFactory implements GameFactory { public ConfigManager configuration() { return new ConfigManager() .addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 10, 20, 30, 40)) - .addOption(new NumericOption("startSpeed", Material.LEATHER_BOOTS, TranslatedComponent.byId("game_TurtleGame#startSpeed"), 2, 4, 6)); + .addOption(new NumericOption("startSpeed", Material.LEATHER_BOOTS, TranslatedComponent.byId("game_TurtleGame#startSpeed"), 2, 4, 6, 8)); } @Override From 61aa7543be170dd727b60e499713faf59422105b Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 16:29:03 +0200 Subject: [PATCH 13/27] improved sidebar (ordered and colored) --- .../types/turtleGame/TurtleGame.java | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 0d32701..aaefdca 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -84,7 +84,7 @@ class TurtleGame extends StatelessGame { .forEach(snack -> { this.eat(p, snack); this.generateNewSnack(); - if(this.scoreMap.values().stream().mapToInt(Integer::intValue).sum() % 3 == 0) this.generateNewBomb(); + if(this.scoreMap.values().stream().mapToInt(Integer::intValue).sum() % 4 == 0) this.generateNewBomb(); }); this.bombs.stream() .filter(bomb -> bomb.getBoundingBox().intersectBox(turtle.getPosition().sub(bomb.getPosition()), turtle.getBoundingBox())) @@ -93,7 +93,9 @@ class TurtleGame extends StatelessGame { this.explode(p, bomb); this.generateNewBomb(2); this.speed += this.maxSpeedIncrease / this.getPlayers().size(); - this.sidebarMap.values().forEach(sidebar -> sidebar.updateLineScore("1", (int) this.speed)); + this.sidebarMap.values().forEach(sidebar -> sidebar.updateLineContent("1", + Component.text("Speed: ").color(NamedTextColor.BLUE) + .append(Component.text(String.format("%3d", (int) this.speed)).color(NamedTextColor.RED)))); }); } } @@ -106,7 +108,9 @@ class TurtleGame extends StatelessGame { this.snacks.remove(snack); snack.remove(); this.scoreMap.put(p, this.scoreMap.get(p) + 1); - this.sidebarMap.get(p).updateLineScore("0", this.scoreMap.get(p)); + this.sidebarMap.get(p).updateLineContent("0", + Component.text("Score: ").color(NamedTextColor.GREEN) + .append(Component.text(String.format("%3d", this.scoreMap.get(p))).color(NamedTextColor.RED))); } protected void explode(Player p, Entity bomb) { @@ -122,7 +126,9 @@ class TurtleGame extends StatelessGame { this.getScore().insertResult(p, this.scoreMap.get(p)); this.bombs.remove(bomb); bomb.remove(); - this.sidebarMap.values().forEach(sidebar -> sidebar.updateLineScore("2", (int) this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).count())); + this.sidebarMap.values().forEach(sidebar -> sidebar.updateLineContent("2", + Component.text("Players: ").color(NamedTextColor.AQUA) + .append(Component.text(String.format("%3d", (int) this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).count())).color(NamedTextColor.RED)))); } @Override @@ -136,21 +142,29 @@ class TurtleGame extends StatelessGame { Sidebar sidebar = this.sidebarMap.get(p); sidebar.createLine(new Sidebar.ScoreboardLine( "0", - Component.text("Score: ").color(NamedTextColor.DARK_GREEN), - this.scoreMap.get(p) + Component.text("Score: ").color(NamedTextColor.GREEN) + .append(Component.text(String.format("%3d", this.scoreMap.get(p))).color(NamedTextColor.RED)), + 3, + Sidebar.NumberFormat.blank() )); sidebar.createLine(new Sidebar.ScoreboardLine( "1", - Component.text("Speed: ").color(NamedTextColor.DARK_BLUE), - (int) this.speed + Component.text("Speed: ").color(NamedTextColor.BLUE) + .append(Component.text(String.format("%3d", (int) this.speed)).color(NamedTextColor.RED)), + 2, + Sidebar.NumberFormat.blank() )); sidebar.createLine(new Sidebar.ScoreboardLine( "2", - Component.text("Players: ").color(NamedTextColor.AQUA), - this.turtlePlayerMap.size() + Component.text("Players: ").color(NamedTextColor.AQUA) + .append(Component.text(String.format("%3d", (int) this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).count())).color(NamedTextColor.RED)), + 1, + Sidebar.NumberFormat.blank() )); sidebar.addViewer(p); - this.sidebarMap.values().forEach(bar -> bar.updateLineScore("2", this.turtlePlayerMap.size())); + this.sidebarMap.values().forEach(bar -> bar.updateLineContent("2", + Component.text("Players: ").color(NamedTextColor.AQUA) + .append(Component.text(String.format("%3d", (int) this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).count())).color(NamedTextColor.RED)))); EntityCreature turtle = this.turtlePlayerMap.get(p); MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { From 75314748da3183db426c55e4759ce0efd8c78891 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 4 Oct 2025 18:32:27 +0200 Subject: [PATCH 14/27] removed sidebar, added names for items --- .../types/turtleGame/TurtleGame.java | 56 +++++-------------- .../types/turtleGame/TurtleGameFactory.java | 2 +- 2 files changed, 14 insertions(+), 44 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index aaefdca..015b920 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -6,6 +6,7 @@ import eu.mhsl.minenet.minigames.score.PointsWinScore; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; @@ -18,7 +19,6 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import net.minestom.server.network.packet.server.play.ParticlePacket; import net.minestom.server.particle.Particle; -import net.minestom.server.scoreboard.Sidebar; import net.minestom.server.sound.SoundEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,18 +30,15 @@ class TurtleGame extends StatelessGame { private final int radius; private final Map turtlePlayerMap = new WeakHashMap<>(); private final Map scoreMap = new WeakHashMap<>(); - private final Map sidebarMap = new HashMap<>(); private final ArrayList snacks = new ArrayList<>(); private final ArrayList bombs = new ArrayList<>(); private final Block snackBlock = Block.SUNFLOWER.withProperty("half", "upper"); private double speed; - private final double maxSpeedIncrease; public TurtleGame(int radius, int startSpeed) { super(Dimension.OVERWORLD.key, "Turtle Game", new PointsWinScore()); this.radius = radius; this.speed = startSpeed; - this.maxSpeedIncrease = (double) this.radius / 4; this.eventNode() .addListener(PlayerTickEvent.class, this::onPlayerTick); @@ -84,7 +81,10 @@ class TurtleGame extends StatelessGame { .forEach(snack -> { this.eat(p, snack); this.generateNewSnack(); - if(this.scoreMap.values().stream().mapToInt(Integer::intValue).sum() % 4 == 0) this.generateNewBomb(); + if(this.scoreMap.values().stream().mapToInt(Integer::intValue).sum() % 4 == 0) { + this.generateNewBomb(); + this.speed += 0.4; + } }); this.bombs.stream() .filter(bomb -> bomb.getBoundingBox().intersectBox(turtle.getPosition().sub(bomb.getPosition()), turtle.getBoundingBox())) @@ -92,10 +92,7 @@ class TurtleGame extends StatelessGame { .forEach(bomb -> { this.explode(p, bomb); this.generateNewBomb(2); - this.speed += this.maxSpeedIncrease / this.getPlayers().size(); - this.sidebarMap.values().forEach(sidebar -> sidebar.updateLineContent("1", - Component.text("Speed: ").color(NamedTextColor.BLUE) - .append(Component.text(String.format("%3d", (int) this.speed)).color(NamedTextColor.RED)))); + this.speed += 0.3; }); } } @@ -108,9 +105,7 @@ class TurtleGame extends StatelessGame { this.snacks.remove(snack); snack.remove(); this.scoreMap.put(p, this.scoreMap.get(p) + 1); - this.sidebarMap.get(p).updateLineContent("0", - Component.text("Score: ").color(NamedTextColor.GREEN) - .append(Component.text(String.format("%3d", this.scoreMap.get(p))).color(NamedTextColor.RED))); + p.setLevel(this.scoreMap.get(p)); } protected void explode(Player p, Entity bomb) { @@ -126,9 +121,6 @@ class TurtleGame extends StatelessGame { this.getScore().insertResult(p, this.scoreMap.get(p)); this.bombs.remove(bomb); bomb.remove(); - this.sidebarMap.values().forEach(sidebar -> sidebar.updateLineContent("2", - Component.text("Players: ").color(NamedTextColor.AQUA) - .append(Component.text(String.format("%3d", (int) this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).count())).color(NamedTextColor.RED)))); } @Override @@ -138,33 +130,7 @@ class TurtleGame extends StatelessGame { this.turtlePlayerMap.put(p, turtle); } this.scoreMap.putIfAbsent(p, 0); - this.sidebarMap.putIfAbsent(p, new Sidebar(Component.text("Info:").color(NamedTextColor.GOLD))); - Sidebar sidebar = this.sidebarMap.get(p); - sidebar.createLine(new Sidebar.ScoreboardLine( - "0", - Component.text("Score: ").color(NamedTextColor.GREEN) - .append(Component.text(String.format("%3d", this.scoreMap.get(p))).color(NamedTextColor.RED)), - 3, - Sidebar.NumberFormat.blank() - )); - sidebar.createLine(new Sidebar.ScoreboardLine( - "1", - Component.text("Speed: ").color(NamedTextColor.BLUE) - .append(Component.text(String.format("%3d", (int) this.speed)).color(NamedTextColor.RED)), - 2, - Sidebar.NumberFormat.blank() - )); - sidebar.createLine(new Sidebar.ScoreboardLine( - "2", - Component.text("Players: ").color(NamedTextColor.AQUA) - .append(Component.text(String.format("%3d", (int) this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).count())).color(NamedTextColor.RED)), - 1, - Sidebar.NumberFormat.blank() - )); - sidebar.addViewer(p); - this.sidebarMap.values().forEach(bar -> bar.updateLineContent("2", - Component.text("Players: ").color(NamedTextColor.AQUA) - .append(Component.text(String.format("%3d", (int) this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).count())).color(NamedTextColor.RED)))); + p.setLevel(this.scoreMap.get(p)); EntityCreature turtle = this.turtlePlayerMap.get(p); MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { @@ -181,7 +147,6 @@ class TurtleGame extends StatelessGame { protected void onPlayerLeave(Player p) { EntityCreature turtle = this.turtlePlayerMap.get(p); turtle.remove(); - this.sidebarMap.get(p).removeViewer(p); } @Override @@ -205,6 +170,9 @@ class TurtleGame extends StatelessGame { Entity snack = new Entity(EntityType.FALLING_BLOCK); FallingBlockMeta meta = (FallingBlockMeta) snack.getEntityMeta(); meta.setBlock(this.snackBlock.withProperty("half", "upper")); + meta.setCustomName(Component.text("Snack").color(NamedTextColor.WHITE)); + meta.setCustomNameVisible(true); + meta.setHasGlowingEffect(true); snack.setInstance(this); Pos spawnPosition = this.newSpawnPosition(snack); if(spawnPosition == null) { @@ -225,6 +193,8 @@ class TurtleGame extends StatelessGame { Entity bomb = new Entity(EntityType.FALLING_BLOCK); FallingBlockMeta meta = (FallingBlockMeta) bomb.getEntityMeta(); meta.setBlock(Block.TNT); + meta.setCustomName(Component.text("Bomb").color(NamedTextColor.RED).decorate(TextDecoration.BOLD)); + meta.setCustomNameVisible(true); bomb.setInstance(this); Pos spawnPosition = this.newSpawnPosition(bomb, 2); if(spawnPosition == null) { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index 014260f..e91d47e 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -27,7 +27,7 @@ public class TurtleGameFactory implements GameFactory { public ConfigManager configuration() { return new ConfigManager() .addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 10, 20, 30, 40)) - .addOption(new NumericOption("startSpeed", Material.LEATHER_BOOTS, TranslatedComponent.byId("game_TurtleGame#startSpeed"), 2, 4, 6, 8)); + .addOption(new NumericOption("startSpeed", Material.LEATHER_BOOTS, TranslatedComponent.byId("game_TurtleGame#startSpeed"), 2, 4, 6, 8, 10)); } @Override From 39fb7f4956bd4a0c9c8fefd6f1cafe64b4378c1f Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 5 Oct 2025 00:13:56 +0200 Subject: [PATCH 15/27] added boost mechanic --- .../types/turtleGame/TurtleGame.java | 85 ++++++++------- .../types/turtleGame/gameObjects/Turtle.java | 103 ++++++++++++++++++ 2 files changed, 148 insertions(+), 40 deletions(-) create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 015b920..39699ed 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -2,6 +2,7 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.gameObjects.Turtle; import eu.mhsl.minenet.minigames.score.PointsWinScore; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; @@ -9,10 +10,10 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; -import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.*; -import net.minestom.server.entity.attribute.Attribute; import net.minestom.server.entity.metadata.other.FallingBlockMeta; +import net.minestom.server.event.player.PlayerStartSneakingEvent; +import net.minestom.server.event.player.PlayerStopSneakingEvent; import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.instance.block.Block; import net.minestom.server.item.ItemStack; @@ -28,20 +29,21 @@ import java.util.concurrent.CompletableFuture; class TurtleGame extends StatelessGame { private final int radius; - private final Map turtlePlayerMap = new WeakHashMap<>(); - private final Map scoreMap = new WeakHashMap<>(); + private final Map turtlePlayerMap = new WeakHashMap<>(); private final ArrayList snacks = new ArrayList<>(); private final ArrayList bombs = new ArrayList<>(); private final Block snackBlock = Block.SUNFLOWER.withProperty("half", "upper"); - private double speed; + private final double startSpeed; public TurtleGame(int radius, int startSpeed) { super(Dimension.OVERWORLD.key, "Turtle Game", new PointsWinScore()); this.radius = radius; - this.speed = startSpeed; + this.startSpeed = startSpeed; this.eventNode() - .addListener(PlayerTickEvent.class, this::onPlayerTick); + .addListener(PlayerTickEvent.class, this::onPlayerTick) + .addListener(PlayerStartSneakingEvent.class, this::onPlayerStartSneak) + .addListener(PlayerStopSneakingEvent.class, this::onPlayerStopSneak); } @Override @@ -65,38 +67,53 @@ class TurtleGame extends StatelessGame { } } + private void onPlayerStartSneak(@NotNull PlayerStartSneakingEvent event) { + Player p = event.getPlayer(); + this.turtlePlayerMap.get(p).boostSpeed(); + } + + private void onPlayerStopSneak(@NotNull PlayerStopSneakingEvent event) { + Player p = event.getPlayer(); + this.turtlePlayerMap.get(p).cancelBoost(); + } + protected void onPlayerTick(@NotNull PlayerTickEvent event) { Player p = event.getPlayer(); if(p.getGameMode() == GameMode.SPECTATOR) return; - EntityCreature turtle = this.turtlePlayerMap.get(p); - turtle.teleport(turtle.getPosition().withView(p.getPosition())); - Vec direction = p.getPosition().direction(); + Turtle turtle = this.turtlePlayerMap.get(p); + turtle.adaptView(); if(this.isRunning()) { - Vec targetDirection = direction.withY(0).normalize().mul(this.speed); - turtle.setVelocity(targetDirection); - + turtle.move(); this.snacks.stream() - .filter(snack -> snack.getBoundingBox().intersectBox(turtle.getPosition().sub(snack.getPosition()), turtle.getBoundingBox())) + .filter(turtle::checkCollisionWithEntity) .toList() .forEach(snack -> { this.eat(p, snack); this.generateNewSnack(); - if(this.scoreMap.values().stream().mapToInt(Integer::intValue).sum() % 4 == 0) { + if(this.turtlePlayerMap.get(p).getScore() % 5 == 0) { this.generateNewBomb(); - this.speed += 0.4; + this.addSpeed(0.4, p); } }); this.bombs.stream() - .filter(bomb -> bomb.getBoundingBox().intersectBox(turtle.getPosition().sub(bomb.getPosition()), turtle.getBoundingBox())) + .filter(turtle::checkCollisionWithEntity) .toList() .forEach(bomb -> { this.explode(p, bomb); this.generateNewBomb(2); - this.speed += 0.3; + this.addGlobalSpeed(0.3); }); } } + protected void addSpeed(double amount, Player p) { + this.turtlePlayerMap.get(p).addSpeed(amount); + } + + protected void addGlobalSpeed(double amount) { + this.turtlePlayerMap.values().forEach(turtle -> turtle.addSpeed(amount)); + } + protected void eat(Player p, Entity snack) { p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EAT, Sound.Source.MASTER, 1f, 1f), snack.getPosition()); Material snackMaterial = this.snackBlock.registry().material(); @@ -104,48 +121,35 @@ class TurtleGame extends StatelessGame { p.sendPacket(new ParticlePacket(Particle.ITEM.withItem(ItemStack.of(snackMaterial)), p.getPosition(), new Pos(0.5, 0.5, 0.5), 0, 8)); this.snacks.remove(snack); snack.remove(); - this.scoreMap.put(p, this.scoreMap.get(p) + 1); - p.setLevel(this.scoreMap.get(p)); + this.turtlePlayerMap.get(p).increaseScore(); } protected void explode(Player p, Entity bomb) { - EntityCreature turtle = this.turtlePlayerMap.get(p); + Turtle turtle = this.turtlePlayerMap.get(p); p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.MASTER, 2f, 1f), bomb.getPosition()); p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.MASTER, 2f, 1f), bomb.getPosition()); p.sendPacket(new ParticlePacket(Particle.EXPLOSION, p.getPosition(), new Pos(0.5, 0.5, 0.5), 0, 8)); p.setGameMode(GameMode.SPECTATOR); p.setFlying(true); - turtle.removePassenger(p); - turtle.remove(); - turtle.kill(); - this.getScore().insertResult(p, this.scoreMap.get(p)); + turtle.destroy(); + this.getScore().insertResult(p, this.turtlePlayerMap.get(p).getScore()); this.bombs.remove(bomb); bomb.remove(); } @Override protected boolean onPlayerJoin(Player p) { - if(this.turtlePlayerMap.get(p) == null) { - EntityCreature turtle = new EntityCreature(EntityType.TURTLE); - this.turtlePlayerMap.put(p, turtle); - } - this.scoreMap.putIfAbsent(p, 0); - p.setLevel(this.scoreMap.get(p)); - - EntityCreature turtle = this.turtlePlayerMap.get(p); - MinecraftServer.getSchedulerManager().scheduleNextTick(() -> { - turtle.setInstance(this); - turtle.teleport(p.getPosition()); - turtle.addPassenger(p); - turtle.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.15); - }); + this.turtlePlayerMap.putIfAbsent(p, new Turtle(p, this.startSpeed)); + p.setLevel(this.turtlePlayerMap.get(p).getScore()); + Turtle turtle = this.turtlePlayerMap.get(p); + MinecraftServer.getSchedulerManager().scheduleNextTick(turtle::spawnTurtle); return super.onPlayerJoin(p); } @Override protected void onPlayerLeave(Player p) { - EntityCreature turtle = this.turtlePlayerMap.get(p); + Turtle turtle = this.turtlePlayerMap.get(p); turtle.remove(); } @@ -236,5 +240,6 @@ class TurtleGame extends StatelessGame { protected void onStart() { this.generateNewSnack((int) Math.ceil(this.turtlePlayerMap.size() * 1.5)); this.generateNewBomb((int) Math.ceil(this.snacks.size() * 0.5)); + this.turtlePlayerMap.values().forEach(Turtle::startBoostRefill); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java new file mode 100644 index 0000000..e7f0434 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java @@ -0,0 +1,103 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.gameObjects; + +import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EntityCreature; +import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.Player; +import net.minestom.server.entity.attribute.Attribute; +import net.minestom.server.timer.Task; +import net.minestom.server.timer.TaskSchedule; + +public class Turtle extends EntityCreature { + private final Player player; + private int score = 0; + private double speed; + private final double boostSpeedAmount = 4; + private float boostChargeLevel = 0f; + private Task boostTask; + private Task boostRefillTask; + + public Turtle(Player player, double speed) { + super(EntityType.TURTLE); + this.player = player; + this.speed = speed; + + this.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.15); + this.getAttribute(Attribute.MAX_HEALTH).setBaseValue(1); + this.player.setExp(this.boostChargeLevel); + } + + public void spawnTurtle() { + this.setInstance(this.player.getInstance()); + this.teleport(this.player.getPosition()); + this.addPassenger(this.player); + } + + public void startBoostRefill() { + this.boostRefillTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> { + if(this.boostChargeLevel >= 1f) return; + this.boostChargeLevel = Math.min(1f, this.boostChargeLevel + 0.025f); + this.player.setExp(this.boostChargeLevel); + }, TaskSchedule.seconds(1), TaskSchedule.seconds(1)); + } + + public void destroy() { + this.removePassenger(this.player); + this.remove(); + this.kill(); + this.boostRefillTask.cancel(); + this.boostTask.cancel(); + } + + public void adaptView() { + this.teleport(this.getPosition().withView(this.player.getPosition().withPitch(this.getPosition().pitch()))); + Vec lookingVector = this.player.getPosition().direction().withY(0).mul(100); + this.lookAt(this.getPosition().add(lookingVector.asPosition())); + } + + public void move() { + this.adaptView(); + Vec direction = this.player.getPosition().direction(); + Vec movementVector = direction.withY(0).normalize().mul(this.speed); + this.setVelocity(movementVector); + } + + public boolean checkCollisionWithEntity(Entity other) { + return this.getBoundingBox().intersectBox(other.getPosition().sub(this.getPosition()), other.getBoundingBox()); + } + + public void boostSpeed() { + if(this.boostChargeLevel <= 0f) return; + this.speed += this.boostSpeedAmount; + this.boostTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> { + if(this.boostChargeLevel <= 0f) { + this.cancelBoost(); + return; + } + this.boostChargeLevel = Math.max(0f, this.boostChargeLevel - 0.025f); + System.out.println(this.boostChargeLevel); + this.player.setExp(this.boostChargeLevel); + }, TaskSchedule.millis(30), TaskSchedule.millis(30)); + } + + public void cancelBoost() { + if(!this.boostTask.isAlive()) return; + this.boostTask.cancel(); + this.speed -= this.boostSpeedAmount; + } + + public void addSpeed(double amount) { + this.speed += amount; + } + + public int getScore() { + return this.score; + } + + public void increaseScore() { + this.score += 1; + this.player.setLevel(this.score); + } +} From dece9c13b73ee21a12d1aa1cbe9a73b95f95fb19 Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 5 Oct 2025 00:19:37 +0200 Subject: [PATCH 16/27] added translations --- src/main/resources/lang/locales.map.csv | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/lang/locales.map.csv b/src/main/resources/lang/locales.map.csv index 46b4bb2..606d08b 100644 --- a/src/main/resources/lang/locales.map.csv +++ b/src/main/resources/lang/locales.map.csv @@ -143,3 +143,8 @@ description;Stay on the high ground to win!;Bleibe solange wie möglich auf der ns:game_Fastbridge#;; name;Fastbridge;Fastbridge description;Speedbridge to the other platform. The first one there wins!;Baue dich so schnell wie möglich zur anderen Plattform. Wer zuerst dort ist, gewinnt! +;; +ns:game_TurtleGame#;; +name;Turtle Game;Turtle Game +description;Eat snacks and dodge bombs to get the highest score!;Esse Snacks und weiche Bomben aus, um den höchsten Score zu erreichen! +startSpeed;Start Speed;Startgeschwindigkeit From 84de61388e3c6c73b03522c5dc1ab41cd081fdcd Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 5 Oct 2025 18:24:46 +0200 Subject: [PATCH 17/27] improved speed mechanic and bomb spawning, added countdown for last player --- .../types/turtleGame/TurtleGame.java | 38 ++++++++++++++----- .../types/turtleGame/gameObjects/Turtle.java | 17 ++++++--- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 39699ed..a34ebab 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -125,18 +125,26 @@ class TurtleGame extends StatelessGame { } protected void explode(Player p, Entity bomb) { - Turtle turtle = this.turtlePlayerMap.get(p); + this.letPlayerLoose(p); p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.MASTER, 2f, 1f), bomb.getPosition()); p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.MASTER, 2f, 1f), bomb.getPosition()); p.sendPacket(new ParticlePacket(Particle.EXPLOSION, p.getPosition(), new Pos(0.5, 0.5, 0.5), 0, 8)); - p.setGameMode(GameMode.SPECTATOR); - p.setFlying(true); - turtle.destroy(); - this.getScore().insertResult(p, this.turtlePlayerMap.get(p).getScore()); + if(this.getLeftPlayers().size() == 1) this.setTimeLimit(10); this.bombs.remove(bomb); bomb.remove(); } + protected void letPlayerLoose(Player p) { + p.setGameMode(GameMode.SPECTATOR); + p.setFlying(true); + this.turtlePlayerMap.get(p).destroy(); + this.getScore().insertResult(p, this.turtlePlayerMap.get(p).getScore()); + } + + protected List getLeftPlayers() { + return this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).toList(); + } + @Override protected boolean onPlayerJoin(Player p) { this.turtlePlayerMap.putIfAbsent(p, new Turtle(p, this.startSpeed)); @@ -200,7 +208,7 @@ class TurtleGame extends StatelessGame { meta.setCustomName(Component.text("Bomb").color(NamedTextColor.RED).decorate(TextDecoration.BOLD)); meta.setCustomNameVisible(true); bomb.setInstance(this); - Pos spawnPosition = this.newSpawnPosition(bomb, 2); + Pos spawnPosition = this.newSpawnPosition(bomb, false); if(spawnPosition == null) { bomb.remove(); return; @@ -211,11 +219,11 @@ class TurtleGame extends StatelessGame { @Nullable private Pos newSpawnPosition(Entity entity) { - return this.newSpawnPosition(entity, 0); + return this.newSpawnPosition(entity, true); } @Nullable - private Pos newSpawnPosition(Entity entity, double border) { + private Pos newSpawnPosition(Entity entity, boolean nearPlayers) { Pos spawnPosition; int counter = 0; boolean isInRadius, collides; @@ -227,10 +235,15 @@ class TurtleGame extends StatelessGame { int z = this.rnd.nextInt(-this.radius+2, this.radius-2); spawnPosition = new Pos(x, 1, z).add(0.5, 0, 0.5); Pos checkPosition = spawnPosition; - isInRadius = checkPosition.distance(0, 1, 0) < this.radius-3; + isInRadius = checkPosition.distance(0, 1, 0) < this.radius-2; collides = this.getEntities().stream() .filter(e -> !e.equals(entity)) - .anyMatch(e -> entity.getBoundingBox().growSymmetrically(border, border, border).intersectBox(e.getPosition().sub(checkPosition), e.getBoundingBox())); + .anyMatch(e -> entity.getBoundingBox().intersectBox(e.getPosition().sub(checkPosition), e.getBoundingBox())); + if(!collides && !nearPlayers) collides = this.turtlePlayerMap.values().stream() + .filter(turtle -> !turtle.equals(entity)) + .anyMatch(turtle -> entity.getBoundingBox() + .growSymmetrically(turtle.getBombBorder(), 1, turtle.getBombBorder()) + .intersectBox(turtle.getPosition().sub(checkPosition), turtle.getBoundingBox())); counter++; } while (!isInRadius || collides); return spawnPosition; @@ -242,4 +255,9 @@ class TurtleGame extends StatelessGame { this.generateNewBomb((int) Math.ceil(this.snacks.size() * 0.5)); this.turtlePlayerMap.values().forEach(Turtle::startBoostRefill); } + + @Override + protected void onStop() { + this.getLeftPlayers().forEach(this::letPlayerLoose); + } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java index e7f0434..7c75ef1 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java @@ -14,7 +14,7 @@ public class Turtle extends EntityCreature { private final Player player; private int score = 0; private double speed; - private final double boostSpeedAmount = 4; + private double boostSpeedMultiplier = 1; private float boostChargeLevel = 0f; private Task boostTask; private Task boostRefillTask; @@ -47,8 +47,8 @@ public class Turtle extends EntityCreature { this.removePassenger(this.player); this.remove(); this.kill(); - this.boostRefillTask.cancel(); - this.boostTask.cancel(); + if(this.boostRefillTask.isAlive()) this.boostRefillTask.cancel(); + if(this.boostTask.isAlive()) this.boostTask.cancel(); } public void adaptView() { @@ -60,7 +60,7 @@ public class Turtle extends EntityCreature { public void move() { this.adaptView(); Vec direction = this.player.getPosition().direction(); - Vec movementVector = direction.withY(0).normalize().mul(this.speed); + Vec movementVector = direction.withY(0).normalize().mul(this.speed * this.boostSpeedMultiplier); this.setVelocity(movementVector); } @@ -70,7 +70,7 @@ public class Turtle extends EntityCreature { public void boostSpeed() { if(this.boostChargeLevel <= 0f) return; - this.speed += this.boostSpeedAmount; + this.boostSpeedMultiplier = 3.5; this.boostTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> { if(this.boostChargeLevel <= 0f) { this.cancelBoost(); @@ -85,7 +85,7 @@ public class Turtle extends EntityCreature { public void cancelBoost() { if(!this.boostTask.isAlive()) return; this.boostTask.cancel(); - this.speed -= this.boostSpeedAmount; + this.boostSpeedMultiplier = 1; } public void addSpeed(double amount) { @@ -96,6 +96,11 @@ public class Turtle extends EntityCreature { return this.score; } + public double getBombBorder() { + // 1 bei speed 2; 2 bei speed 4; 4 bei speed 8 + return Math.clamp((this.speed * this.boostSpeedMultiplier) / 2, 1.5, 4); + } + public void increaseScore() { this.score += 1; this.player.setLevel(this.score); From ec76dd5c85c5cc463e94f53c63de5d3a1830f615 Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 6 Oct 2025 17:31:04 +0200 Subject: [PATCH 18/27] added boost charge when eating snacks --- .../game/stateless/types/turtleGame/TurtleGame.java | 2 +- .../stateless/types/turtleGame/gameObjects/Turtle.java | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index a34ebab..3146a3a 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -122,6 +122,7 @@ class TurtleGame extends StatelessGame { this.snacks.remove(snack); snack.remove(); this.turtlePlayerMap.get(p).increaseScore(); + this.turtlePlayerMap.get(p).increaseBoostChargeLevel(0.02f); } protected void explode(Player p, Entity bomb) { @@ -184,7 +185,6 @@ class TurtleGame extends StatelessGame { meta.setBlock(this.snackBlock.withProperty("half", "upper")); meta.setCustomName(Component.text("Snack").color(NamedTextColor.WHITE)); meta.setCustomNameVisible(true); - meta.setHasGlowingEffect(true); snack.setInstance(this); Pos spawnPosition = this.newSpawnPosition(snack); if(spawnPosition == null) { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java index 7c75ef1..2f9328b 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java @@ -38,8 +38,7 @@ public class Turtle extends EntityCreature { public void startBoostRefill() { this.boostRefillTask = MinecraftServer.getSchedulerManager().scheduleTask(() -> { if(this.boostChargeLevel >= 1f) return; - this.boostChargeLevel = Math.min(1f, this.boostChargeLevel + 0.025f); - this.player.setExp(this.boostChargeLevel); + this.increaseBoostChargeLevel(0.02f); }, TaskSchedule.seconds(1), TaskSchedule.seconds(1)); } @@ -88,6 +87,11 @@ public class Turtle extends EntityCreature { this.boostSpeedMultiplier = 1; } + public void increaseBoostChargeLevel(float amount) { + this.boostChargeLevel = Math.min(1f, this.boostChargeLevel + amount); + this.player.setExp(this.boostChargeLevel); + } + public void addSpeed(double amount) { this.speed += amount; } From d5910b4b545de6d566bbb94b87c36b19f825c4d0 Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 6 Oct 2025 17:40:08 +0200 Subject: [PATCH 19/27] renamed methods --- .../game/stateless/types/turtleGame/TurtleGame.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 3146a3a..94dafbf 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -100,7 +100,7 @@ class TurtleGame extends StatelessGame { .toList() .forEach(bomb -> { this.explode(p, bomb); - this.generateNewBomb(2); + this.generateNewBombs(2); this.addGlobalSpeed(0.3); }); } @@ -173,7 +173,7 @@ class TurtleGame extends StatelessGame { return new Pos(x, 1, z).withLookAt(new Pos(0, 0, 0)); } - private void generateNewSnack(int count) { + private void generateNewSnacks(int count) { for (int i = 0; i < count; i++) { this.generateNewSnack(); } @@ -195,7 +195,7 @@ class TurtleGame extends StatelessGame { this.snacks.add(snack); } - private void generateNewBomb(int count) { + private void generateNewBombs(int count) { for (int i = 0; i < count; i++) { this.generateNewBomb(); } @@ -251,8 +251,8 @@ class TurtleGame extends StatelessGame { @Override protected void onStart() { - this.generateNewSnack((int) Math.ceil(this.turtlePlayerMap.size() * 1.5)); - this.generateNewBomb((int) Math.ceil(this.snacks.size() * 0.5)); + this.generateNewSnacks((int) Math.ceil(this.turtlePlayerMap.size() * 1.5)); + this.generateNewBombs((int) Math.ceil(this.snacks.size() * 0.5)); this.turtlePlayerMap.values().forEach(Turtle::startBoostRefill); } From 3dfff84c61a0db94d3f00515a97259415b02bd09 Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 15 Oct 2025 20:55:30 +0200 Subject: [PATCH 20/27] changed left player detection to use hasResult of Score --- .../instance/game/stateless/types/turtleGame/TurtleGame.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 94dafbf..12936c4 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -143,7 +143,9 @@ class TurtleGame extends StatelessGame { } protected List getLeftPlayers() { - return this.turtlePlayerMap.keySet().stream().filter(player -> !player.isFlying()).toList(); + return this.turtlePlayerMap.keySet().stream() + .filter(player -> !this.getScore().hasResult(player)) + .toList(); } @Override From 1830307f4bf5b18be2d2af7769e271afa33ba40f Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 15 Oct 2025 21:03:12 +0200 Subject: [PATCH 21/27] increased boost refill when eating flowers, changed speed options --- .../instance/game/stateless/types/turtleGame/TurtleGame.java | 2 +- .../game/stateless/types/turtleGame/TurtleGameFactory.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 12936c4..fdaa064 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -122,7 +122,7 @@ class TurtleGame extends StatelessGame { this.snacks.remove(snack); snack.remove(); this.turtlePlayerMap.get(p).increaseScore(); - this.turtlePlayerMap.get(p).increaseBoostChargeLevel(0.02f); + this.turtlePlayerMap.get(p).increaseBoostChargeLevel(0.04f); } protected void explode(Player p, Entity bomb) { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java index e91d47e..1f66cf5 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGameFactory.java @@ -27,7 +27,7 @@ public class TurtleGameFactory implements GameFactory { public ConfigManager configuration() { return new ConfigManager() .addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 10, 20, 30, 40)) - .addOption(new NumericOption("startSpeed", Material.LEATHER_BOOTS, TranslatedComponent.byId("game_TurtleGame#startSpeed"), 2, 4, 6, 8, 10)); + .addOption(new NumericOption("startSpeed", Material.LEATHER_BOOTS, TranslatedComponent.byId("game_TurtleGame#startSpeed"), 2, 3, 4, 6, 8)); } @Override From c8bf5f9186b176ead94c0d008f8dbbcc37ef5acb Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 15 Oct 2025 21:04:46 +0200 Subject: [PATCH 22/27] added turtle game to pve --- .../java/eu/mhsl/minenet/minigames/instance/game/GameList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java index ad3504f..33b9727 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java @@ -30,11 +30,11 @@ public enum GameList { BEDWARS(new BedwarsFactory(), GameType.PROTOTYPE), BACKROOMS(new BackroomsFactory(), GameType.PROTOTYPE), BOWSPLEEF(new BowSpleefFactory(), GameType.PROTOTYPE), - TURTLEGAME(new TurtleGameFactory(), GameType.PROTOTYPE), TETRIS(new TetrisFactory(), GameType.OTHER), TNTRUN(new TntRunFactory(), GameType.OTHER), ANVILRUN(new AnvilRunFactory(), GameType.PVE), ACIDRAIN(new AcidRainFactory(), GameType.PVE), + TURTLEGAME(new TurtleGameFactory(), GameType.PVE), ELYTRARACE(new ElytraRaceFactory(), GameType.PVP), SPLEEF(new SpleefFactory(), GameType.PVP), JUMPDIVE(new JumpDiveFactory(), GameType.JUMPNRUN), From eff5e36987fee3aaa0636b2d127c7221d13ed100 Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 15 Oct 2025 21:26:02 +0200 Subject: [PATCH 23/27] solved some pr comments --- .../types/turtleGame/TurtleGame.java | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index fdaa064..47d7754 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -48,10 +48,6 @@ class TurtleGame extends StatelessGame { @Override protected void onLoad(@NotNull CompletableFuture callback) { - this.generatePlatform(); - } - - private void generatePlatform() { for(int x = -this.radius - 1; x <= this.radius + 1; x++) { for(int z = -this.radius - 1; z <= this.radius + 1; z++) { double distance = new Pos(x, 0, z).distance(new Pos(0, 0, 0)); @@ -116,8 +112,7 @@ class TurtleGame extends StatelessGame { protected void eat(Player p, Entity snack) { p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EAT, Sound.Source.MASTER, 1f, 1f), snack.getPosition()); - Material snackMaterial = this.snackBlock.registry().material(); - if(snackMaterial == null) snackMaterial = Material.DIRT; + Material snackMaterial = Objects.requireNonNull(this.snackBlock.registry().material()); p.sendPacket(new ParticlePacket(Particle.ITEM.withItem(ItemStack.of(snackMaterial)), p.getPosition(), new Pos(0.5, 0.5, 0.5), 0, 8)); this.snacks.remove(snack); snack.remove(); @@ -184,16 +179,15 @@ class TurtleGame extends StatelessGame { private void generateNewSnack() { Entity snack = new Entity(EntityType.FALLING_BLOCK); FallingBlockMeta meta = (FallingBlockMeta) snack.getEntityMeta(); - meta.setBlock(this.snackBlock.withProperty("half", "upper")); - meta.setCustomName(Component.text("Snack").color(NamedTextColor.WHITE)); + meta.setBlock(this.snackBlock); + meta.setCustomName(Component.text("Snack")); meta.setCustomNameVisible(true); - snack.setInstance(this); Pos spawnPosition = this.newSpawnPosition(snack); if(spawnPosition == null) { snack.remove(); return; } - snack.teleport(spawnPosition); + snack.setInstance(this, spawnPosition); this.snacks.add(snack); } @@ -209,30 +203,25 @@ class TurtleGame extends StatelessGame { meta.setBlock(Block.TNT); meta.setCustomName(Component.text("Bomb").color(NamedTextColor.RED).decorate(TextDecoration.BOLD)); meta.setCustomNameVisible(true); - bomb.setInstance(this); Pos spawnPosition = this.newSpawnPosition(bomb, false); if(spawnPosition == null) { bomb.remove(); return; } - bomb.teleport(spawnPosition); + bomb.setInstance(this, spawnPosition); this.bombs.add(bomb); } - @Nullable - private Pos newSpawnPosition(Entity entity) { + private @Nullable Pos newSpawnPosition(Entity entity) { return this.newSpawnPosition(entity, true); } - @Nullable - private Pos newSpawnPosition(Entity entity, boolean nearPlayers) { + private @Nullable Pos newSpawnPosition(Entity entity, boolean nearPlayers) { Pos spawnPosition; int counter = 0; boolean isInRadius, collides; do { - if(counter > 200) { - return null; - } + if(counter > 200) return null; int x = this.rnd.nextInt(-this.radius+2, this.radius-2); int z = this.rnd.nextInt(-this.radius+2, this.radius-2); spawnPosition = new Pos(x, 1, z).add(0.5, 0, 0.5); From 35dc924104b7ae0f30de48457e79a351bef3203f Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 15 Oct 2025 21:30:11 +0200 Subject: [PATCH 24/27] added null ckeck for boostTask and boostRefillTask --- .../game/stateless/types/turtleGame/gameObjects/Turtle.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java index 2f9328b..539ee8d 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java @@ -46,8 +46,8 @@ public class Turtle extends EntityCreature { this.removePassenger(this.player); this.remove(); this.kill(); - if(this.boostRefillTask.isAlive()) this.boostRefillTask.cancel(); - if(this.boostTask.isAlive()) this.boostTask.cancel(); + if(this.boostRefillTask != null && this.boostRefillTask.isAlive()) this.boostRefillTask.cancel(); + if(this.boostTask != null && this.boostTask.isAlive()) this.boostTask.cancel(); } public void adaptView() { @@ -82,7 +82,7 @@ public class Turtle extends EntityCreature { } public void cancelBoost() { - if(!this.boostTask.isAlive()) return; + if(this.boostTask == null || !this.boostTask.isAlive()) return; this.boostTask.cancel(); this.boostSpeedMultiplier = 1; } From 6d8c5ed917226d50f14b360c0d766c41e2cd16c7 Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 15 Oct 2025 21:33:17 +0200 Subject: [PATCH 25/27] solved pr comments --- .../game/stateless/types/turtleGame/gameObjects/Turtle.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java index 539ee8d..cbcd537 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java @@ -30,8 +30,7 @@ public class Turtle extends EntityCreature { } public void spawnTurtle() { - this.setInstance(this.player.getInstance()); - this.teleport(this.player.getPosition()); + this.setInstance(this.player.getInstance(), this.player.getPosition()); this.addPassenger(this.player); } @@ -45,7 +44,6 @@ public class Turtle extends EntityCreature { public void destroy() { this.removePassenger(this.player); this.remove(); - this.kill(); if(this.boostRefillTask != null && this.boostRefillTask.isAlive()) this.boostRefillTask.cancel(); if(this.boostTask != null && this.boostTask.isAlive()) this.boostTask.cancel(); } @@ -76,7 +74,6 @@ public class Turtle extends EntityCreature { return; } this.boostChargeLevel = Math.max(0f, this.boostChargeLevel - 0.025f); - System.out.println(this.boostChargeLevel); this.player.setExp(this.boostChargeLevel); }, TaskSchedule.millis(30), TaskSchedule.millis(30)); } From 9f71523a0763207263a57462b838e7c0d9288d75 Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 15 Oct 2025 21:56:48 +0200 Subject: [PATCH 26/27] lowered snack count --- .../instance/game/stateless/types/turtleGame/TurtleGame.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java index 47d7754..c2ab1b3 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/TurtleGame.java @@ -242,7 +242,7 @@ class TurtleGame extends StatelessGame { @Override protected void onStart() { - this.generateNewSnacks((int) Math.ceil(this.turtlePlayerMap.size() * 1.5)); + this.generateNewSnacks(this.turtlePlayerMap.size() + 1); this.generateNewBombs((int) Math.ceil(this.snacks.size() * 0.5)); this.turtlePlayerMap.values().forEach(Turtle::startBoostRefill); } From be6b6da68eb162a06218785b7e737f63187ffa53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Wed, 15 Oct 2025 22:01:10 +0200 Subject: [PATCH 27/27] fix: prevent null instance in Turtle adaptView method --- .../game/stateless/types/turtleGame/gameObjects/Turtle.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java index cbcd537..5ba3916 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/turtleGame/gameObjects/Turtle.java @@ -49,6 +49,7 @@ public class Turtle extends EntityCreature { } public void adaptView() { + if(this.getInstance() == null) return; this.teleport(this.getPosition().withView(this.player.getPosition().withPitch(this.getPosition().pitch()))); Vec lookingVector = this.player.getPosition().direction().withY(0).mul(100); this.lookAt(this.getPosition().add(lookingVector.asPosition()));