From 20b93cc9ae7990f8de329773bd85fe0fb0366fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Sat, 4 Oct 2025 21:34:40 +0200 Subject: [PATCH] added BlockBreakRace game and related assets --- .../minigames/instance/game/GameList.java | 4 +- .../types/blockBreakRace/BlockBreakRace.java | 76 +++++++++++++++++++ .../blockBreakRace/BlockBreakRaceFactory.java | 40 ++++++++++ .../BlockBreakRaceGenerator.java | 67 ++++++++++++++++ src/main/resources/lang/locales.map.csv | 5 ++ 5 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRace.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRaceFactory.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRaceGenerator.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 a20e115..150a603 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 @@ -2,6 +2,7 @@ package eu.mhsl.minenet.minigames.instance.game; import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.anvilRun.AnvilRunFactory; +import eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBreakRace.BlockBreakRaceFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.bowSpleef.BowSpleefFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.elytraRace.ElytraRaceFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.backrooms.BackroomsFactory; @@ -38,7 +39,8 @@ public enum GameList { JUMPDIVE(new JumpDiveFactory(), GameType.JUMPNRUN), SUMO(new SumoFactory(), GameType.PVP), HIGHGROUND(new HighGroundFactory(), GameType.PVP), - FASTBRIDGE(new FastbridgeFactory(), GameType.OTHER); + FASTBRIDGE(new FastbridgeFactory(), GameType.OTHER), + BLOCKBREAKRACE(new BlockBreakRaceFactory(), GameType.OTHER); private final GameFactory factory; private final GameType type; diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRace.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRace.java new file mode 100644 index 0000000..b123f86 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRace.java @@ -0,0 +1,76 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBreakRace; + +import eu.mhsl.minenet.minigames.instance.Dimension; +import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import eu.mhsl.minenet.minigames.score.FirstWinsScore; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.GameMode; +import net.minestom.server.entity.Player; +import net.minestom.server.event.player.PlayerBlockBreakEvent; +import net.minestom.server.event.player.PlayerMoveEvent; +import net.minestom.server.inventory.PlayerInventory; +import net.minestom.server.item.ItemStack; +import net.minestom.server.item.Material; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class BlockBreakRace extends StatelessGame { + private int spawnCount = 0; + private final int height; + + public BlockBreakRace(int height) { + super(Dimension.OVERWORLD.key, "blockBreakRace", new FirstWinsScore()); + this.height = height; + this.setGenerator(new BlockBreakRaceGenerator(height)); + } + + @Override + protected void onStart() { + this.getPlayers().forEach(player -> { + PlayerInventory inv = player.getInventory(); + inv.addItemStack(ItemStack.of(Material.DIAMOND_PICKAXE)); + inv.addItemStack(ItemStack.of(Material.DIAMOND_AXE)); + inv.addItemStack(ItemStack.of(Material.DIAMOND_SHOVEL)); + player.setGameMode(GameMode.SURVIVAL); + }); + } + + @Override + protected void onBlockBreak(@NotNull PlayerBlockBreakEvent event) { + List allowedMaterials = List.of(Material.STONE, Material.OAK_PLANKS, Material.DIRT); + if(!allowedMaterials.contains(event.getBlock().registry().material())) event.setCancelled(true); + if(this.isBeforeBeginning) event.setCancelled(true); + } + + @Override + protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) { + if(this.isBeforeBeginning) return; + if(playerMoveEvent.getNewPosition().y() < BlockBreakRaceGenerator.BOTTOM_Y) { + Player player = playerMoveEvent.getPlayer(); + this.getScore().insertResult(player); + player.setGameMode(GameMode.SPECTATOR); + player.getInventory().clear(); + } + } + + @Override + public Pos getSpawn() { + int idx = this.spawnCount++; + + int cols = BlockBreakRaceGenerator.ROW_OFFSETS_X.length; + int rows = BlockBreakRaceGenerator.ROW_OFFSETS_Z.length; + int perChunk = cols * rows; + int zChunk = idx / perChunk; + + int gridIndex = idx % perChunk; + int xIndex = gridIndex % cols; + int zIndex = gridIndex / cols; + + int localX = BlockBreakRaceGenerator.ROW_OFFSETS_X[xIndex]; + int localZ = BlockBreakRaceGenerator.ROW_OFFSETS_Z[zIndex]; + + int absZ = (zChunk * 16) + localZ; + return new Pos(localX, BlockBreakRaceGenerator.BOTTOM_Y + this.height + 1, absZ).add(0.5); + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRaceFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRaceFactory.java new file mode 100644 index 0000000..7ff5f1f --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRaceFactory.java @@ -0,0 +1,40 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBreakRace; + +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.NumericOption; +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; + +public class BlockBreakRaceFactory implements GameFactory { + @Override + public TranslatedComponent name() { + return TranslatedComponent.byId("game_BlockBreakRace#name"); + } + + @Override + public Material symbol() { + return Material.DIAMOND_PICKAXE; + } + + @Override + public TranslatedComponent description() { + return TranslatedComponent.byId("game_BlockBreakRace#description"); + } + + @Override + public ConfigManager configuration() { + return new ConfigManager() + .addOption(new NumericOption("height", Material.SCAFFOLDING, TranslatedComponent.byId("optionCommon#height"), 20, 30, 40, 50)); + } + + @Override + public Game manufacture(Room parent, Map> configuration) throws Exception { + return new BlockBreakRace(configuration.get("height").getAsInt()).setParent(parent); + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRaceGenerator.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRaceGenerator.java new file mode 100644 index 0000000..768bf72 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/blockBreakRace/BlockBreakRaceGenerator.java @@ -0,0 +1,67 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBreakRace; + +import eu.mhsl.minenet.minigames.world.generator.featureEnriched.ValeGenerator; +import eu.mhsl.minenet.minigames.world.generator.terrain.BaseGenerator; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.instance.block.Block; +import net.minestom.server.instance.generator.GenerationUnit; + +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +public class BlockBreakRaceGenerator extends BaseGenerator { + public static final int BOTTOM_Y = 50; + public final int TOP_Y; + public static final int[] ROW_OFFSETS_X = {4, 8, 12}; + public static final int[] ROW_OFFSETS_Z = {4, 8, 12}; + + private static final Block[] FILL_BLOCKS = { + Block.STONE, + Block.DIRT, + Block.OAK_PLANKS + }; + + private final Random random = ThreadLocalRandom.current(); + + public BlockBreakRaceGenerator(int height) { + this.TOP_Y = BOTTOM_Y + height; + ValeGenerator vale = new ValeGenerator(); + vale.setXShiftMultiplier(i -> 0.5d); + vale.setHeightNoiseMultiplier(i -> 2); + vale.setXShiftOffset(i -> 40d); + this.addMixIn(vale); + + this.addMixIn(unit -> { + if(unit.absoluteStart().chunkX() != 0) return; + + for (int localX : ROW_OFFSETS_X) { + for (int localZ : ROW_OFFSETS_Z) { + final int absZ = unit.absoluteStart().blockZ() + localZ; + this.placeTube(unit, localX, absZ); + } + } + }); + } + + private void placeTube(GenerationUnit unit, int x, int z) { + for (int y = BOTTOM_Y; y < this.TOP_Y; y++) { + Block fill = FILL_BLOCKS[this.random.nextInt(FILL_BLOCKS.length)]; + unit.modifier().fill( + new Pos(x, y, z), + new Pos(x, y, z).add(1), + fill + ); + } + + for (int dx = -1; dx <= 1; dx++) { + for (int dz = -1; dz <= 1; dz++) { + if (dx == 0 && dz == 0) continue; // Zentrum überspringen + unit.modifier().fill( + new Pos(x + dx, BOTTOM_Y, z + dz), + new Pos(x + dx, this.TOP_Y + 3, z + dz).add(1), + Block.BARRIER + ); + } + } + } +} diff --git a/src/main/resources/lang/locales.map.csv b/src/main/resources/lang/locales.map.csv index 46b4bb2..d2167ae 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_BlockBreakRace#;; +name;Block Break Race;Blockbruch-Rennen +description;Dig down through the tubes using the right tools. The first player to reach the bottom wins!;Grabe dich durch die Röhren nach unten und verwende dabei das richtige Werkzeug. Wer zuerst unten ankommt, gewinnt! +;; \ No newline at end of file