From 7ea39f9aada4513712bee98781a280eef2eb2631 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 19 Oct 2024 16:38:43 +0200 Subject: [PATCH 01/30] started tetris --- .../minigames/command/PrivilegedCommand.java | 3 +- .../minigames/instance/game/GameList.java | 2 + .../game/stateless/types/tetris/Tetris.java | 111 ++++++++++++++++++ .../stateless/types/tetris/TetrisFactory.java | 38 ++++++ 4 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java diff --git a/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java b/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java index 13294f6..22a1700 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java +++ b/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java @@ -27,7 +27,8 @@ public class PrivilegedCommand extends Command { } protected CommandCondition isPrivileged() { - return (sender, commandString) -> sender.hasPermission("admin"); +// return (sender, commandString) -> sender.hasPermission("admin"); + return (sender, commandString) -> true; } protected void addCondition(CommandCondition condition) { 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 0fa51f5..9dbb7f0 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 @@ -11,6 +11,7 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.types.deathcube.Deathcu import eu.mhsl.minenet.minigames.instance.game.stateless.types.minerun.MinerunFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.spleef.SpleefFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.stickfight.StickFightFactory; +import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.TetrisFactory; 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; @@ -24,6 +25,7 @@ public enum GameList { BEDWARS(new BedwarsFactory(), GameType.PROTOTYPE), BACKROOMS(new BackroomsFactory(), GameType.PROTOTYPE), ANVILRUN(new AnvilRunFactory(), GameType.PROTOTYPE), + TETRIS(new TetrisFactory(), GameType.PROTOTYPE), TNTRUN(new TntRunFactory(), GameType.OTHER), ACIDRAIN(new AcidRainFactory(), GameType.PVE), ELYTRARACE(new ElytraRaceFactory(), GameType.PVP), diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java new file mode 100644 index 0000000..cb03e4f --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -0,0 +1,111 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris; + +import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import eu.mhsl.minenet.minigames.score.FirstWinsScore; +import eu.mhsl.minenet.minigames.util.BatchUtil; +import eu.mhsl.minenet.minigames.instance.Dimension; +import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.Player; +import net.minestom.server.event.player.PlayerMoveEvent; +import net.minestom.server.instance.batch.AbsoluteBlockBatch; +import net.minestom.server.instance.block.Block; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +class Tetris extends StatelessGame { + private final boolean isFast; + private final int width = 9; + private final int height = 20; + + enum Button { + W, + A, + S, + D, + mouseLeft, + mouseRight, + space + } + + public Tetris(boolean isFast) { + super(Dimension.THE_END.key, "Tetris", new FirstWinsScore()); + this.setGenerator(new CircularPlateTerrainGenerator(30).setPlateHeight(0)); + + this.isFast = isFast; + } + + protected void pressedButton(Button button) { + switch (button) { + case A -> System.out.println("A"); + case S -> System.out.println("S"); + case D -> System.out.println("D"); + case W -> System.out.println("W"); + } + } + + @Override + protected void onLoad(@NotNull CompletableFuture callback) { + AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); + + for(int y = 45; y <= 45+height; y++) { + for(int x = -(width/2)-1; x <= (width/2)+1; x++) { + batch.setBlock(x, y, 0, Block.STONE); + } + } + + for(int y = 45; y <= 45+height; y++) { + batch.setBlock(-(width/2)-1, y, 1, Block.GRAY_CONCRETE); + batch.setBlock((width/2)+1, y, 1, Block.GRAY_CONCRETE); + } + for(int x = -(width/2)-1; x <= (width/2)+1; x++) { + batch.setBlock(x, 45, 1, Block.GRAY_CONCRETE); + } + + BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null)); + } + + @Override + protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) { + super.onPlayerMove(playerMoveEvent); + +// if(playerMoveEvent.getNewPosition().z() < getSpawn().z()) { +// pressedButton(Button.W); +// } +// if(playerMoveEvent.getNewPosition().z() > getSpawn().z()) { +// pressedButton(Button.S); +// } +// if(playerMoveEvent.getNewPosition().x() < getSpawn().x()) { +// pressedButton(Button.A); +// } +// if(playerMoveEvent.getNewPosition().x() > getSpawn().x()) { +// pressedButton(Button.D); +// } + +// playerMoveEvent.getNewPosition().asVec(); + + Vec movementVector = playerMoveEvent.getPlayer().getPreviousPosition().asVec().sub(playerMoveEvent.getNewPosition()); + + + + System.out.println(movementVector); + +// if(!(playerMoveEvent.getNewPosition().withYaw(0).withPitch(0) == getSpawn().withYaw(0).withPitch(0))) { + playerMoveEvent.setNewPosition(getSpawn().withView(playerMoveEvent.getNewPosition())); +// return; +// } + } + + @Override + protected boolean onPlayerJoin(Player p) { + p.setNoGravity(true); + return super.onPlayerJoin(p); + } + + @Override + public Pos getSpawn() { + return new Pos(0, 50, 15).withView(180, 0); + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java new file mode 100644 index 0000000..02d6f3c --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java @@ -0,0 +1,38 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris; + +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.game.stateless.config.ConfigManager; +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 TetrisFactory implements GameFactory { + @Override + public TranslatedComponent name() { + return TranslatedComponent.byId("game_Tetris#name"); + } + + @Override + public TranslatedComponent description() { + return TranslatedComponent.byId("game_Tetris#description"); + } + + @Override + public ConfigManager configuration() { + return new ConfigManager(); + } + + @Override + public Game manufacture(Room parent, Map> configuration) { + return new Tetris(false).setParent(parent); + } + + @Override + public Material symbol() { + return Material.PURPLE_WOOL; + } +} From 9d287f7c2f03855a8ecf2e1faab616db7a1b0914 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 19 Oct 2024 22:57:05 +0200 Subject: [PATCH 02/30] added control input --- .../game/stateless/types/tetris/Tetris.java | 102 +++++++++++++----- 1 file changed, 78 insertions(+), 24 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index cb03e4f..421e5cb 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -5,14 +5,19 @@ import eu.mhsl.minenet.minigames.score.FirstWinsScore; import eu.mhsl.minenet.minigames.util.BatchUtil; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator; +import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Player; -import net.minestom.server.event.player.PlayerMoveEvent; +import net.minestom.server.event.player.*; import net.minestom.server.instance.batch.AbsoluteBlockBatch; 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.HashMap; +import java.util.Map; import java.util.concurrent.CompletableFuture; class Tetris extends StatelessGame { @@ -20,6 +25,8 @@ class Tetris extends StatelessGame { private final int width = 9; private final int height = 20; + private final Map lastPresses = new HashMap<>(); + enum Button { W, A, @@ -35,17 +42,36 @@ class Tetris extends StatelessGame { this.setGenerator(new CircularPlateTerrainGenerator(30).setPlateHeight(0)); this.isFast = isFast; + + eventNode() + .addListener(PlayerUseItemEvent.class, this::onPlayerInteract) + .addListener(PlayerHandAnimationEvent.class, this::onPlayerAttack); + } + + @Override + protected void onStart() { + super.onStart(); } protected void pressedButton(Button button) { + if(lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-200) return; + lastPresses.put(button, System.currentTimeMillis()); + switch (button) { case A -> System.out.println("A"); case S -> System.out.println("S"); case D -> System.out.println("D"); case W -> System.out.println("W"); + case mouseLeft -> System.out.println("mouse left"); + case mouseRight -> System.out.println("mouse right"); + case space -> System.out.println("space"); } } + protected void releasedButton(Button button) { + lastPresses.put(button, 0L); + } + @Override protected void onLoad(@NotNull CompletableFuture callback) { AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); @@ -64,43 +90,71 @@ class Tetris extends StatelessGame { batch.setBlock(x, 45, 1, Block.GRAY_CONCRETE); } + batch.setBlock((int) getSpawn().x(), (int) (getSpawn().y()-1), (int) getSpawn().z(), Block.STONE); + BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null)); } @Override - protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) { - super.onPlayerMove(playerMoveEvent); + protected void onPlayerMove(@NotNull PlayerMoveEvent event) { + super.onPlayerMove(event); -// if(playerMoveEvent.getNewPosition().z() < getSpawn().z()) { -// pressedButton(Button.W); -// } -// if(playerMoveEvent.getNewPosition().z() > getSpawn().z()) { -// pressedButton(Button.S); -// } -// if(playerMoveEvent.getNewPosition().x() < getSpawn().x()) { -// pressedButton(Button.A); -// } -// if(playerMoveEvent.getNewPosition().x() > getSpawn().x()) { -// pressedButton(Button.D); -// } + Player player = event.getPlayer(); + Pos previousPosition = event.getPlayer().getPosition(); + Pos currentPosition = event.getNewPosition(); -// playerMoveEvent.getNewPosition().asVec(); + Vec movementVector = currentPosition.asVec().sub(previousPosition.asVec()); - Vec movementVector = playerMoveEvent.getPlayer().getPreviousPosition().asVec().sub(playerMoveEvent.getNewPosition()); + float yaw = player.getPosition().yaw(); - + double yawRadians = Math.toRadians(yaw); + double forwardX = -Math.sin(yawRadians); + double forwardZ = Math.cos(yawRadians); - System.out.println(movementVector); + Vec forward = new Vec(forwardX, 0, forwardZ).normalize(); + Vec left = forward.cross(new Vec(0, 1, 0)).normalize(); -// if(!(playerMoveEvent.getNewPosition().withYaw(0).withPitch(0) == getSpawn().withYaw(0).withPitch(0))) { - playerMoveEvent.setNewPosition(getSpawn().withView(playerMoveEvent.getNewPosition())); -// return; -// } + double forwardAmount = movementVector.dot(forward); + double leftAmount = movementVector.dot(left); + + if (forwardAmount > 0.01) { + pressedButton(Button.W); + releasedButton(Button.S); + } else if (forwardAmount < -0.01) { + pressedButton(Button.S); + releasedButton(Button.W); + } else { + releasedButton(Button.W); + releasedButton(Button.S); + } + + if (leftAmount > 0.01) { + pressedButton(Button.D); + releasedButton(Button.A); + } else if (leftAmount < -0.01) { + pressedButton(Button.A); + releasedButton(Button.D); + } else { + releasedButton(Button.A); + releasedButton(Button.D); + } + + if(previousPosition.y() < currentPosition.y()) pressedButton(Button.space); + + event.setNewPosition(getSpawn().withView(event.getNewPosition())); + } + + protected void onPlayerInteract(@NotNull PlayerUseItemEvent event) { + pressedButton(Button.mouseRight); + } + + protected void onPlayerAttack(@NotNull PlayerHandAnimationEvent event) { + pressedButton(Button.mouseLeft); } @Override protected boolean onPlayerJoin(Player p) { - p.setNoGravity(true); + p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build()); return super.onPlayerJoin(p); } From 5acfe8f6af85b184e96c03e0052e8b56fd927657 Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 20 Oct 2024 18:24:53 +0200 Subject: [PATCH 03/30] added basic tetris classes --- .../game/stateless/types/tetris/Tetris.java | 43 +++--------- .../stateless/types/tetris/TetrisFactory.java | 2 +- .../types/tetris/game/Playfield.java | 37 ++++++++++ .../types/tetris/game/TetrisGame.java | 28 ++++++++ .../types/tetris/game/Tetromino.java | 69 +++++++++++++++++++ 5 files changed, 146 insertions(+), 33 deletions(-) create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 421e5cb..ff123f2 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -1,8 +1,8 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.TetrisGame; import eu.mhsl.minenet.minigames.score.FirstWinsScore; -import eu.mhsl.minenet.minigames.util.BatchUtil; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator; import net.kyori.adventure.text.Component; @@ -10,8 +10,6 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Player; import net.minestom.server.event.player.*; -import net.minestom.server.instance.batch.AbsoluteBlockBatch; -import net.minestom.server.instance.block.Block; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import org.jetbrains.annotations.NotNull; @@ -21,9 +19,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; class Tetris extends StatelessGame { - private final boolean isFast; - private final int width = 9; - private final int height = 20; + private TetrisGame tetrisGame; private final Map lastPresses = new HashMap<>(); @@ -37,12 +33,10 @@ class Tetris extends StatelessGame { space } - public Tetris(boolean isFast) { + public Tetris() { super(Dimension.THE_END.key, "Tetris", new FirstWinsScore()); this.setGenerator(new CircularPlateTerrainGenerator(30).setPlateHeight(0)); - this.isFast = isFast; - eventNode() .addListener(PlayerUseItemEvent.class, this::onPlayerInteract) .addListener(PlayerHandAnimationEvent.class, this::onPlayerAttack); @@ -51,6 +45,8 @@ class Tetris extends StatelessGame { @Override protected void onStart() { super.onStart(); + + this.tetrisGame.generate(); } protected void pressedButton(Button button) { @@ -74,25 +70,7 @@ class Tetris extends StatelessGame { @Override protected void onLoad(@NotNull CompletableFuture callback) { - AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); - - for(int y = 45; y <= 45+height; y++) { - for(int x = -(width/2)-1; x <= (width/2)+1; x++) { - batch.setBlock(x, y, 0, Block.STONE); - } - } - - for(int y = 45; y <= 45+height; y++) { - batch.setBlock(-(width/2)-1, y, 1, Block.GRAY_CONCRETE); - batch.setBlock((width/2)+1, y, 1, Block.GRAY_CONCRETE); - } - for(int x = -(width/2)-1; x <= (width/2)+1; x++) { - batch.setBlock(x, 45, 1, Block.GRAY_CONCRETE); - } - - batch.setBlock((int) getSpawn().x(), (int) (getSpawn().y()-1), (int) getSpawn().z(), Block.STONE); - - BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null)); + this.tetrisGame = new TetrisGame(this, getSpawn().sub(6, 8, 15)); } @Override @@ -117,10 +95,10 @@ class Tetris extends StatelessGame { double forwardAmount = movementVector.dot(forward); double leftAmount = movementVector.dot(left); - if (forwardAmount > 0.01) { + if (forwardAmount > 0.018) { pressedButton(Button.W); releasedButton(Button.S); - } else if (forwardAmount < -0.01) { + } else if (forwardAmount < -0.018) { pressedButton(Button.S); releasedButton(Button.W); } else { @@ -128,10 +106,10 @@ class Tetris extends StatelessGame { releasedButton(Button.S); } - if (leftAmount > 0.01) { + if (leftAmount > 0.018) { pressedButton(Button.D); releasedButton(Button.A); - } else if (leftAmount < -0.01) { + } else if (leftAmount < -0.018) { pressedButton(Button.A); releasedButton(Button.D); } else { @@ -155,6 +133,7 @@ class Tetris extends StatelessGame { @Override protected boolean onPlayerJoin(Player p) { p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build()); + p.setSprinting(false); return super.onPlayerJoin(p); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java index 02d6f3c..3b5b628 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java @@ -28,7 +28,7 @@ public class TetrisFactory implements GameFactory { @Override public Game manufacture(Room parent, Map> configuration) { - return new Tetris(false).setParent(parent); + return new Tetris().setParent(parent); } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java new file mode 100644 index 0000000..2710d85 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -0,0 +1,37 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.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.instance.batch.AbsoluteBlockBatch; +import net.minestom.server.instance.block.Block; + +public class Playfield { + private final Pos lowerLeftCorner; + + public Playfield(Pos lowerLeftCorner) { + this.lowerLeftCorner = lowerLeftCorner; + } + + public Pos getPlayerSpawnPosition() { + return lowerLeftCorner.add(6, 8, 15); + } + + public void generate(StatelessGame instance) { + AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); + + for(int x=0; x<12; x++) { + for(int y=0; y<21; y++) { + batch.setBlock(lowerLeftCorner.add(x, y, 0), Block.STONE); + + if(x==0 || x==11 || y==0) { + batch.setBlock(lowerLeftCorner.add(x, y, 1), Block.GRAY_CONCRETE); + } + } + } + + batch.setBlock(getPlayerSpawnPosition().sub(0, 1, 0), Block.STONE); + + BatchUtil.loadAndApplyBatch(batch, instance, () -> {}); + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java new file mode 100644 index 0000000..9e6401b --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -0,0 +1,28 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game; + +import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import net.minestom.server.coordinate.Pos; + +public class TetrisGame { + private final StatelessGame instance; + private final Playfield playfield; + private int speed = 1; + private int lines = 0; + private Tetromino currentTetromino; + private Tetromino nextTetromino; + + public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) { + this(instance, lowerLeftCorner, new Tetromino(Tetromino.Shape.J), new Tetromino(Tetromino.Shape.T)); + } + + public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino startTetromino, Tetromino nextTetromino) { + this.playfield = new Playfield(lowerLeftCorner); + this.currentTetromino = startTetromino; + this.nextTetromino = nextTetromino; + this.instance = instance; + } + + public void generate() { + this.playfield.generate(this.instance); + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java new file mode 100644 index 0000000..71bad89 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -0,0 +1,69 @@ +package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.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.instance.batch.AbsoluteBlockBatch; +import net.minestom.server.instance.block.Block; + +public class Tetromino { + private final Shape shape; + + private int[][] shapeArray; + + public enum Shape { + I, + J, + L, + O, + S, + T, + Z + } + + public Tetromino(Shape shape) { + this.shape = shape; + + switch (this.shape) { + case I -> shapeArray = new int[][]{{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}}; + case J -> shapeArray = new int[][]{{1,0,0}, {1,1,1}, {0,0,0}}; + case L -> shapeArray = new int[][]{{0,0,1}, {1,1,1}, {0,0,0}}; + case O -> shapeArray = new int[][]{{1,1}, {1,1}}; + case S -> shapeArray = new int[][]{{0,1,1}, {1,1,0}, {0,0,0}}; + case T -> shapeArray = new int[][]{{0,1,0}, {1,1,1}, {0,0,0}}; + case Z -> shapeArray = new int[][]{{1,1,0}, {0,1,1}, {0,0,0}}; + } + } + + private int[][] getTurnedShapeArray(boolean clockwise) { + int iterations = 1; + if(!clockwise) iterations = 3; + + int arrayLength = this.shapeArray.length; + int[][] returnArray = new int[arrayLength][arrayLength]; + + for(int k=0; k {}); + } +} From 1332a42bf65645e4172342f06d8664923c7615ca Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 21 Oct 2024 00:27:58 +0200 Subject: [PATCH 04/30] added tetromino controlls --- .../game/stateless/types/tetris/Tetris.java | 18 ++- .../types/tetris/game/Playfield.java | 4 + .../types/tetris/game/TetrisGame.java | 52 +++++++- .../types/tetris/game/Tetromino.java | 117 ++++++++++++++++-- 4 files changed, 174 insertions(+), 17 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index ff123f2..3626e30 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -46,7 +46,7 @@ class Tetris extends StatelessGame { protected void onStart() { super.onStart(); - this.tetrisGame.generate(); + this.tetrisGame.start(); } protected void pressedButton(Button button) { @@ -54,9 +54,18 @@ class Tetris extends StatelessGame { lastPresses.put(button, System.currentTimeMillis()); switch (button) { - case A -> System.out.println("A"); - case S -> System.out.println("S"); - case D -> System.out.println("D"); + case A -> { + System.out.println("A"); + System.out.println(this.tetrisGame.currentTetromino.moveLeft()); + } + case S -> { + System.out.println("S"); + System.out.println(this.tetrisGame.currentTetromino.moveDown()); + } + case D -> { + System.out.println("D"); + System.out.println(this.tetrisGame.currentTetromino.moveRight()); + } case W -> System.out.println("W"); case mouseLeft -> System.out.println("mouse left"); case mouseRight -> System.out.println("mouse right"); @@ -71,6 +80,7 @@ class Tetris extends StatelessGame { @Override protected void onLoad(@NotNull CompletableFuture callback) { this.tetrisGame = new TetrisGame(this, getSpawn().sub(6, 8, 15)); + this.tetrisGame.generate(); } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index 2710d85..44bf742 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -17,6 +17,10 @@ public class Playfield { return lowerLeftCorner.add(6, 8, 15); } + public Pos getTetrominoSpawnPosition() { + return this.lowerLeftCorner.add(5, 21, 1); + } + public void generate(StatelessGame instance) { AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 9e6401b..d3be554 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -1,18 +1,26 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; +import net.minestom.server.timer.Scheduler; +import net.minestom.server.timer.TaskSchedule; + +import java.util.Random; public class TetrisGame { private final StatelessGame instance; private final Playfield playfield; private int speed = 1; private int lines = 0; - private Tetromino currentTetromino; + public Tetromino currentTetromino; private Tetromino nextTetromino; + private final Random random = new Random(); + + private final Pos tetrominoSpawnPosition; public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) { - this(instance, lowerLeftCorner, new Tetromino(Tetromino.Shape.J), new Tetromino(Tetromino.Shape.T)); + this(instance, lowerLeftCorner, new Tetromino(instance, Tetromino.Shape.J), new Tetromino(instance, Tetromino.Shape.T)); } public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino startTetromino, Tetromino nextTetromino) { @@ -20,9 +28,49 @@ public class TetrisGame { this.currentTetromino = startTetromino; this.nextTetromino = nextTetromino; this.instance = instance; + + this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition(); + } + + public void start() { + Scheduler scheduler = MinecraftServer.getSchedulerManager(); + scheduler.submitTask(() -> { + this.tick(); + return TaskSchedule.tick(40/this.speed); + }); } public void generate() { this.playfield.generate(this.instance); + + this.currentTetromino.setPosition(this.tetrominoSpawnPosition); + this.currentTetromino.draw(); + } + + public void tick() { + if(!currentTetromino.moveDown()) { + currentTetromino = nextTetromino; + currentTetromino.setPosition(this.tetrominoSpawnPosition); + currentTetromino.draw(); + nextTetromino = getNextTetromino(); + } + } + + + private Tetromino getNextTetromino() { + int randomNumber = random.nextInt(1, 7); + Tetromino.Shape nextShape; + + switch (randomNumber) { + case 2 -> nextShape = Tetromino.Shape.J; + case 3 -> nextShape = Tetromino.Shape.L; + case 4 -> nextShape = Tetromino.Shape.O; + case 5 -> nextShape = Tetromino.Shape.S; + case 6 -> nextShape = Tetromino.Shape.T; + case 7 -> nextShape = Tetromino.Shape.Z; + default -> nextShape = Tetromino.Shape.I; + } + + return new Tetromino(this.instance, nextShape); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index 71bad89..00ddf1e 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -1,14 +1,16 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.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.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.block.Block; +import java.util.ArrayList; +import java.util.List; + public class Tetromino { private final Shape shape; - + private final StatelessGame instance; + private Pos position; private int[][] shapeArray; public enum Shape { @@ -21,7 +23,8 @@ public class Tetromino { Z } - public Tetromino(Shape shape) { + public Tetromino(StatelessGame instance, Shape shape) { + this.instance = instance; this.shape = shape; switch (this.shape) { @@ -35,6 +38,58 @@ public class Tetromino { } } + public Pos getPosition() { + return this.position; + } + + public void setPosition(Pos newPosition) { + this.position = newPosition; + } + + public boolean rotate(boolean clockwise) { + int[][] newShapeArray = this.getTurnedShapeArray(clockwise); + return checkCollisionAndMove(this.position, newShapeArray); + } + + public boolean moveDown() { + Pos newPosition = this.position.sub(0, 1, 0); + return checkCollisionAndMove(newPosition, this.shapeArray); + } + + public boolean moveLeft() { + Pos newPosition = this.position.sub(1, 0, 0); + return checkCollisionAndMove(newPosition, this.shapeArray); + } + + public boolean moveRight() { + Pos newPosition = this.position.add(1, 0, 0); + return checkCollisionAndMove(newPosition, this.shapeArray); + } + + public void draw() { + getBlockPositions().forEach(pos -> this.instance.setBlock(pos, this.getColoredBlock())); + } + + public void remove() { + this.getBlockPositions().forEach(pos -> this.instance.setBlock(pos, Block.AIR)); + } + + + private Block getColoredBlock() { + Block returnBlock; + switch (this.shape) { + case I -> returnBlock = Block.LIGHT_BLUE_CONCRETE; + case J -> returnBlock = Block.BLUE_CONCRETE; + case L -> returnBlock = Block.ORANGE_CONCRETE; + case O -> returnBlock = Block.YELLOW_CONCRETE; + case S -> returnBlock = Block.GREEN_CONCRETE; + case T -> returnBlock = Block.PURPLE_CONCRETE; + case Z -> returnBlock = Block.RED_CONCRETE; + default -> returnBlock = Block.WHITE_CONCRETE; + } + return returnBlock; + } + private int[][] getTurnedShapeArray(boolean clockwise) { int iterations = 1; if(!clockwise) iterations = 3; @@ -53,17 +108,57 @@ public class Tetromino { return returnArray; } - public void draw(StatelessGame instance, Pos spawnPosition) { + private boolean isPartOfTetromino(Pos position) { + for(Pos blockPosition : getBlockPositions()) { + if(position.sameBlock(blockPosition)) { + return true; + } + } + System.out.println("Not part of Tetromino!!!"); + return false; + } + + private List getBlockPositions() { + List returnList = new ArrayList<>(); + if(this.position == null) return returnList; + int arrayLength = this.shapeArray.length; - AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); - - for(int x=-1; x {}); + return returnList; + } + + private boolean checkCollision(Pos newPosition, int[][] newShapeArray) { + int arrayLength = newShapeArray.length; + + for(int x=0; x Date: Mon, 21 Oct 2024 15:55:54 +0200 Subject: [PATCH 05/30] fixed collision detection, added rotation --- .../game/stateless/types/tetris/Tetris.java | 18 +++-- .../types/tetris/game/Playfield.java | 39 +++++++-- .../types/tetris/game/TetrisGame.java | 81 ++++++++++++++++--- .../types/tetris/game/Tetromino.java | 39 +++++---- 4 files changed, 139 insertions(+), 38 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 3626e30..f873c62 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -50,25 +50,31 @@ class Tetris extends StatelessGame { } protected void pressedButton(Button button) { - if(lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-200) return; + if(lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-100) return; lastPresses.put(button, System.currentTimeMillis()); switch (button) { case A -> { System.out.println("A"); - System.out.println(this.tetrisGame.currentTetromino.moveLeft()); + System.out.println(this.tetrisGame.moveLeft()); } case S -> { System.out.println("S"); - System.out.println(this.tetrisGame.currentTetromino.moveDown()); + System.out.println(this.tetrisGame.moveDown()); } case D -> { System.out.println("D"); - System.out.println(this.tetrisGame.currentTetromino.moveRight()); + System.out.println(this.tetrisGame.moveRight()); } case W -> System.out.println("W"); - case mouseLeft -> System.out.println("mouse left"); - case mouseRight -> System.out.println("mouse right"); + case mouseLeft -> { + System.out.println("mouse left"); + System.out.println(this.tetrisGame.rotate(false)); + } + case mouseRight -> { + System.out.println("mouse right"); + System.out.println(this.tetrisGame.rotate(true)); + } case space -> System.out.println("space"); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index 44bf742..9f1e060 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -8,34 +8,61 @@ import net.minestom.server.instance.block.Block; public class Playfield { private final Pos lowerLeftCorner; + private final StatelessGame instance; - public Playfield(Pos lowerLeftCorner) { + public Playfield(Pos lowerLeftCorner, StatelessGame instance) { this.lowerLeftCorner = lowerLeftCorner; + this.instance = instance; } public Pos getPlayerSpawnPosition() { - return lowerLeftCorner.add(6, 8, 15); + return this.lowerLeftCorner.add(6, 8, 15); } public Pos getTetrominoSpawnPosition() { return this.lowerLeftCorner.add(5, 21, 1); } - public void generate(StatelessGame instance) { + public void generate() { AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); for(int x=0; x<12; x++) { for(int y=0; y<21; y++) { - batch.setBlock(lowerLeftCorner.add(x, y, 0), Block.STONE); + batch.setBlock(this.lowerLeftCorner.add(x, y, 0), Block.STONE); if(x==0 || x==11 || y==0) { - batch.setBlock(lowerLeftCorner.add(x, y, 1), Block.GRAY_CONCRETE); + batch.setBlock(this.lowerLeftCorner.add(x, y, 1), Block.GRAY_CONCRETE); } } } batch.setBlock(getPlayerSpawnPosition().sub(0, 1, 0), Block.STONE); - BatchUtil.loadAndApplyBatch(batch, instance, () -> {}); + BatchUtil.loadAndApplyBatch(batch, this.instance, () -> {}); + } + + public int removeFullLines() { + int removedLinesCounter = 0; + for(int y=1; y<21; y++) { + boolean isFullLine = true; + for(int x=1; x<11; x++) { + if(this.instance.getBlock(this.lowerLeftCorner.add(x, y, 1)) == Block.AIR) isFullLine = false; + } + if(isFullLine) { + removeFullLine(y); + removedLinesCounter += 1; + y -= 1; + } + } + return removedLinesCounter; + } + + private void removeFullLine(int positionY) { + for(int y=positionY; y<21; y++) { + for(int x=1; x<11; x++) { + Block blockAbove = this.instance.getBlock(this.lowerLeftCorner.add(x, y+1, 1)); + this.instance.setBlock(this.lowerLeftCorner.add(x, y, 1), blockAbove); + } + } } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index d3be554..3bd3414 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -11,10 +11,13 @@ import java.util.Random; public class TetrisGame { private final StatelessGame instance; private final Playfield playfield; - private int speed = 1; + private int level = 1; private int lines = 0; + private int score = 0; + private boolean lost = false; public Tetromino currentTetromino; private Tetromino nextTetromino; + private Tetromino holdTetromino; private final Random random = new Random(); private final Pos tetrominoSpawnPosition; @@ -24,10 +27,10 @@ public class TetrisGame { } public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino startTetromino, Tetromino nextTetromino) { - this.playfield = new Playfield(lowerLeftCorner); + this.instance = instance; + this.playfield = new Playfield(lowerLeftCorner, this.instance); this.currentTetromino = startTetromino; this.nextTetromino = nextTetromino; - this.instance = instance; this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition(); } @@ -35,28 +38,53 @@ public class TetrisGame { public void start() { Scheduler scheduler = MinecraftServer.getSchedulerManager(); scheduler.submitTask(() -> { + if(this.lost) return TaskSchedule.stop(); this.tick(); - return TaskSchedule.tick(40/this.speed); + return TaskSchedule.tick(40/this.level); }); } public void generate() { - this.playfield.generate(this.instance); + this.playfield.generate(); this.currentTetromino.setPosition(this.tetrominoSpawnPosition); this.currentTetromino.draw(); } public void tick() { + if(this.lost) return; if(!currentTetromino.moveDown()) { - currentTetromino = nextTetromino; - currentTetromino.setPosition(this.tetrominoSpawnPosition); - currentTetromino.draw(); - nextTetromino = getNextTetromino(); + setActiveTetrominoDown(); } } + public boolean rotate(boolean clockwise) { + if(this.lost) return false; + return this.currentTetromino.rotate(clockwise); + } + + public boolean moveLeft() { + if(this.lost) return false; + return this.currentTetromino.moveLeft(); + } + + public boolean moveRight() { + if(this.lost) return false; + return this.currentTetromino.moveRight(); + } + + public boolean moveDown() { + if(this.lost) return false; + if(!this.currentTetromino.moveDown()) { + this.setActiveTetrominoDown(); + return false; + } + this.score += 1; + return true; + } + + private Tetromino getNextTetromino() { int randomNumber = random.nextInt(1, 7); Tetromino.Shape nextShape; @@ -73,4 +101,39 @@ public class TetrisGame { return new Tetromino(this.instance, nextShape); } + + private void loose() { + this.lost = true; + } + + private void setActiveTetrominoDown() { + currentTetromino = nextTetromino; + nextTetromino = getNextTetromino(); + + int removedLines = this.playfield.removeFullLines(); + switch (removedLines) { + case 1 -> { + this.lines += 1; + this.score += 40 * this.level; + } + case 2 -> { + this.lines += 3; + this.score += 100 * this.level; + } + case 3 -> { + this.lines += 5; + this.score += 300 * this.level; + } + case 4 -> { + this.lines += 8; + this.score += 1200 * this.level; + } + } + + currentTetromino.setPosition(this.tetrominoSpawnPosition); + currentTetromino.draw(); + if(!currentTetromino.moveDown()) { + loose(); + } + } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index 00ddf1e..d95c945 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -5,6 +5,7 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.instance.block.Block; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class Tetromino { @@ -95,14 +96,16 @@ public class Tetromino { if(!clockwise) iterations = 3; int arrayLength = this.shapeArray.length; + int[][] startArray = Arrays.stream(this.shapeArray).map(int[]::clone).toArray(int[][]::new); int[][] returnArray = new int[arrayLength][arrayLength]; for(int k=0; k getBlockPositions() { - List returnList = new ArrayList<>(); - if(this.position == null) return returnList; + return this.getBlockPositions(this.position, this.shapeArray); + } - int arrayLength = this.shapeArray.length; + private List getBlockPositions(Pos position, int[][] shapeArray) { + List returnList = new ArrayList<>(); + if(position == null) return returnList; + + int arrayLength = shapeArray.length; for(int x=0; x returnList.add(position.add(x-1, y-2, 0)); + case O -> returnList.add(position.add(x, y, 0)); + default -> returnList.add(position.add(x-1, y-1, 0)); + } } } } @@ -136,25 +146,20 @@ public class Tetromino { } private boolean checkCollision(Pos newPosition, int[][] newShapeArray) { - int arrayLength = newShapeArray.length; + List newBlockPositions = getBlockPositions(newPosition, newShapeArray); - for(int x=0; x Date: Mon, 21 Oct 2024 19:22:31 +0200 Subject: [PATCH 06/30] changed background, added hold, show score --- .../game/stateless/types/tetris/Tetris.java | 27 ++++- .../types/tetris/game/Playfield.java | 13 +- .../types/tetris/game/TetrisGame.java | 112 ++++++++++++++---- 3 files changed, 122 insertions(+), 30 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index f873c62..fa4763a 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -66,7 +66,12 @@ class Tetris extends StatelessGame { System.out.println("D"); System.out.println(this.tetrisGame.moveRight()); } - case W -> System.out.println("W"); + case W -> { + System.out.println("W"); + while(this.tetrisGame.moveDown()) { + this.tetrisGame.addPoints(2); + } + } case mouseLeft -> { System.out.println("mouse left"); System.out.println(this.tetrisGame.rotate(false)); @@ -75,7 +80,10 @@ class Tetris extends StatelessGame { System.out.println("mouse right"); System.out.println(this.tetrisGame.rotate(true)); } - case space -> System.out.println("space"); + case space -> { + System.out.println("space"); + System.out.println(this.tetrisGame.switchHold()); + } } } @@ -91,7 +99,10 @@ class Tetris extends StatelessGame { @Override protected void onPlayerMove(@NotNull PlayerMoveEvent event) { - super.onPlayerMove(event); +// if(!getSpawn().withView(event.getNewPosition()).equals(event.getNewPosition())) { +// event.setCancelled(true); +// event.getPlayer().setSprinting(false); +// } Player player = event.getPlayer(); Pos previousPosition = event.getPlayer().getPosition(); @@ -135,7 +146,7 @@ class Tetris extends StatelessGame { if(previousPosition.y() < currentPosition.y()) pressedButton(Button.space); - event.setNewPosition(getSpawn().withView(event.getNewPosition())); +// event.setNewPosition(getSpawn().withView(event.getNewPosition())); } protected void onPlayerInteract(@NotNull PlayerUseItemEvent event) { @@ -150,6 +161,14 @@ class Tetris extends StatelessGame { protected boolean onPlayerJoin(Player p) { p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build()); p.setSprinting(false); + +// p.setGameMode(GameMode.SPECTATOR); +// Entity anvil = new Entity(EntityType.FALLING_BLOCK); +// ((FallingBlockMeta) anvil.getEntityMeta()).setBlock(Block.ANVIL); +// anvil.setInstance(this, getSpawn()); +// anvil.addPassenger(p); + + this.tetrisGame.sidebar.addViewer(p); return super.onPlayerJoin(p); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index 9f1e060..601f250 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -23,12 +23,17 @@ public class Playfield { return this.lowerLeftCorner.add(5, 21, 1); } + public Pos getHoldPosition() { + return this.lowerLeftCorner.add(-4, 19, 0); + } + public void generate() { AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); for(int x=0; x<12; x++) { - for(int y=0; y<21; y++) { - batch.setBlock(this.lowerLeftCorner.add(x, y, 0), Block.STONE); + for(int y=0; y<22; y++) { + batch.setBlock(this.lowerLeftCorner.add(x, y, 0), Block.GLASS); + batch.setBlock(this.lowerLeftCorner.add(x, y, -1), Block.BLACK_CONCRETE); if(x==0 || x==11 || y==0) { batch.setBlock(this.lowerLeftCorner.add(x, y, 1), Block.GRAY_CONCRETE); @@ -43,7 +48,7 @@ public class Playfield { public int removeFullLines() { int removedLinesCounter = 0; - for(int y=1; y<21; y++) { + for(int y=1; y<22; y++) { boolean isFullLine = true; for(int x=1; x<11; x++) { if(this.instance.getBlock(this.lowerLeftCorner.add(x, y, 1)) == Block.AIR) isFullLine = false; @@ -58,7 +63,7 @@ public class Playfield { } private void removeFullLine(int positionY) { - for(int y=positionY; y<21; y++) { + for(int y=positionY; y<22; y++) { for(int x=1; x<11; x++) { Block blockAbove = this.instance.getBlock(this.lowerLeftCorner.add(x, y+1, 1)); this.instance.setBlock(this.lowerLeftCorner.add(x, y, 1), blockAbove); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 3bd3414..e18b192 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -1,11 +1,16 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; +import net.kyori.adventure.text.Component; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; +import net.minestom.server.scoreboard.Sidebar; import net.minestom.server.timer.Scheduler; import net.minestom.server.timer.TaskSchedule; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Random; public class TetrisGame { @@ -15,12 +20,15 @@ public class TetrisGame { private int lines = 0; private int score = 0; private boolean lost = false; + public boolean paused = true; public Tetromino currentTetromino; private Tetromino nextTetromino; private Tetromino holdTetromino; - private final Random random = new Random(); - + private final List tetrominoBag = new ArrayList<>(); + private boolean holdPossible = true; + private final Pos holdPosition; private final Pos tetrominoSpawnPosition; + public Sidebar sidebar = new Sidebar(Component.text("Info:")); public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) { this(instance, lowerLeftCorner, new Tetromino(instance, Tetromino.Shape.J), new Tetromino(instance, Tetromino.Shape.T)); @@ -32,13 +40,17 @@ public class TetrisGame { this.currentTetromino = startTetromino; this.nextTetromino = nextTetromino; + this.holdPosition = this.playfield.getHoldPosition(); this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition(); + this.buildSidebar(); } public void start() { + this.paused = false; Scheduler scheduler = MinecraftServer.getSchedulerManager(); scheduler.submitTask(() -> { if(this.lost) return TaskSchedule.stop(); + if(this.paused) return TaskSchedule.tick(40/this.level); this.tick(); return TaskSchedule.tick(40/this.level); }); @@ -52,60 +64,111 @@ public class TetrisGame { } public void tick() { - if(this.lost) return; + if(this.lost || this.paused) return; if(!currentTetromino.moveDown()) { setActiveTetrominoDown(); } } + public void addPoints(int points) { + this.score += points; + this.updateSidebar(); + } + public boolean rotate(boolean clockwise) { - if(this.lost) return false; + if(this.lost || this.paused) return false; return this.currentTetromino.rotate(clockwise); } public boolean moveLeft() { - if(this.lost) return false; + if(this.lost || this.paused) return false; return this.currentTetromino.moveLeft(); } public boolean moveRight() { - if(this.lost) return false; + if(this.lost || this.paused) return false; return this.currentTetromino.moveRight(); } public boolean moveDown() { - if(this.lost) return false; + if(this.lost || this.paused) return false; if(!this.currentTetromino.moveDown()) { this.setActiveTetrominoDown(); return false; } this.score += 1; + this.updateSidebar(); + return true; + } + + public boolean switchHold() { + if(!holdPossible) return false; + if(this.lost || this.paused) return false; + + Tetromino newCurrentTetromino; + if(this.holdTetromino == null) { + newCurrentTetromino = this.nextTetromino; + this.nextTetromino = this.getNextTetromino(); + } else { + newCurrentTetromino = this.holdTetromino; + this.holdTetromino.remove(); + } + + this.currentTetromino.remove(); + this.holdTetromino = this.currentTetromino; + this.currentTetromino = newCurrentTetromino; + + this.currentTetromino.setPosition(this.tetrominoSpawnPosition); + this.currentTetromino.draw(); + if(!this.currentTetromino.moveDown()) loose(); + + this.holdTetromino.setPosition(this.holdPosition); + this.holdTetromino.draw(); + this.holdPossible = false; return true; } private Tetromino getNextTetromino() { - int randomNumber = random.nextInt(1, 7); - Tetromino.Shape nextShape; - - switch (randomNumber) { - case 2 -> nextShape = Tetromino.Shape.J; - case 3 -> nextShape = Tetromino.Shape.L; - case 4 -> nextShape = Tetromino.Shape.O; - case 5 -> nextShape = Tetromino.Shape.S; - case 6 -> nextShape = Tetromino.Shape.T; - case 7 -> nextShape = Tetromino.Shape.Z; - default -> nextShape = Tetromino.Shape.I; + if(this.tetrominoBag.isEmpty()) { + for(Tetromino.Shape shape : Tetromino.Shape.values()) { + this.tetrominoBag.add(new Tetromino(this.instance, shape)); + } + Collections.shuffle(this.tetrominoBag); } - return new Tetromino(this.instance, nextShape); + return this.tetrominoBag.removeFirst(); } private void loose() { this.lost = true; } + private void buildSidebar() { + this.sidebar.createLine(new Sidebar.ScoreboardLine( + "0", + Component.text("Score: "), + 0 + )); + this.sidebar.createLine(new Sidebar.ScoreboardLine( + "1", + Component.text("Lines: "), + 0 + )); + this.sidebar.createLine(new Sidebar.ScoreboardLine( + "2", + Component.text("Level: "), + 1 + )); + } + + private void updateSidebar() { + this.sidebar.updateLineScore("0", this.score); + this.sidebar.updateLineScore("1", this.lines); + this.sidebar.updateLineScore("2", this.level); + } + private void setActiveTetrominoDown() { currentTetromino = nextTetromino; nextTetromino = getNextTetromino(); @@ -117,19 +180,24 @@ public class TetrisGame { this.score += 40 * this.level; } case 2 -> { - this.lines += 3; + this.lines += 2; this.score += 100 * this.level; } case 3 -> { - this.lines += 5; + this.lines += 3; this.score += 300 * this.level; } case 4 -> { - this.lines += 8; + this.lines += 4; this.score += 1200 * this.level; } } + this.level = (int) Math.floor((double) this.lines / 10) + 1; + this.holdPossible = true; + + this.updateSidebar(); + currentTetromino.setPosition(this.tetrominoSpawnPosition); currentTetromino.draw(); if(!currentTetromino.moveDown()) { From f56023004a7c157a73a8b0a00541a03f05b72015 Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 21 Oct 2024 19:22:51 +0200 Subject: [PATCH 07/30] removed unused import --- .../instance/game/stateless/types/tetris/game/TetrisGame.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index e18b192..404d426 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -11,7 +11,6 @@ import net.minestom.server.timer.TaskSchedule; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Random; public class TetrisGame { private final StatelessGame instance; From 710838645fc0fb0afc8ffc5da58a30798373d752 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 22 Oct 2024 00:36:57 +0200 Subject: [PATCH 08/30] added ghost tetromino --- .../game/stateless/types/tetris/Tetris.java | 23 +++++------ .../types/tetris/game/Playfield.java | 28 ++++++++++++-- .../types/tetris/game/TetrisGame.java | 38 ++++++++++++------- .../types/tetris/game/Tetromino.java | 26 ++++++++++--- 4 files changed, 78 insertions(+), 37 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index fa4763a..ed29ff8 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -93,21 +93,20 @@ class Tetris extends StatelessGame { @Override protected void onLoad(@NotNull CompletableFuture callback) { - this.tetrisGame = new TetrisGame(this, getSpawn().sub(6, 8, 15)); - this.tetrisGame.generate(); + } @Override protected void onPlayerMove(@NotNull PlayerMoveEvent event) { -// if(!getSpawn().withView(event.getNewPosition()).equals(event.getNewPosition())) { -// event.setCancelled(true); -// event.getPlayer().setSprinting(false); -// } - Player player = event.getPlayer(); Pos previousPosition = event.getPlayer().getPosition(); Pos currentPosition = event.getNewPosition(); + if(this.tetrisGame == null) return; + + event.setNewPosition(this.tetrisGame.getPlayerSpawnPosition().withView(event.getNewPosition())); + player.setSprinting(false); + Vec movementVector = currentPosition.asVec().sub(previousPosition.asVec()); float yaw = player.getPosition().yaw(); @@ -145,8 +144,6 @@ class Tetris extends StatelessGame { } if(previousPosition.y() < currentPosition.y()) pressedButton(Button.space); - -// event.setNewPosition(getSpawn().withView(event.getNewPosition())); } protected void onPlayerInteract(@NotNull PlayerUseItemEvent event) { @@ -162,11 +159,9 @@ class Tetris extends StatelessGame { p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build()); p.setSprinting(false); -// p.setGameMode(GameMode.SPECTATOR); -// Entity anvil = new Entity(EntityType.FALLING_BLOCK); -// ((FallingBlockMeta) anvil.getEntityMeta()).setBlock(Block.ANVIL); -// anvil.setInstance(this, getSpawn()); -// anvil.addPassenger(p); + this.tetrisGame = new TetrisGame(this, getSpawn().sub(6, 8, 15)); + this.tetrisGame.generate(); + p.teleport(this.tetrisGame.getPlayerSpawnPosition()); this.tetrisGame.sidebar.addViewer(p); return super.onPlayerJoin(p); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index 601f250..882c221 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -9,6 +9,7 @@ import net.minestom.server.instance.block.Block; public class Playfield { private final Pos lowerLeftCorner; private final StatelessGame instance; + private final int height = 22; public Playfield(Pos lowerLeftCorner, StatelessGame instance) { this.lowerLeftCorner = lowerLeftCorner; @@ -16,7 +17,7 @@ public class Playfield { } public Pos getPlayerSpawnPosition() { - return this.lowerLeftCorner.add(6, 8, 15); + return this.lowerLeftCorner.add(6, 8, 20); } public Pos getTetrominoSpawnPosition() { @@ -27,28 +28,36 @@ public class Playfield { return this.lowerLeftCorner.add(-4, 19, 0); } + public Pos getNextPosition() { + return this.lowerLeftCorner.add(14, 19, 0); + } + public void generate() { AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); for(int x=0; x<12; x++) { - for(int y=0; y<22; y++) { + for(int y=0; y {}); } public int removeFullLines() { int removedLinesCounter = 0; - for(int y=1; y<22; y++) { + for(int y=1; y tetrominoBag = new ArrayList<>(); private boolean holdPossible = true; + private final Pos nextPosition; private final Pos holdPosition; private final Pos tetrominoSpawnPosition; public Sidebar sidebar = new Sidebar(Component.text("Info:")); public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) { - this(instance, lowerLeftCorner, new Tetromino(instance, Tetromino.Shape.J), new Tetromino(instance, Tetromino.Shape.T)); + this(instance, lowerLeftCorner, Tetromino.Shape.J); } - public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino startTetromino, Tetromino nextTetromino) { + public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino.Shape startTetrominoShape) { this.instance = instance; this.playfield = new Playfield(lowerLeftCorner, this.instance); - this.currentTetromino = startTetromino; - this.nextTetromino = nextTetromino; this.holdPosition = this.playfield.getHoldPosition(); + this.nextPosition = this.playfield.getNextPosition(); this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition(); this.buildSidebar(); + + this.currentTetromino = new Tetromino(this.instance, startTetrominoShape, this.playfield); + this.nextTetromino = this.getNextTetromino(); + } + + public Pos getPlayerSpawnPosition() { + return this.playfield.getPlayerSpawnPosition(); } public void start() { @@ -115,7 +122,7 @@ public class TetrisGame { } this.currentTetromino.remove(); - this.holdTetromino = this.currentTetromino; + this.holdTetromino = new Tetromino(this.instance, this.currentTetromino.shape, this.playfield); this.currentTetromino = newCurrentTetromino; this.currentTetromino.setPosition(this.tetrominoSpawnPosition); @@ -123,7 +130,7 @@ public class TetrisGame { if(!this.currentTetromino.moveDown()) loose(); this.holdTetromino.setPosition(this.holdPosition); - this.holdTetromino.draw(); + this.holdTetromino.draw(false); this.holdPossible = false; return true; } @@ -132,12 +139,17 @@ public class TetrisGame { private Tetromino getNextTetromino() { if(this.tetrominoBag.isEmpty()) { for(Tetromino.Shape shape : Tetromino.Shape.values()) { - this.tetrominoBag.add(new Tetromino(this.instance, shape)); + this.tetrominoBag.add(new Tetromino(this.instance, shape, this.playfield)); } Collections.shuffle(this.tetrominoBag); } - return this.tetrominoBag.removeFirst(); + if(this.nextTetromino != null) this.nextTetromino.remove(); + Tetromino tetromino = this.tetrominoBag.removeFirst(); + tetromino.setPosition(this.nextPosition); + tetromino.draw(false); + + return tetromino; } private void loose() { @@ -169,8 +181,8 @@ public class TetrisGame { } private void setActiveTetrominoDown() { - currentTetromino = nextTetromino; - nextTetromino = getNextTetromino(); + this.currentTetromino = this.nextTetromino; + this.nextTetromino = getNextTetromino(); int removedLines = this.playfield.removeFullLines(); switch (removedLines) { @@ -197,9 +209,9 @@ public class TetrisGame { this.updateSidebar(); - currentTetromino.setPosition(this.tetrominoSpawnPosition); - currentTetromino.draw(); - if(!currentTetromino.moveDown()) { + this.currentTetromino.setPosition(this.tetrominoSpawnPosition); + this.currentTetromino.draw(); + if(!this.currentTetromino.moveDown()) { loose(); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index d95c945..bd5b56d 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -9,10 +9,12 @@ import java.util.Arrays; import java.util.List; public class Tetromino { - private final Shape shape; + public final Shape shape; private final StatelessGame instance; + private final Playfield playfield; private Pos position; private int[][] shapeArray; + private final Block ghostBlock = Block.ICE; public enum Shape { I, @@ -24,9 +26,10 @@ public class Tetromino { Z } - public Tetromino(StatelessGame instance, Shape shape) { + public Tetromino(StatelessGame instance, Shape shape, Playfield playfield) { this.instance = instance; this.shape = shape; + this.playfield = playfield; switch (this.shape) { case I -> shapeArray = new int[][]{{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}}; @@ -39,10 +42,6 @@ public class Tetromino { } } - public Pos getPosition() { - return this.position; - } - public void setPosition(Pos newPosition) { this.position = newPosition; } @@ -68,6 +67,20 @@ public class Tetromino { } public void draw() { + this.draw(true); + } + + public void draw(boolean withGhost) { + if(withGhost) { + this.playfield.removeBlock(this.ghostBlock); + Pos ghostPos = this.position; + while (!checkCollision(ghostPos.sub(0, 1, 0), this.shapeArray)) { + ghostPos = ghostPos.sub(0, 1, 0); + } + Pos positionChange = this.position.sub(ghostPos); + getBlockPositions().forEach(pos -> this.instance.setBlock(pos.sub(positionChange), this.ghostBlock)); + } + getBlockPositions().forEach(pos -> this.instance.setBlock(pos, this.getColoredBlock())); } @@ -150,6 +163,7 @@ public class Tetromino { for(Pos pos : newBlockPositions) { if(isPartOfTetromino(pos)) continue; + if(this.instance.getBlock(pos) == this.ghostBlock) continue; if(this.instance.getBlock(pos) != Block.AIR) return true; } From 2799a40c589a6a40cd77419b3b3fb08501cb8e8b Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 22 Oct 2024 15:51:00 +0200 Subject: [PATCH 09/30] made multiplayer possible --- .../game/stateless/types/tetris/Tetris.java | 137 +++++++----------- .../types/tetris/game/Playfield.java | 36 +++-- .../types/tetris/game/TetrisGame.java | 66 +++++++-- .../types/tetris/game/Tetromino.java | 37 ++++- 4 files changed, 156 insertions(+), 120 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index ed29ff8..5ccef02 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -2,12 +2,15 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.TetrisGame; -import eu.mhsl.minenet.minigames.score.FirstWinsScore; import eu.mhsl.minenet.minigames.instance.Dimension; +import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.Tetromino; +import eu.mhsl.minenet.minigames.score.LastWinsScore; import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; import net.minestom.server.event.player.*; import net.minestom.server.item.ItemStack; @@ -16,84 +19,36 @@ import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.CompletableFuture; class Tetris extends StatelessGame { - private TetrisGame tetrisGame; - - private final Map lastPresses = new HashMap<>(); - - enum Button { - W, - A, - S, - D, - mouseLeft, - mouseRight, - space - } + private final Map tetrisGames = new HashMap<>(); public Tetris() { - super(Dimension.THE_END.key, "Tetris", new FirstWinsScore()); + super(Dimension.THE_END.key, "Tetris", new LastWinsScore()); this.setGenerator(new CircularPlateTerrainGenerator(30).setPlateHeight(0)); eventNode() .addListener(PlayerUseItemEvent.class, this::onPlayerInteract) - .addListener(PlayerHandAnimationEvent.class, this::onPlayerAttack); + .addListener(PlayerHandAnimationEvent.class, this::onPlayerAttack) + .addListener(PlayerTickEvent.class, this::onPlayerTick); } @Override protected void onStart() { - super.onStart(); - - this.tetrisGame.start(); - } - - protected void pressedButton(Button button) { - if(lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-100) return; - lastPresses.put(button, System.currentTimeMillis()); - - switch (button) { - case A -> { - System.out.println("A"); - System.out.println(this.tetrisGame.moveLeft()); - } - case S -> { - System.out.println("S"); - System.out.println(this.tetrisGame.moveDown()); - } - case D -> { - System.out.println("D"); - System.out.println(this.tetrisGame.moveRight()); - } - case W -> { - System.out.println("W"); - while(this.tetrisGame.moveDown()) { - this.tetrisGame.addPoints(2); - } - } - case mouseLeft -> { - System.out.println("mouse left"); - System.out.println(this.tetrisGame.rotate(false)); - } - case mouseRight -> { - System.out.println("mouse right"); - System.out.println(this.tetrisGame.rotate(true)); - } - case space -> { - System.out.println("space"); - System.out.println(this.tetrisGame.switchHold()); - } - } - } - - protected void releasedButton(Button button) { - lastPresses.put(button, 0L); + this.getEntities().stream() + .filter(entity -> entity.getEntityType().equals(Tetromino.getGhostEntityType())) + .forEach(Entity::remove); + this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.start()); } @Override - protected void onLoad(@NotNull CompletableFuture callback) { + protected void onStop() { + this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.sidebar.removeViewer(player)); + } + @Override + protected void onPlayerLeave(Player p) { + this.tetrisGames.get(p).sidebar.removeViewer(p); } @Override @@ -102,9 +57,13 @@ class Tetris extends StatelessGame { Pos previousPosition = event.getPlayer().getPosition(); Pos currentPosition = event.getNewPosition(); - if(this.tetrisGame == null) return; + TetrisGame tetrisGame = this.tetrisGames.get(player); - event.setNewPosition(this.tetrisGame.getPlayerSpawnPosition().withView(event.getNewPosition())); + if(tetrisGame == null) return; + if(tetrisGame.lost) return; + if(player.getGameMode() == GameMode.SPECTATOR) return; + + event.setNewPosition(tetrisGame.getPlayerSpawnPosition().withView(currentPosition)); player.setSprinting(false); Vec movementVector = currentPosition.asVec().sub(previousPosition.asVec()); @@ -122,36 +81,36 @@ class Tetris extends StatelessGame { double leftAmount = movementVector.dot(left); if (forwardAmount > 0.018) { - pressedButton(Button.W); - releasedButton(Button.S); + tetrisGame.pressedButton(TetrisGame.Button.W); } else if (forwardAmount < -0.018) { - pressedButton(Button.S); - releasedButton(Button.W); - } else { - releasedButton(Button.W); - releasedButton(Button.S); + tetrisGame.pressedButton(TetrisGame.Button.S); } if (leftAmount > 0.018) { - pressedButton(Button.D); - releasedButton(Button.A); + tetrisGame.pressedButton(TetrisGame.Button.D); } else if (leftAmount < -0.018) { - pressedButton(Button.A); - releasedButton(Button.D); - } else { - releasedButton(Button.A); - releasedButton(Button.D); + tetrisGame.pressedButton(TetrisGame.Button.A); } - if(previousPosition.y() < currentPosition.y()) pressedButton(Button.space); + if(previousPosition.y() < currentPosition.y()) tetrisGame.pressedButton(TetrisGame.Button.space); } protected void onPlayerInteract(@NotNull PlayerUseItemEvent event) { - pressedButton(Button.mouseRight); + this.tetrisGames.get(event.getPlayer()).pressedButton(TetrisGame.Button.mouseRight); } protected void onPlayerAttack(@NotNull PlayerHandAnimationEvent event) { - pressedButton(Button.mouseLeft); + this.tetrisGames.get(event.getPlayer()).pressedButton(TetrisGame.Button.mouseLeft); + } + + protected void onPlayerTick(PlayerTickEvent event) { + TetrisGame tetrisGame = this.tetrisGames.get(event.getPlayer()); + if(tetrisGame == null) return; + if(tetrisGame.lost && event.getPlayer().getGameMode() != GameMode.SPECTATOR) { + event.getPlayer().setGameMode(GameMode.SPECTATOR); + getScore().insertResult(event.getPlayer()); + tetrisGame.sidebar.removeViewer(event.getPlayer()); + } } @Override @@ -159,16 +118,20 @@ class Tetris extends StatelessGame { p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build()); p.setSprinting(false); - this.tetrisGame = new TetrisGame(this, getSpawn().sub(6, 8, 15)); - this.tetrisGame.generate(); - p.teleport(this.tetrisGame.getPlayerSpawnPosition()); + if(this.tetrisGames.get(p) == null) { + this.tetrisGames.put(p, new TetrisGame(this, getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*23, 0, 0))); + this.tetrisGames.get(p).generate(); + } + TetrisGame tetrisGame = this.tetrisGames.get(p); + + p.teleport(tetrisGame.getPlayerSpawnPosition()); + tetrisGame.sidebar.addViewer(p); - this.tetrisGame.sidebar.addViewer(p); return super.onPlayerJoin(p); } @Override public Pos getSpawn() { - return new Pos(0, 50, 15).withView(180, 0); + return new Pos(-50, 50, 15).withView(180, 0); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index 882c221..819f013 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -3,13 +3,15 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.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.entity.Entity; +import net.minestom.server.entity.EntityType; import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.block.Block; public class Playfield { private final Pos lowerLeftCorner; private final StatelessGame instance; - private final int height = 22; + private final static int height = 22; public Playfield(Pos lowerLeftCorner, StatelessGame instance) { this.lowerLeftCorner = lowerLeftCorner; @@ -17,7 +19,8 @@ public class Playfield { } public Pos getPlayerSpawnPosition() { - return this.lowerLeftCorner.add(6, 8, 20); +// return this.lowerLeftCorner.add(6.5, 9+((double) 3/16), 20.5).withView(180, 0); + return this.lowerLeftCorner.add(6.5, 9, 20.5).withView(180, 0); } public Pos getTetrominoSpawnPosition() { @@ -36,7 +39,7 @@ public class Playfield { AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); for(int x=0; x<12; x++) { - for(int y=0; y {}); } public int removeFullLines() { int removedLinesCounter = 0; - for(int y=1; y entity.getEntityType().equals(entityType)) + .filter(entity -> { + Pos position = entity.getPosition(); + if(position.x() > this.lowerLeftCorner.x() && position.y() > this.lowerLeftCorner.y()) { + return position.x() < this.lowerLeftCorner.x() + 11 && position.y() < this.lowerLeftCorner.y() + height; } - } - } + return false; + }) + .forEach(Entity::remove); } private void removeFullLine(int positionY) { - for(int y=positionY; y lastPresses = new HashMap<>(); + + public enum Button { + W, + A, + S, + D, + mouseLeft, + mouseRight, + space + } public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) { this(instance, lowerLeftCorner, Tetromino.Shape.J); @@ -47,6 +56,24 @@ public class TetrisGame { this.nextTetromino = this.getNextTetromino(); } + public void pressedButton(Button button) { + if(lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-100) return; + + lastPresses.put(button, System.currentTimeMillis()); + if(button == Button.W) lastPresses.put(button, System.currentTimeMillis()+70); + if(button == Button.S) lastPresses.put(button, System.currentTimeMillis()-70); + + switch (button) { + case A -> this.moveLeft(); + case S -> this.moveDown(); + case D -> this.moveRight(); + case W -> this.hardDrop(); + case mouseLeft -> this.rotate(false); + case mouseRight -> this.rotate(true); + case space -> this.switchHold(); + } + } + public Pos getPlayerSpawnPosition() { return this.playfield.getPlayerSpawnPosition(); } @@ -76,28 +103,23 @@ public class TetrisGame { } } - public void addPoints(int points) { - this.score += points; - this.updateSidebar(); - } - - public boolean rotate(boolean clockwise) { + private boolean rotate(boolean clockwise) { if(this.lost || this.paused) return false; return this.currentTetromino.rotate(clockwise); } - public boolean moveLeft() { + private boolean moveLeft() { if(this.lost || this.paused) return false; return this.currentTetromino.moveLeft(); } - public boolean moveRight() { + private boolean moveRight() { if(this.lost || this.paused) return false; return this.currentTetromino.moveRight(); } - public boolean moveDown() { + private boolean moveDown() { if(this.lost || this.paused) return false; if(!this.currentTetromino.moveDown()) { this.setActiveTetrominoDown(); @@ -108,7 +130,23 @@ public class TetrisGame { return true; } - public boolean switchHold() { + private boolean hardDrop() { + if(this.lost || this.paused) return false; + if(!this.currentTetromino.moveDown()) { + this.setActiveTetrominoDown(); + return false; + } + this.score += 2; + this.updateSidebar(); + while(this.currentTetromino.moveDown()) { + this.score += 2; + this.updateSidebar(); + } + this.setActiveTetrominoDown(); + return true; + } + + private boolean switchHold() { if(!holdPossible) return false; if(this.lost || this.paused) return false; diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index bd5b56d..06f41d3 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -2,6 +2,9 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.metadata.other.FallingBlockMeta; import net.minestom.server.instance.block.Block; import java.util.ArrayList; @@ -14,7 +17,7 @@ public class Tetromino { private final Playfield playfield; private Pos position; private int[][] shapeArray; - private final Block ghostBlock = Block.ICE; + private final static EntityType ghostEntityType = EntityType.FALLING_BLOCK; public enum Shape { I, @@ -42,6 +45,10 @@ public class Tetromino { } } + public static EntityType getGhostEntityType() { + return ghostEntityType; + } + public void setPosition(Pos newPosition) { this.position = newPosition; } @@ -72,13 +79,20 @@ public class Tetromino { public void draw(boolean withGhost) { if(withGhost) { - this.playfield.removeBlock(this.ghostBlock); + this.playfield.removeEntity(ghostEntityType); Pos ghostPos = this.position; while (!checkCollision(ghostPos.sub(0, 1, 0), this.shapeArray)) { ghostPos = ghostPos.sub(0, 1, 0); } Pos positionChange = this.position.sub(ghostPos); - getBlockPositions().forEach(pos -> this.instance.setBlock(pos.sub(positionChange), this.ghostBlock)); + getBlockPositions().forEach(pos -> { + Entity ghostBlock = new Entity(ghostEntityType); + ((FallingBlockMeta) ghostBlock.getEntityMeta()).setBlock(this.getGhostBlock()); + ghostBlock.setNoGravity(true); + ghostBlock.setGlowing(true); + ghostBlock.setInvisible(true); + ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(0.5, 0, 0.5)); + }); } getBlockPositions().forEach(pos -> this.instance.setBlock(pos, this.getColoredBlock())); @@ -104,6 +118,21 @@ public class Tetromino { return returnBlock; } + private Block getGhostBlock() { + Block returnBlock; + switch (this.shape) { + case I -> returnBlock = Block.LIGHT_BLUE_STAINED_GLASS; + case J -> returnBlock = Block.BLUE_STAINED_GLASS; + case L -> returnBlock = Block.ORANGE_STAINED_GLASS; + case O -> returnBlock = Block.YELLOW_STAINED_GLASS; + case S -> returnBlock = Block.GREEN_STAINED_GLASS; + case T -> returnBlock = Block.PURPLE_STAINED_GLASS; + case Z -> returnBlock = Block.RED_STAINED_GLASS; + default -> returnBlock = Block.WHITE_STAINED_GLASS; + } + return returnBlock; + } + private int[][] getTurnedShapeArray(boolean clockwise) { int iterations = 1; if(!clockwise) iterations = 3; @@ -163,7 +192,7 @@ public class Tetromino { for(Pos pos : newBlockPositions) { if(isPartOfTetromino(pos)) continue; - if(this.instance.getBlock(pos) == this.ghostBlock) continue; + if(this.instance.getBlock(pos) == this.getGhostBlock()) continue; if(this.instance.getBlock(pos) != Block.AIR) return true; } From 1b448e749e4f410cb2a8c850472c9a6578541117 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 22 Oct 2024 16:34:23 +0200 Subject: [PATCH 10/30] fixed leaderboard with new PointsWinScore class --- .../game/stateless/types/tetris/Tetris.java | 6 +-- .../types/tetris/game/TetrisGame.java | 4 ++ .../minigames/score/FirstWinsScore.java | 10 +++++ .../minigames/score/LastWinsScore.java | 12 +++++- .../mhsl/minenet/minigames/score/NoScore.java | 10 +++++ .../minigames/score/PointsWinScore.java | 40 +++++++++++++++++++ .../mhsl/minenet/minigames/score/Score.java | 6 +++ .../mhsl/minenet/minigames/util/MapUtil.java | 20 ++++++++++ 8 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java create mode 100644 src/main/java/eu/mhsl/minenet/minigames/util/MapUtil.java diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 5ccef02..adfab17 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -4,7 +4,7 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.TetrisGame; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.Tetromino; -import eu.mhsl.minenet.minigames.score.LastWinsScore; +import eu.mhsl.minenet.minigames.score.PointsWinScore; import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Pos; @@ -24,7 +24,7 @@ class Tetris extends StatelessGame { private final Map tetrisGames = new HashMap<>(); public Tetris() { - super(Dimension.THE_END.key, "Tetris", new LastWinsScore()); + super(Dimension.THE_END.key, "Tetris", new PointsWinScore()); this.setGenerator(new CircularPlateTerrainGenerator(30).setPlateHeight(0)); eventNode() @@ -108,7 +108,7 @@ class Tetris extends StatelessGame { if(tetrisGame == null) return; if(tetrisGame.lost && event.getPlayer().getGameMode() != GameMode.SPECTATOR) { event.getPlayer().setGameMode(GameMode.SPECTATOR); - getScore().insertResult(event.getPlayer()); + getScore().insertResult(event.getPlayer(), tetrisGame.getScore()); tetrisGame.sidebar.removeViewer(event.getPlayer()); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 6fecba9..c32c4d4 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -103,6 +103,10 @@ public class TetrisGame { } } + public int getScore() { + return this.score; + } + private boolean rotate(boolean clockwise) { if(this.lost || this.paused) return false; diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/FirstWinsScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/FirstWinsScore.java index bc505dd..9595e6f 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/FirstWinsScore.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/FirstWinsScore.java @@ -8,11 +8,21 @@ import java.time.Duration; import java.util.Set; public class FirstWinsScore extends Score { + @Override + public void insertResultImplementation(Set p, int points) { + + } + @Override public void insertResultImplementation(Set p) { getScores().add(p); } + @Override + public void insertResult(Player p, int points) { + + } + @Override protected TranslatableMessage scoreMessage() { return new TitleMessage(Duration.ofMillis(1000), Duration.ofSeconds(1)).appendTranslated("score#finish"); diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/LastWinsScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/LastWinsScore.java index c2bae16..c4a40b3 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/LastWinsScore.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/LastWinsScore.java @@ -8,9 +8,19 @@ import java.time.Duration; import java.util.Set; public class LastWinsScore extends Score { + @Override + public void insertResultImplementation(Set p, int points) { + + } + @Override public void insertResultImplementation(Set p) { - getScores().add(0, p); + getScores().addFirst(p); + } + + @Override + public void insertResult(Player p, int points) { + } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/NoScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/NoScore.java index 91478d5..232d874 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/NoScore.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/NoScore.java @@ -10,11 +10,21 @@ public class NoScore extends Score { protected void checkGameEnd() { } + @Override + public void insertResultImplementation(Set p, int points) { + + } + @Override public void insertResultImplementation(Set p) { } + @Override + public void insertResult(Player p, int points) { + + } + @Override protected TranslatableMessage scoreMessage() { return null; diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java new file mode 100644 index 0000000..5164e65 --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java @@ -0,0 +1,40 @@ +package eu.mhsl.minenet.minigames.score; + +import eu.mhsl.minenet.minigames.message.TranslatableMessage; +import eu.mhsl.minenet.minigames.message.type.TitleMessage; +import eu.mhsl.minenet.minigames.util.MapUtil; +import net.minestom.server.entity.Player; +import org.apache.commons.lang3.NotImplementedException; + +import java.time.Duration; +import java.util.*; + +public class PointsWinScore extends Score { + private Map, Integer> scoreOrder = new HashMap<>(); + + @Override + public void insertResultImplementation(Set p, int points) { + this.scoreOrder.put(p, points); + this.scoreOrder = MapUtil.sortByValue(this.scoreOrder); + getScores().clear(); + this.scoreOrder.forEach((player, integer) -> getScores().addFirst(player)); + } + + @Override + protected void insertResultImplementation(Set p) { + throw new NotImplementedException("PointsWinScore does not support adding entries without points"); + } + + @Override + public void insertResult(Player p, int points) { + if(hasResult(p)) return; + this.scoreMessage().send(p); + this.insertResultImplementation(Set.of(p), points); + this.checkGameEnd(); + } + + @Override + protected TranslatableMessage scoreMessage() { + return new TitleMessage(Duration.ofMillis(1000), Duration.ofSeconds(1)).appendTranslated("score#death"); + } +} diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/Score.java b/src/main/java/eu/mhsl/minenet/minigames/score/Score.java index 92d7385..38b54ae 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/Score.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/Score.java @@ -45,7 +45,13 @@ public abstract class Score { setDone(); } } + + public abstract void insertResultImplementation(Set p, int points); + protected abstract void insertResultImplementation(Set p); + + public abstract void insertResult(Player p, int points); + protected abstract TranslatableMessage scoreMessage(); public void insertResult(Player p) { diff --git a/src/main/java/eu/mhsl/minenet/minigames/util/MapUtil.java b/src/main/java/eu/mhsl/minenet/minigames/util/MapUtil.java new file mode 100644 index 0000000..ac5506b --- /dev/null +++ b/src/main/java/eu/mhsl/minenet/minigames/util/MapUtil.java @@ -0,0 +1,20 @@ +package eu.mhsl.minenet.minigames.util; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class MapUtil { + public static > Map sortByValue(Map map) { + List> list = new ArrayList<>(map.entrySet()); + list.sort(Map.Entry.comparingByValue()); + + Map result = new LinkedHashMap<>(); + for (Map.Entry entry : list) { + result.put(entry.getKey(), entry.getValue()); + } + + return result; + } +} \ No newline at end of file From e192ae4433fdec8eb78ae0bd3fd53a9c54515834 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 22 Oct 2024 16:45:32 +0200 Subject: [PATCH 11/30] moved tetris from prototype to other --- .../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 9dbb7f0..fc0b8ac 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 @@ -25,7 +25,7 @@ public enum GameList { BEDWARS(new BedwarsFactory(), GameType.PROTOTYPE), BACKROOMS(new BackroomsFactory(), GameType.PROTOTYPE), ANVILRUN(new AnvilRunFactory(), GameType.PROTOTYPE), - TETRIS(new TetrisFactory(), GameType.PROTOTYPE), + TETRIS(new TetrisFactory(), GameType.OTHER), TNTRUN(new TntRunFactory(), GameType.OTHER), ACIDRAIN(new AcidRainFactory(), GameType.PVE), ELYTRARACE(new ElytraRaceFactory(), GameType.PVP), From 8594f8029c7499c202d12298b8bc0ba9dc94239b Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 22 Oct 2024 17:05:24 +0200 Subject: [PATCH 12/30] fixed score at end of tetris not working --- .../game/stateless/types/tetris/game/TetrisGame.java | 12 ++++++++---- .../mhsl/minenet/minigames/score/PointsWinScore.java | 3 +-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index c32c4d4..928469f 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -57,11 +57,11 @@ public class TetrisGame { } public void pressedButton(Button button) { - if(lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-100) return; + if(this.lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-100) return; - lastPresses.put(button, System.currentTimeMillis()); - if(button == Button.W) lastPresses.put(button, System.currentTimeMillis()+70); - if(button == Button.S) lastPresses.put(button, System.currentTimeMillis()-70); + this.lastPresses.put(button, System.currentTimeMillis()); + if(button == Button.W) this.lastPresses.put(button, System.currentTimeMillis()+70); + if(button == Button.S) this.lastPresses.put(button, System.currentTimeMillis()-70); switch (button) { case A -> this.moveLeft(); @@ -74,6 +74,10 @@ public class TetrisGame { } } + public void releaseButton(Button button) { + this.lastPresses.put(button, 0L); + } + public Pos getPlayerSpawnPosition() { return this.playfield.getPlayerSpawnPosition(); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java index 5164e65..95ba294 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java @@ -4,7 +4,6 @@ import eu.mhsl.minenet.minigames.message.TranslatableMessage; import eu.mhsl.minenet.minigames.message.type.TitleMessage; import eu.mhsl.minenet.minigames.util.MapUtil; import net.minestom.server.entity.Player; -import org.apache.commons.lang3.NotImplementedException; import java.time.Duration; import java.util.*; @@ -22,7 +21,7 @@ public class PointsWinScore extends Score { @Override protected void insertResultImplementation(Set p) { - throw new NotImplementedException("PointsWinScore does not support adding entries without points"); + this.insertResultImplementation(p, 0); } @Override From c9d00f4f77af4aea1c343474379bd3f63eb290f4 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 22 Oct 2024 17:16:26 +0200 Subject: [PATCH 13/30] added tetris to translation file --- .../mhsl/minenet/minigames/command/PrivilegedCommand.java | 1 + src/main/resources/lang/locales.map.csv | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java b/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java index 22a1700..7a2cc37 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java +++ b/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java @@ -27,6 +27,7 @@ public class PrivilegedCommand extends Command { } protected CommandCondition isPrivileged() { + //TODO // return (sender, commandString) -> sender.hasPermission("admin"); return (sender, commandString) -> true; } diff --git a/src/main/resources/lang/locales.map.csv b/src/main/resources/lang/locales.map.csv index 9dc3d69..9d6195f 100644 --- a/src/main/resources/lang/locales.map.csv +++ b/src/main/resources/lang/locales.map.csv @@ -89,4 +89,8 @@ description;Protect the path ????;?????? ns:game_Spleef#;; name;Spleef;Spleef; description;Spleef other players and be the last survivor;Zerstöre Blöcke unter anderen Spielern und sei der letzte im Feld -shovelName;Snow thrower;Schneeflug \ No newline at end of file +shovelName;Snow thrower;Schneeflug +;; +ns:game_Tetris#;; +name;Tetris;Tetris +description;Sort falling blocks and clear lines;Sortiere fallende Blöcke und kläre Linien \ No newline at end of file From 075db7a91b70f8b2fa75f56c8ca4e06f9d9363b9 Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 22 Oct 2024 21:21:00 +0200 Subject: [PATCH 14/30] added border around next and hold tetromino --- .../game/stateless/types/tetris/Tetris.java | 7 +++---- .../stateless/types/tetris/game/Playfield.java | 17 +++++++++++++++-- .../stateless/types/tetris/game/TetrisGame.java | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index adfab17..827b4c9 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -5,7 +5,6 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.Tetri import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.Tetromino; import eu.mhsl.minenet.minigames.score.PointsWinScore; -import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Vec; @@ -25,7 +24,7 @@ class Tetris extends StatelessGame { public Tetris() { super(Dimension.THE_END.key, "Tetris", new PointsWinScore()); - this.setGenerator(new CircularPlateTerrainGenerator(30).setPlateHeight(0)); +// this.setGenerator(new CircularPlateTerrainGenerator(20)); eventNode() .addListener(PlayerUseItemEvent.class, this::onPlayerInteract) @@ -119,7 +118,7 @@ class Tetris extends StatelessGame { p.setSprinting(false); if(this.tetrisGames.get(p) == null) { - this.tetrisGames.put(p, new TetrisGame(this, getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*23, 0, 0))); + this.tetrisGames.put(p, new TetrisGame(this, getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*27, 0, 0))); this.tetrisGames.get(p).generate(); } TetrisGame tetrisGame = this.tetrisGames.get(p); @@ -132,6 +131,6 @@ class Tetris extends StatelessGame { @Override public Pos getSpawn() { - return new Pos(-50, 50, 15).withView(180, 0); + return new Pos(0, 30, 15).withView(180, 0); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index 819f013..8eac64c 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -28,11 +28,11 @@ public class Playfield { } public Pos getHoldPosition() { - return this.lowerLeftCorner.add(-4, 19, 0); + return this.lowerLeftCorner.add(-4, 18, 1); } public Pos getNextPosition() { - return this.lowerLeftCorner.add(14, 19, 0); + return this.lowerLeftCorner.add(14, 18, 1); } public void generate() { @@ -50,6 +50,19 @@ public class Playfield { } } + for(int x = 0; x < 6; x++) { + for(int y = 0; y < 6; y++) { + if(x==0 || x==5 || y==0 || y==5) { + batch.setBlock(this.getHoldPosition().add(x-2, y-2, 0), Block.BLACK_CONCRETE); + batch.setBlock(this.getNextPosition().add(x-2, y-2, 0), Block.BLACK_CONCRETE); + batch.setBlock(this.getHoldPosition().add(x-2, y-2, -1), Block.BLACK_CONCRETE); + batch.setBlock(this.getNextPosition().add(x-2, y-2, -1), Block.BLACK_CONCRETE); + } + batch.setBlock(this.getHoldPosition().add(x-2, y-2, -1), Block.QUARTZ_BLOCK); + batch.setBlock(this.getNextPosition().add(x-2, y-2, -1), Block.QUARTZ_BLOCK); + } + } + batch.setBlock(getPlayerSpawnPosition().sub(0, 1, 0), Block.STONE); // batch.setBlock(getPlayerSpawnPosition(), Block.IRON_TRAPDOOR.withProperty("half", "bottom")); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 928469f..6b8f921 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -97,7 +97,7 @@ public class TetrisGame { this.playfield.generate(); this.currentTetromino.setPosition(this.tetrominoSpawnPosition); - this.currentTetromino.draw(); + this.currentTetromino.draw(false); } public void tick() { From 179fa2e4d76b622236f7d2630d245955824f5dc6 Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 23 Oct 2024 01:08:52 +0200 Subject: [PATCH 15/30] added combat system and options for game list --- .../game/stateless/config/Option.java | 6 +- .../stateless/config/common/BoolOption.java | 4 +- .../game/stateless/types/tetris/Tetris.java | 24 ++++- .../stateless/types/tetris/TetrisFactory.java | 9 +- .../types/tetris/game/Playfield.java | 73 ++++++++++++--- .../types/tetris/game/TetrisGame.java | 89 ++++++++++++++----- .../types/tetris/game/Tetromino.java | 4 +- 7 files changed, 169 insertions(+), 40 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/Option.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/Option.java index 26d9959..02cfea2 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/Option.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/Option.java @@ -25,7 +25,7 @@ public abstract class Option { this.name = name; this.options = options; - currentValue = options.get(0); + currentValue = options.getFirst(); } public void setRestrictionHandler(RestrictionHandler restrictionHandler) { @@ -56,6 +56,10 @@ public abstract class Option { return Integer.parseInt(getAsString()); } + public boolean getAsBoolean() { + return getAsInt() != 0; + } + public String getAsString() { return currentValue.toString(); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/common/BoolOption.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/common/BoolOption.java index d77ba96..22017e0 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/common/BoolOption.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/common/BoolOption.java @@ -6,8 +6,8 @@ import net.minestom.server.item.Material; import java.util.List; -public class BoolOption extends Option { +public class BoolOption extends Option { public BoolOption(String id, Material item, TranslatedComponent name) { - super(id, item, name, List.of(true, false)); + super(id, item, name, List.of(1, 0)); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 827b4c9..da6f2ec 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -21,8 +21,11 @@ import java.util.Map; class Tetris extends StatelessGame { private final Map tetrisGames = new HashMap<>(); + private final int nextTetrominoesCount; + private final boolean isFast; + private final boolean hasCombat; - public Tetris() { + public Tetris(int nextTetrominoesCount, boolean isFast, boolean hasCombat) { super(Dimension.THE_END.key, "Tetris", new PointsWinScore()); // this.setGenerator(new CircularPlateTerrainGenerator(20)); @@ -30,6 +33,10 @@ class Tetris extends StatelessGame { .addListener(PlayerUseItemEvent.class, this::onPlayerInteract) .addListener(PlayerHandAnimationEvent.class, this::onPlayerAttack) .addListener(PlayerTickEvent.class, this::onPlayerTick); + + this.nextTetrominoesCount = nextTetrominoesCount; + this.isFast = isFast; + this.hasCombat = hasCombat; } @Override @@ -37,6 +44,11 @@ class Tetris extends StatelessGame { this.getEntities().stream() .filter(entity -> entity.getEntityType().equals(Tetromino.getGhostEntityType())) .forEach(Entity::remove); + + if(this.hasCombat) { + this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values().stream().toList())); + } + this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.start()); } @@ -118,8 +130,16 @@ class Tetris extends StatelessGame { p.setSprinting(false); if(this.tetrisGames.get(p) == null) { - this.tetrisGames.put(p, new TetrisGame(this, getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*27, 0, 0))); + this.tetrisGames.put(p, new TetrisGame( + this, + getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*24, 0, 0), + Tetromino.Shape.J, + this.nextTetrominoesCount, + this.isFast, + this.hasCombat + )); this.tetrisGames.get(p).generate(); + this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values().stream().toList())); } TetrisGame tetrisGame = this.tetrisGames.get(p); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java index 3b5b628..56630f7 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/TetrisFactory.java @@ -4,6 +4,8 @@ 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.game.stateless.config.ConfigManager; +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; @@ -23,12 +25,15 @@ public class TetrisFactory implements GameFactory { @Override public ConfigManager configuration() { - return new ConfigManager(); + return new ConfigManager() + .addOption(new NumericOption("nextTetrominoesCount", Material.LADDER, TranslatedComponent.byId("game_Tetris#nextTetrominoesCount"), 3, 4, 5, 1, 2)) + .addOption(new BoolOption("isFast", Material.MINECART, TranslatedComponent.byId("game_Tetris#isFast"))) + .addOption(new BoolOption("hasCombat", Material.DIAMOND_SWORD, TranslatedComponent.byId("game_Tetris#hasCombat"))); } @Override public Game manufacture(Room parent, Map> configuration) { - return new Tetris().setParent(parent); + return new Tetris(configuration.get("nextTetrominoesCount").getAsInt(), configuration.get("isFast").getAsBoolean(), configuration.get("hasCombat").getAsBoolean()).setParent(parent); } @Override diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index 8eac64c..bc11e86 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -8,14 +8,20 @@ import net.minestom.server.entity.EntityType; import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.block.Block; +import java.util.Random; + public class Playfield { private final Pos lowerLeftCorner; private final StatelessGame instance; private final static int height = 22; + private final int nextTetrominoesCount; + private final Random random; - public Playfield(Pos lowerLeftCorner, StatelessGame instance) { + public Playfield(Pos lowerLeftCorner, StatelessGame instance, int nextTetrominoesCount) { + this.nextTetrominoesCount = nextTetrominoesCount; this.lowerLeftCorner = lowerLeftCorner; this.instance = instance; + this.random = new Random(); } public Pos getPlayerSpawnPosition() { @@ -38,6 +44,7 @@ public class Playfield { public void generate() { AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); + // actual playfield: for(int x=0; x<12; x++) { for(int y = 0; y< height; y++) { batch.setBlock(this.lowerLeftCorner.add(x, y, 0), Block.GLASS); @@ -50,16 +57,25 @@ public class Playfield { } } - for(int x = 0; x < 6; x++) { - for(int y = 0; y < 6; y++) { - if(x==0 || x==5 || y==0 || y==5) { - batch.setBlock(this.getHoldPosition().add(x-2, y-2, 0), Block.BLACK_CONCRETE); - batch.setBlock(this.getNextPosition().add(x-2, y-2, 0), Block.BLACK_CONCRETE); - batch.setBlock(this.getHoldPosition().add(x-2, y-2, -1), Block.BLACK_CONCRETE); - batch.setBlock(this.getNextPosition().add(x-2, y-2, -1), Block.BLACK_CONCRETE); - } - batch.setBlock(this.getHoldPosition().add(x-2, y-2, -1), Block.QUARTZ_BLOCK); - batch.setBlock(this.getNextPosition().add(x-2, y-2, -1), Block.QUARTZ_BLOCK); + // hold position: + for(int x = 0; x < 4; x++) { + for(int y = 0; y < 4; y++) { +// if(x==0 || x==5 || y==0 || y==5) { +// batch.setBlock(this.getHoldPosition().add(x-2, y-2, 0), Block.BLACK_CONCRETE); +// batch.setBlock(this.getHoldPosition().add(x-2, y-2, -1), Block.BLACK_CONCRETE); +// } + batch.setBlock(this.getHoldPosition().add(x-1, y-1, -1), Block.QUARTZ_BLOCK); + } + } + + // next positions: + for(int x = 0; x < 4; x++) { + for(int y = -4*this.nextTetrominoesCount+4; y < 4; y++) { +// if(x==0 || x==5 || y==-4*this.nextTetrominoesCount+4 || y==5) { +// batch.setBlock(this.getNextPosition().add(x-2, y-2, 0), Block.BLACK_CONCRETE); +// batch.setBlock(this.getNextPosition().add(x-2, y-2, -1), Block.BLACK_CONCRETE); +// } + batch.setBlock(this.getNextPosition().add(x-1, y-1, -1), Block.QUARTZ_BLOCK); } } @@ -100,6 +116,41 @@ public class Playfield { .forEach(Entity::remove); } + public void addLines(int lines) { + int xPosMissing = random.nextInt(1, 10); + + for (int i = 0; i < lines; i++) { + moveAllLinesUp(); + for (int x = 1; x < 11; x++) { + if(x != xPosMissing) { + this.instance.setBlock(this.lowerLeftCorner.add(x, 1, 1), Block.LIGHT_GRAY_CONCRETE); + } else { + this.instance.setBlock(this.lowerLeftCorner.add(x, 1, 1), Block.AIR); + } + } + } + } + + public void updateAttackingLines(int attackingLines) { + for (int y = 0; y < height + 5; y++) { + if(attackingLines > 0) { + this.instance.setBlock(this.lowerLeftCorner.add(12, y, 1), Block.REDSTONE_BLOCK); + attackingLines -= 1; + } else { + this.instance.setBlock(this.lowerLeftCorner.add(12, y, 1), Block.AIR); + } + } + } + + + private void moveAllLinesUp() { + for (int y = height + 3; y > 1; y--) { + for (int x = 1; x < 11; x++) { + Block blockBeneath = this.instance.getBlock(this.lowerLeftCorner.add(x, y - 1, 1)); + this.instance.setBlock(this.lowerLeftCorner.add(x, y, 1), blockBeneath); + } + } + } private void removeFullLine(int positionY) { for(int y = positionY; y< height; y++) { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 6b8f921..6a86879 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -13,13 +13,16 @@ import java.util.*; public class TetrisGame { private final StatelessGame instance; private final Playfield playfield; + private final boolean isFast; private int level = 1; private int lines = 0; private int score = 0; + private int attackingLines = 0; public boolean lost = false; public boolean paused = true; + private final boolean hasCombat; public Tetromino currentTetromino; - private Tetromino nextTetromino; + private final List nextTetrominoes = new ArrayList<>(); private Tetromino holdTetromino; private final List tetrominoBag = new ArrayList<>(); private boolean holdPossible = true; @@ -28,6 +31,7 @@ public class TetrisGame { private final Pos tetrominoSpawnPosition; public Sidebar sidebar = new Sidebar(Component.text("Info:")); private final Map lastPresses = new HashMap<>(); + private final List otherTetrisGames = new ArrayList<>(); public enum Button { W, @@ -40,12 +44,14 @@ public class TetrisGame { } public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) { - this(instance, lowerLeftCorner, Tetromino.Shape.J); + this(instance, lowerLeftCorner, Tetromino.Shape.J, 3, false, false); } - public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino.Shape startTetrominoShape) { + public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino.Shape startTetrominoShape, int nextTetrominoesCount, boolean isfast, boolean hasCombat) { + this.isFast = isfast; + this.hasCombat = hasCombat; this.instance = instance; - this.playfield = new Playfield(lowerLeftCorner, this.instance); + this.playfield = new Playfield(lowerLeftCorner, this.instance, nextTetrominoesCount); this.holdPosition = this.playfield.getHoldPosition(); this.nextPosition = this.playfield.getNextPosition(); @@ -53,7 +59,9 @@ public class TetrisGame { this.buildSidebar(); this.currentTetromino = new Tetromino(this.instance, startTetrominoShape, this.playfield); - this.nextTetromino = this.getNextTetromino(); + for (int i = 0; i < nextTetrominoesCount; i++) { + this.getNextTetromino(); + } } public void pressedButton(Button button) { @@ -74,10 +82,6 @@ public class TetrisGame { } } - public void releaseButton(Button button) { - this.lastPresses.put(button, 0L); - } - public Pos getPlayerSpawnPosition() { return this.playfield.getPlayerSpawnPosition(); } @@ -87,9 +91,11 @@ public class TetrisGame { Scheduler scheduler = MinecraftServer.getSchedulerManager(); scheduler.submitTask(() -> { if(this.lost) return TaskSchedule.stop(); - if(this.paused) return TaskSchedule.tick(40/this.level); + int standardTickDelay = 40; + if(this.isFast) standardTickDelay = 20; + if(this.paused) return TaskSchedule.tick(Math.round((float) standardTickDelay /this.level)); this.tick(); - return TaskSchedule.tick(40/this.level); + return TaskSchedule.tick(Math.round((float) standardTickDelay /this.level)); }); } @@ -111,6 +117,20 @@ public class TetrisGame { return this.score; } + public void updateOtherTetrisGames(List tetrisGames) { + List games = new ArrayList<>(tetrisGames); + games.remove(this); + this.otherTetrisGames.clear(); + this.otherTetrisGames.addAll(games); + } + + public void getAttacked(int lines) { + if(this.hasCombat) { + this.attackingLines += lines; + this.playfield.updateAttackingLines(this.attackingLines); + } + } + private boolean rotate(boolean clockwise) { if(this.lost || this.paused) return false; @@ -160,8 +180,9 @@ public class TetrisGame { Tetromino newCurrentTetromino; if(this.holdTetromino == null) { - newCurrentTetromino = this.nextTetromino; - this.nextTetromino = this.getNextTetromino(); + newCurrentTetromino = this.nextTetrominoes.removeFirst(); + newCurrentTetromino.remove(); + this.getNextTetromino(); } else { newCurrentTetromino = this.holdTetromino; this.holdTetromino.remove(); @@ -190,12 +211,15 @@ public class TetrisGame { Collections.shuffle(this.tetrominoBag); } - if(this.nextTetromino != null) this.nextTetromino.remove(); - Tetromino tetromino = this.tetrominoBag.removeFirst(); - tetromino.setPosition(this.nextPosition); - tetromino.draw(false); + if(!this.nextTetrominoes.isEmpty()) this.nextTetrominoes.forEach(Tetromino::remove); + Tetromino newTetromino = this.tetrominoBag.removeFirst(); + this.nextTetrominoes.add(newTetromino); + this.nextTetrominoes.forEach(tetromino -> { + tetromino.setPosition(this.nextPosition.sub(0, 4*this.nextTetrominoes.indexOf(tetromino), 0)); + tetromino.draw(false); + }); - return tetromino; + return newTetromino; } private void loose() { @@ -227,29 +251,54 @@ public class TetrisGame { } private void setActiveTetrominoDown() { - this.currentTetromino = this.nextTetromino; - this.nextTetromino = getNextTetromino(); + this.currentTetromino = this.nextTetrominoes.removeFirst(); + this.currentTetromino.remove(); + this.getNextTetromino(); int removedLines = this.playfield.removeFullLines(); + int combatLines = 0; switch (removedLines) { case 1 -> { this.lines += 1; this.score += 40 * this.level; } case 2 -> { + combatLines = 1; this.lines += 2; this.score += 100 * this.level; } case 3 -> { + combatLines = 2; this.lines += 3; this.score += 300 * this.level; } case 4 -> { + combatLines = 4; this.lines += 4; this.score += 1200 * this.level; } } + if(this.hasCombat && this.attackingLines > 0) { + if(combatLines > 0 && this.attackingLines >= combatLines) { + this.attackingLines -= combatLines; + combatLines = 0; + } else if(combatLines > 0) { + combatLines -= this.attackingLines; + this.attackingLines = 0; + } else { + this.playfield.addLines(this.attackingLines); + this.attackingLines = 0; + } + + this.playfield.updateAttackingLines(this.attackingLines); + } + + if(this.hasCombat && !this.otherTetrisGames.isEmpty()) { + Collections.shuffle(this.otherTetrisGames); + this.otherTetrisGames.getFirst().getAttacked(combatLines); + } + this.level = (int) Math.floor((double) this.lines / 10) + 1; this.holdPossible = true; diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index 06f41d3..e41a57a 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -102,8 +102,7 @@ public class Tetromino { this.getBlockPositions().forEach(pos -> this.instance.setBlock(pos, Block.AIR)); } - - private Block getColoredBlock() { + public Block getColoredBlock() { Block returnBlock; switch (this.shape) { case I -> returnBlock = Block.LIGHT_BLUE_CONCRETE; @@ -118,6 +117,7 @@ public class Tetromino { return returnBlock; } + private Block getGhostBlock() { Block returnBlock; switch (this.shape) { From 3c25f5f079babbec5c95401c18570d4d7b447f0e Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 23 Oct 2024 13:55:39 +0200 Subject: [PATCH 16/30] changed player spawn position --- .../stateless/types/tetris/game/Playfield.java | 7 +++++-- .../stateless/types/tetris/game/Tetromino.java | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index bc11e86..fd8fec0 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -25,8 +25,8 @@ public class Playfield { } public Pos getPlayerSpawnPosition() { -// return this.lowerLeftCorner.add(6.5, 9+((double) 3/16), 20.5).withView(180, 0); - return this.lowerLeftCorner.add(6.5, 9, 20.5).withView(180, 0); +// return this.lowerLeftCorner.add(6, 9+((double) 3/16), 20).withView(180, 0); + return this.lowerLeftCorner.add(6, 9, 20).withView(180, 0); } public Pos getTetrominoSpawnPosition() { @@ -80,6 +80,9 @@ public class Playfield { } batch.setBlock(getPlayerSpawnPosition().sub(0, 1, 0), Block.STONE); + batch.setBlock(getPlayerSpawnPosition().sub(1, 1, 0), Block.STONE); + batch.setBlock(getPlayerSpawnPosition().sub(1, 1, 1), Block.STONE); + batch.setBlock(getPlayerSpawnPosition().sub(0, 1, 1), Block.STONE); // batch.setBlock(getPlayerSpawnPosition(), Block.IRON_TRAPDOOR.withProperty("half", "bottom")); // batch.setBlock(getPlayerSpawnPosition().add(0, 1, 0), Block.IRON_TRAPDOOR.withProperty("half", "top")); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index e41a57a..b921a09 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -10,6 +10,7 @@ import net.minestom.server.instance.block.Block; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.UUID; public class Tetromino { public final Shape shape; @@ -18,6 +19,7 @@ public class Tetromino { private Pos position; private int[][] shapeArray; private final static EntityType ghostEntityType = EntityType.FALLING_BLOCK; + private final UUID uuid; public enum Shape { I, @@ -33,6 +35,7 @@ public class Tetromino { this.instance = instance; this.shape = shape; this.playfield = playfield; + this.uuid = UUID.randomUUID(); switch (this.shape) { case I -> shapeArray = new int[][]{{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}}; @@ -88,16 +91,29 @@ public class Tetromino { getBlockPositions().forEach(pos -> { Entity ghostBlock = new Entity(ghostEntityType); ((FallingBlockMeta) ghostBlock.getEntityMeta()).setBlock(this.getGhostBlock()); +// ((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(this.getGhostBlock()); ghostBlock.setNoGravity(true); ghostBlock.setGlowing(true); - ghostBlock.setInvisible(true); ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(0.5, 0, 0.5)); +// ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(1, 0, 1)); }); } getBlockPositions().forEach(pos -> this.instance.setBlock(pos, this.getColoredBlock())); } + public void drawAsEntities() { + getBlockPositions().forEach(pos -> { + Entity ghostBlock = new Entity(ghostEntityType); + ((FallingBlockMeta) ghostBlock.getEntityMeta()).setBlock(this.getGhostBlock()); +// ((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(this.getGhostBlock()); + ghostBlock.setNoGravity(true); + ghostBlock.setGlowing(true); + ghostBlock.setInstance(this.instance, pos.add(0.5, 0, 0.5)); +// ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(1, 0, 1)); + }); + } + public void remove() { this.getBlockPositions().forEach(pos -> this.instance.setBlock(pos, Block.AIR)); } From f838317af0d81fbf8361e10724400118b1f7b2cb Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 23 Oct 2024 14:53:07 +0200 Subject: [PATCH 17/30] centered hold and next tetrominoes --- .../types/tetris/game/Playfield.java | 15 ------- .../types/tetris/game/TetrisGame.java | 45 +++++++++++++------ .../types/tetris/game/Tetromino.java | 31 ++++++++----- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index fd8fec0..3df931e 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -3,8 +3,6 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.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.entity.Entity; -import net.minestom.server.entity.EntityType; import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.block.Block; @@ -106,19 +104,6 @@ public class Playfield { return removedLinesCounter; } - public void removeEntity(EntityType entityType) { - this.instance.getEntities().stream() - .filter(entity -> entity.getEntityType().equals(entityType)) - .filter(entity -> { - Pos position = entity.getPosition(); - if(position.x() > this.lowerLeftCorner.x() && position.y() > this.lowerLeftCorner.y()) { - return position.x() < this.lowerLeftCorner.x() + 11 && position.y() < this.lowerLeftCorner.y() + height; - } - return false; - }) - .forEach(Entity::remove); - } - public void addLines(int lines) { int xPosMissing = random.nextInt(1, 10); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 6a86879..7e3366f 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -58,9 +58,9 @@ public class TetrisGame { this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition(); this.buildSidebar(); - this.currentTetromino = new Tetromino(this.instance, startTetrominoShape, this.playfield); + this.currentTetromino = new Tetromino(this.instance, startTetrominoShape); for (int i = 0; i < nextTetrominoesCount; i++) { - this.getNextTetromino(); + this.updateNextTetrominoes(); } } @@ -97,6 +97,16 @@ public class TetrisGame { this.tick(); return TaskSchedule.tick(Math.round((float) standardTickDelay /this.level)); }); + + this.nextTetrominoes.forEach(tetromino -> { + double xChange; + switch (tetromino.shape) { + case O, I -> xChange = 0; + case null, default -> xChange = -0.5; + } + tetromino.setPosition(this.nextPosition.sub(xChange, 4*this.nextTetrominoes.indexOf(tetromino), 0)); + tetromino.drawAsEntities(); + }); } public void generate() { @@ -182,31 +192,36 @@ public class TetrisGame { if(this.holdTetromino == null) { newCurrentTetromino = this.nextTetrominoes.removeFirst(); newCurrentTetromino.remove(); - this.getNextTetromino(); + this.updateNextTetrominoes(); } else { newCurrentTetromino = this.holdTetromino; this.holdTetromino.remove(); } this.currentTetromino.remove(); - this.holdTetromino = new Tetromino(this.instance, this.currentTetromino.shape, this.playfield); + this.holdTetromino = new Tetromino(this.instance, this.currentTetromino.shape); this.currentTetromino = newCurrentTetromino; this.currentTetromino.setPosition(this.tetrominoSpawnPosition); this.currentTetromino.draw(); if(!this.currentTetromino.moveDown()) loose(); - this.holdTetromino.setPosition(this.holdPosition); - this.holdTetromino.draw(false); + double xChange; + switch (this.holdTetromino.shape) { + case O, I -> xChange = 0; + case null, default -> xChange = 0.5; + } + this.holdTetromino.setPosition(this.holdPosition.add(xChange, 0, 0)); + this.holdTetromino.drawAsEntities(); this.holdPossible = false; return true; } - private Tetromino getNextTetromino() { + private void updateNextTetrominoes() { if(this.tetrominoBag.isEmpty()) { for(Tetromino.Shape shape : Tetromino.Shape.values()) { - this.tetrominoBag.add(new Tetromino(this.instance, shape, this.playfield)); + this.tetrominoBag.add(new Tetromino(this.instance, shape)); } Collections.shuffle(this.tetrominoBag); } @@ -215,11 +230,14 @@ public class TetrisGame { Tetromino newTetromino = this.tetrominoBag.removeFirst(); this.nextTetrominoes.add(newTetromino); this.nextTetrominoes.forEach(tetromino -> { - tetromino.setPosition(this.nextPosition.sub(0, 4*this.nextTetrominoes.indexOf(tetromino), 0)); - tetromino.draw(false); + double xChange; + switch (tetromino.shape) { + case O, I -> xChange = 0; + case null, default -> xChange = -0.5; + } + tetromino.setPosition(this.nextPosition.sub(xChange, 4*this.nextTetrominoes.indexOf(tetromino), 0)); + tetromino.drawAsEntities(); }); - - return newTetromino; } private void loose() { @@ -251,9 +269,10 @@ public class TetrisGame { } private void setActiveTetrominoDown() { + this.currentTetromino.removeOwnEntities(); this.currentTetromino = this.nextTetrominoes.removeFirst(); this.currentTetromino.remove(); - this.getNextTetromino(); + this.updateNextTetrominoes(); int removedLines = this.playfield.removeFullLines(); int combatLines = 0; diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index b921a09..5a08ff8 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -6,6 +6,7 @@ import net.minestom.server.entity.Entity; import net.minestom.server.entity.EntityType; import net.minestom.server.entity.metadata.other.FallingBlockMeta; import net.minestom.server.instance.block.Block; +import net.minestom.server.tag.Tag; import java.util.ArrayList; import java.util.Arrays; @@ -15,11 +16,11 @@ import java.util.UUID; public class Tetromino { public final Shape shape; private final StatelessGame instance; - private final Playfield playfield; private Pos position; private int[][] shapeArray; private final static EntityType ghostEntityType = EntityType.FALLING_BLOCK; private final UUID uuid; + private final static Tag uuidTag = Tag.String("uuid"); public enum Shape { I, @@ -31,10 +32,9 @@ public class Tetromino { Z } - public Tetromino(StatelessGame instance, Shape shape, Playfield playfield) { + public Tetromino(StatelessGame instance, Shape shape) { this.instance = instance; this.shape = shape; - this.playfield = playfield; this.uuid = UUID.randomUUID(); switch (this.shape) { @@ -82,7 +82,6 @@ public class Tetromino { public void draw(boolean withGhost) { if(withGhost) { - this.playfield.removeEntity(ghostEntityType); Pos ghostPos = this.position; while (!checkCollision(ghostPos.sub(0, 1, 0), this.shapeArray)) { ghostPos = ghostPos.sub(0, 1, 0); @@ -94,6 +93,7 @@ public class Tetromino { // ((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(this.getGhostBlock()); ghostBlock.setNoGravity(true); ghostBlock.setGlowing(true); + ghostBlock.setTag(uuidTag, this.uuid.toString()); ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(0.5, 0, 0.5)); // ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(1, 0, 1)); }); @@ -105,16 +105,17 @@ public class Tetromino { public void drawAsEntities() { getBlockPositions().forEach(pos -> { Entity ghostBlock = new Entity(ghostEntityType); - ((FallingBlockMeta) ghostBlock.getEntityMeta()).setBlock(this.getGhostBlock()); + ((FallingBlockMeta) ghostBlock.getEntityMeta()).setBlock(this.getColoredBlock()); // ((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(this.getGhostBlock()); ghostBlock.setNoGravity(true); - ghostBlock.setGlowing(true); + ghostBlock.setTag(uuidTag, this.uuid.toString()); ghostBlock.setInstance(this.instance, pos.add(0.5, 0, 0.5)); // ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(1, 0, 1)); }); } public void remove() { + this.removeOwnEntities(); this.getBlockPositions().forEach(pos -> this.instance.setBlock(pos, Block.AIR)); } @@ -133,6 +134,16 @@ public class Tetromino { return returnBlock; } + public void removeOwnEntities() { + this.instance.getEntities().stream() + .filter(entity -> { + String tagValue = entity.getTag(uuidTag); + if(tagValue != null) return entity.getTag(uuidTag).equals(this.uuid.toString()); + return false; + }) + .forEach(Entity::remove); + } + private Block getGhostBlock() { Block returnBlock; @@ -170,12 +181,8 @@ public class Tetromino { } private boolean isPartOfTetromino(Pos position) { - for(Pos blockPosition : getBlockPositions()) { - if(position.sameBlock(blockPosition)) { - return true; - } - } - return false; + return this.getBlockPositions().stream() + .anyMatch(pos -> pos.equals(position)); } private List getBlockPositions() { From 73a374e5296210e6aef437b6841ecc9a923b79c8 Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 23 Oct 2024 17:26:31 +0200 Subject: [PATCH 18/30] added timeout for tetris and display points at end of PointsWinScore --- .../game/stateless/StatelessGame.java | 6 ++-- .../game/stateless/types/tetris/Tetris.java | 18 ++++++++-- .../types/tetris/game/TetrisGame.java | 21 +++++++----- .../minigames/score/PointsWinScore.java | 34 +++++++++++++++++++ .../mhsl/minenet/minigames/score/Score.java | 2 ++ 5 files changed, 67 insertions(+), 14 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java index c9efbb0..d0bd25d 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java @@ -51,7 +51,9 @@ public class StatelessGame extends Game { int timeLeft = timeLimit - timePlayed; switch (timeLeft) { case 60, 30, 10, 5, 4, 3, 2, 1 -> - new ChatMessage(Icon.SCIENCE).appendStatic("Noch " + timeLeft + " Sekunden!").send(getPlayers()); + new ChatMessage(Icon.SCIENCE).appendStatic("Noch " + timeLeft + " Sekunden!").send(getPlayers()); + case 120 -> + new ChatMessage(Icon.SCIENCE).appendStatic("Noch 2 Minuten!").send(getPlayers()); } timePlayed++; @@ -100,7 +102,7 @@ public class StatelessGame extends Game { countdownUnload(); } - private void countdownUnload() { + protected void countdownUnload() { new TitleMessage(Duration.ofSeconds(1)).appendTranslated("score#done").send(getPlayers()); scheduler().scheduleTask(this::unload, TaskSchedule.seconds(5), TaskSchedule.stop()); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index da6f2ec..75bedec 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -18,16 +18,18 @@ import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; +import java.util.Random; class Tetris extends StatelessGame { private final Map tetrisGames = new HashMap<>(); private final int nextTetrominoesCount; private final boolean isFast; private final boolean hasCombat; + private boolean setTimeLimit = false; + private final long randomSeed; public Tetris(int nextTetrominoesCount, boolean isFast, boolean hasCombat) { super(Dimension.THE_END.key, "Tetris", new PointsWinScore()); -// this.setGenerator(new CircularPlateTerrainGenerator(20)); eventNode() .addListener(PlayerUseItemEvent.class, this::onPlayerInteract) @@ -37,6 +39,9 @@ class Tetris extends StatelessGame { this.nextTetrominoesCount = nextTetrominoesCount; this.isFast = isFast; this.hasCombat = hasCombat; + + Random random = new Random(); + this.randomSeed = random.nextLong(); } @Override @@ -54,6 +59,8 @@ class Tetris extends StatelessGame { @Override protected void onStop() { + this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.loose()); + this.tetrisGames.forEach((player, tetrisGame) -> getScore().insertResult(player, tetrisGame.getScore())); this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.sidebar.removeViewer(player)); } @@ -120,7 +127,11 @@ class Tetris extends StatelessGame { if(tetrisGame.lost && event.getPlayer().getGameMode() != GameMode.SPECTATOR) { event.getPlayer().setGameMode(GameMode.SPECTATOR); getScore().insertResult(event.getPlayer(), tetrisGame.getScore()); - tetrisGame.sidebar.removeViewer(event.getPlayer()); + + if(!setTimeLimit) { + this.setTimeLimit(120); + setTimeLimit = true; + } } } @@ -136,7 +147,8 @@ class Tetris extends StatelessGame { Tetromino.Shape.J, this.nextTetrominoesCount, this.isFast, - this.hasCombat + this.hasCombat, + this.randomSeed )); this.tetrisGames.get(p).generate(); this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values().stream().toList())); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 7e3366f..e829501 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -32,6 +32,7 @@ public class TetrisGame { public Sidebar sidebar = new Sidebar(Component.text("Info:")); private final Map lastPresses = new HashMap<>(); private final List otherTetrisGames = new ArrayList<>(); + private final Random random; public enum Button { W, @@ -43,15 +44,16 @@ public class TetrisGame { space } - public TetrisGame(StatelessGame instance, Pos lowerLeftCorner) { - this(instance, lowerLeftCorner, Tetromino.Shape.J, 3, false, false); + public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, long randomSeed) { + this(instance, lowerLeftCorner, Tetromino.Shape.J, 3, false, false, randomSeed); } - public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino.Shape startTetrominoShape, int nextTetrominoesCount, boolean isfast, boolean hasCombat) { + public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino.Shape startTetrominoShape, int nextTetrominoesCount, boolean isfast, boolean hasCombat, long randomSeed) { this.isFast = isfast; this.hasCombat = hasCombat; this.instance = instance; this.playfield = new Playfield(lowerLeftCorner, this.instance, nextTetrominoesCount); + this.random = new Random(randomSeed); this.holdPosition = this.playfield.getHoldPosition(); this.nextPosition = this.playfield.getNextPosition(); @@ -130,17 +132,22 @@ public class TetrisGame { public void updateOtherTetrisGames(List tetrisGames) { List games = new ArrayList<>(tetrisGames); games.remove(this); + games.removeIf(tetrisGame -> tetrisGame.lost); this.otherTetrisGames.clear(); this.otherTetrisGames.addAll(games); } public void getAttacked(int lines) { - if(this.hasCombat) { + if(this.hasCombat && !this.lost) { this.attackingLines += lines; this.playfield.updateAttackingLines(this.attackingLines); } } + public void loose() { + this.lost = true; + } + private boolean rotate(boolean clockwise) { if(this.lost || this.paused) return false; @@ -223,7 +230,7 @@ public class TetrisGame { for(Tetromino.Shape shape : Tetromino.Shape.values()) { this.tetrominoBag.add(new Tetromino(this.instance, shape)); } - Collections.shuffle(this.tetrominoBag); + Collections.shuffle(this.tetrominoBag, this.random); } if(!this.nextTetrominoes.isEmpty()) this.nextTetrominoes.forEach(Tetromino::remove); @@ -240,10 +247,6 @@ public class TetrisGame { }); } - private void loose() { - this.lost = true; - } - private void buildSidebar() { this.sidebar.createLine(new Sidebar.ScoreboardLine( "0", diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java index 95ba294..209cfe1 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java @@ -1,12 +1,15 @@ package eu.mhsl.minenet.minigames.score; +import eu.mhsl.minenet.minigames.message.Icon; import eu.mhsl.minenet.minigames.message.TranslatableMessage; +import eu.mhsl.minenet.minigames.message.type.ChatMessage; import eu.mhsl.minenet.minigames.message.type.TitleMessage; import eu.mhsl.minenet.minigames.util.MapUtil; import net.minestom.server.entity.Player; import java.time.Duration; import java.util.*; +import java.util.stream.Collectors; public class PointsWinScore extends Score { private Map, Integer> scoreOrder = new HashMap<>(); @@ -32,6 +35,37 @@ public class PointsWinScore extends Score { this.checkGameEnd(); } + @Override + public void setDone() { + if(isClosed()) return; + close(); + new ChatMessage(Icon.STAR, true) + .appendTranslated("score#result") + .newLine() + .indent() + .numberedList( + getScores() + .stream() + .filter(players -> !players.stream() + .filter(player -> !player.getUsername().isBlank()) + .toList() + .isEmpty()) + .map(players -> players + .stream() + .filter(player -> scoreOrder.get(Set.of(player)) != null) + .map(player -> player.getUsername()+" : "+scoreOrder.get(Set.of(player)).toString()) + .collect(Collectors.joining(", ")) + ) + .toList() + ) + .undent() + .newLine() + .appendTranslated("score#thanks") + .send(instance.getPlayers()); + + instance.stop(); + } + @Override protected TranslatableMessage scoreMessage() { return new TitleMessage(Duration.ofMillis(1000), Duration.ofSeconds(1)).appendTranslated("score#death"); diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/Score.java b/src/main/java/eu/mhsl/minenet/minigames/score/Score.java index 38b54ae..383a9e5 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/Score.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/Score.java @@ -103,6 +103,8 @@ public abstract class Score { return isClosed; } + public void close() { isClosed = true; } + protected void onGameEnd() { this.instance.stop(); } From 6638a48677b74322c730afa19e91bfb8c7b673bc Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 23 Oct 2024 17:41:05 +0200 Subject: [PATCH 19/30] added combos --- .../game/stateless/types/tetris/game/TetrisGame.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index e829501..29ea167 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -17,6 +17,7 @@ public class TetrisGame { private int level = 1; private int lines = 0; private int score = 0; + private int combo = 0; private int attackingLines = 0; public boolean lost = false; public boolean paused = true; @@ -279,7 +280,9 @@ public class TetrisGame { int removedLines = this.playfield.removeFullLines(); int combatLines = 0; + this.combo += 1; switch (removedLines) { + case 0 -> this.combo = 0; case 1 -> { this.lines += 1; this.score += 40 * this.level; @@ -301,6 +304,11 @@ public class TetrisGame { } } + this.score += 50 * this.combo * this.level; + if(this.combo >= 2) { + combatLines += (int) Math.floor((double) this.combo /2); + } + if(this.hasCombat && this.attackingLines > 0) { if(combatLines > 0 && this.attackingLines >= combatLines) { this.attackingLines -= combatLines; From bef697e5fcaef315140ef86e9ea5c5a4ecbe307a Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 23 Oct 2024 21:15:47 +0200 Subject: [PATCH 20/30] added Tetris options to translation files --- src/main/resources/lang/locales.map.csv | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/resources/lang/locales.map.csv b/src/main/resources/lang/locales.map.csv index 9d6195f..0546fb1 100644 --- a/src/main/resources/lang/locales.map.csv +++ b/src/main/resources/lang/locales.map.csv @@ -93,4 +93,7 @@ shovelName;Snow thrower;Schneeflug ;; ns:game_Tetris#;; name;Tetris;Tetris -description;Sort falling blocks and clear lines;Sortiere fallende Blöcke und kläre Linien \ No newline at end of file +description;Sort falling blocks and clear lines;Sortiere fallende Blöcke und kläre Linien +nextTetrominoesCount;Number of upcoming Tetrominos displayed;Anzahl der angezeigten kommenden Tetrominos +isFast;Fast mode;Schneller Modus +hasCombat;Competitive mode;Kompetitiver Modus \ No newline at end of file From e397d69d7ae0cda9e3829ee814240d1c76caaebe Mon Sep 17 00:00:00 2001 From: lars Date: Wed, 23 Oct 2024 22:43:14 +0200 Subject: [PATCH 21/30] added score above playfield --- .../game/stateless/types/tetris/Tetris.java | 2 +- .../types/tetris/game/Playfield.java | 56 ++++++++++++++++++- .../types/tetris/game/TetrisGame.java | 12 ++-- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 75bedec..b52376d 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -143,7 +143,7 @@ class Tetris extends StatelessGame { if(this.tetrisGames.get(p) == null) { this.tetrisGames.put(p, new TetrisGame( this, - getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*24, 0, 0), + getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*30, 0, 0), Tetromino.Shape.J, this.nextTetrominoesCount, this.isFast, diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index 3df931e..b5dd3a1 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -5,6 +5,7 @@ import eu.mhsl.minenet.minigames.util.BatchUtil; import net.minestom.server.coordinate.Pos; import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.block.Block; +import org.apache.commons.lang3.ArrayUtils; import java.util.Random; @@ -12,6 +13,7 @@ public class Playfield { private final Pos lowerLeftCorner; private final StatelessGame instance; private final static int height = 22; + private final static Block scoreBlock = Block.STONE; private final int nextTetrominoesCount; private final Random random; @@ -24,7 +26,7 @@ public class Playfield { public Pos getPlayerSpawnPosition() { // return this.lowerLeftCorner.add(6, 9+((double) 3/16), 20).withView(180, 0); - return this.lowerLeftCorner.add(6, 9, 20).withView(180, 0); + return this.lowerLeftCorner.add(6, 12, 25).withView(180, 0); } public Pos getTetrominoSpawnPosition() { @@ -36,7 +38,11 @@ public class Playfield { } public Pos getNextPosition() { - return this.lowerLeftCorner.add(14, 18, 1); + return this.lowerLeftCorner.add(15, 18, 1); + } + + public Pos getScorePosition() { + return this.lowerLeftCorner.add(-5, height+3, 0); } public void generate() { @@ -130,6 +136,52 @@ public class Playfield { } } + public void updateScore(int score) { + this.removeDigits(); + String scoreString = String.valueOf(score); + char[] characters = scoreString.toCharArray(); + ArrayUtils.reverse(characters); + for(int i = 6; i > 0; i--) { + char digit; + if(i <= characters.length) { + digit = characters[i-1]; + } else { + digit = '0'; + } + this.displayDigit(digit, 6-i); + } + } + + + private void displayDigit(char digit, int positionFromLeft) { + int[][] digitArray; + switch (digit) { + case '1' -> digitArray = new int[][]{{0,0,1},{0,1,1},{0,0,1},{0,0,1},{0,0,1}}; + case '2' -> digitArray = new int[][]{{1,1,1},{0,0,1},{1,1,1},{1,0,0},{1,1,1}}; + case '3' -> digitArray = new int[][]{{1,1,1},{0,0,1},{0,1,1},{0,0,1},{1,1,1}}; + case '4' -> digitArray = new int[][]{{1,0,1},{1,0,1},{1,1,1},{0,0,1},{0,0,1}}; + case '5' -> digitArray = new int[][]{{1,1,1},{1,0,0},{1,1,1},{0,0,1},{1,1,1}}; + case '6' -> digitArray = new int[][]{{1,1,1},{1,0,0},{1,1,1},{1,0,1},{1,1,1}}; + case '7' -> digitArray = new int[][]{{1,1,1},{0,0,1},{0,1,0},{0,1,0},{0,1,0}}; + case '8' -> digitArray = new int[][]{{1,1,1},{1,0,1},{1,1,1},{1,0,1},{1,1,1}}; + case '9' -> digitArray = new int[][]{{1,1,1},{1,0,1},{1,1,1},{0,0,1},{1,1,1}}; + default -> digitArray = new int[][]{{1,1,1},{1,0,1},{1,0,1},{1,0,1},{1,1,1}}; + } + + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 5; y++) { + if(digitArray[4-y][x] == 1) this.instance.setBlock(this.getScorePosition().add(positionFromLeft*4+x, y, 0), scoreBlock); + } + } + } + + private void removeDigits() { + for (int x = 0; x < 4 * 6; x++) { + for (int y = 0; y < 5; y++) { + this.instance.setBlock(this.getScorePosition().add(x, y, 0), Block.AIR); + } + } + } private void moveAllLinesUp() { for (int y = height + 3; y > 1; y--) { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 29ea167..5057f0b 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -101,6 +101,7 @@ public class TetrisGame { return TaskSchedule.tick(Math.round((float) standardTickDelay /this.level)); }); + this.updateInfo(); this.nextTetrominoes.forEach(tetromino -> { double xChange; switch (tetromino.shape) { @@ -172,7 +173,7 @@ public class TetrisGame { return false; } this.score += 1; - this.updateSidebar(); + this.updateInfo(); return true; } @@ -183,10 +184,10 @@ public class TetrisGame { return false; } this.score += 2; - this.updateSidebar(); + this.updateInfo(); while(this.currentTetromino.moveDown()) { this.score += 2; - this.updateSidebar(); + this.updateInfo(); } this.setActiveTetrominoDown(); return true; @@ -266,7 +267,8 @@ public class TetrisGame { )); } - private void updateSidebar() { + private void updateInfo() { + this.playfield.updateScore(this.score); this.sidebar.updateLineScore("0", this.score); this.sidebar.updateLineScore("1", this.lines); this.sidebar.updateLineScore("2", this.level); @@ -332,7 +334,7 @@ public class TetrisGame { this.level = (int) Math.floor((double) this.lines / 10) + 1; this.holdPossible = true; - this.updateSidebar(); + this.updateInfo(); this.currentTetromino.setPosition(this.tetrominoSpawnPosition); this.currentTetromino.draw(); From 720d3c8d6538a42e433315629fadbd527b6adfb5 Mon Sep 17 00:00:00 2001 From: lars Date: Thu, 24 Oct 2024 23:10:09 +0200 Subject: [PATCH 22/30] changed Player spawn position --- .../stateless/types/tetris/game/Playfield.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java index b5dd3a1..edf4ddb 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Playfield.java @@ -25,8 +25,7 @@ public class Playfield { } public Pos getPlayerSpawnPosition() { -// return this.lowerLeftCorner.add(6, 9+((double) 3/16), 20).withView(180, 0); - return this.lowerLeftCorner.add(6, 12, 25).withView(180, 0); + return this.lowerLeftCorner.add(6, 9, 20).withView(180, 0); } public Pos getTetrominoSpawnPosition() { @@ -64,10 +63,6 @@ public class Playfield { // hold position: for(int x = 0; x < 4; x++) { for(int y = 0; y < 4; y++) { -// if(x==0 || x==5 || y==0 || y==5) { -// batch.setBlock(this.getHoldPosition().add(x-2, y-2, 0), Block.BLACK_CONCRETE); -// batch.setBlock(this.getHoldPosition().add(x-2, y-2, -1), Block.BLACK_CONCRETE); -// } batch.setBlock(this.getHoldPosition().add(x-1, y-1, -1), Block.QUARTZ_BLOCK); } } @@ -75,10 +70,6 @@ public class Playfield { // next positions: for(int x = 0; x < 4; x++) { for(int y = -4*this.nextTetrominoesCount+4; y < 4; y++) { -// if(x==0 || x==5 || y==-4*this.nextTetrominoesCount+4 || y==5) { -// batch.setBlock(this.getNextPosition().add(x-2, y-2, 0), Block.BLACK_CONCRETE); -// batch.setBlock(this.getNextPosition().add(x-2, y-2, -1), Block.BLACK_CONCRETE); -// } batch.setBlock(this.getNextPosition().add(x-1, y-1, -1), Block.QUARTZ_BLOCK); } } @@ -88,9 +79,6 @@ public class Playfield { batch.setBlock(getPlayerSpawnPosition().sub(1, 1, 1), Block.STONE); batch.setBlock(getPlayerSpawnPosition().sub(0, 1, 1), Block.STONE); -// batch.setBlock(getPlayerSpawnPosition(), Block.IRON_TRAPDOOR.withProperty("half", "bottom")); -// batch.setBlock(getPlayerSpawnPosition().add(0, 1, 0), Block.IRON_TRAPDOOR.withProperty("half", "top")); - BatchUtil.loadAndApplyBatch(batch, this.instance, () -> {}); } From f85ebbbb5d0c8db57ef824025c02c721384442b5 Mon Sep 17 00:00:00 2001 From: lars Date: Thu, 24 Oct 2024 23:37:41 +0200 Subject: [PATCH 23/30] made BoolOption show true or false, shortened tetris Timeout after first death --- .../minigames/instance/game/stateless/StatelessGame.java | 2 -- .../minigames/instance/game/stateless/config/Option.java | 7 ++++--- .../instance/game/stateless/config/common/BoolOption.java | 4 ++-- .../instance/game/stateless/types/tetris/Tetris.java | 5 ++++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java index d0bd25d..7bb79c8 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java @@ -52,8 +52,6 @@ public class StatelessGame extends Game { switch (timeLeft) { case 60, 30, 10, 5, 4, 3, 2, 1 -> new ChatMessage(Icon.SCIENCE).appendStatic("Noch " + timeLeft + " Sekunden!").send(getPlayers()); - case 120 -> - new ChatMessage(Icon.SCIENCE).appendStatic("Noch 2 Minuten!").send(getPlayers()); } timePlayed++; diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/Option.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/Option.java index 02cfea2..1c6fc8f 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/Option.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/Option.java @@ -9,6 +9,7 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import java.util.List; +import java.util.Objects; public abstract class Option { private RestrictionHandler restrictionHandler; @@ -44,11 +45,11 @@ public abstract class Option { } public ItemStack getCurrent(Player p) { - int amount = Integer.parseInt(options.get(pointer).toString()); + String value = options.get(pointer).toString(); return ItemStack.builder(item) .customName(name.getAssembled(p)) .lore(TranslatedComponent.byId("optionCommon#value").setColor(NamedTextColor.GOLD).getAssembled(p) - .append(Component.text(": ")).append(Component.text(amount))) + .append(Component.text(": ")).append(Component.text(value))) .build(); } @@ -57,7 +58,7 @@ public abstract class Option { } public boolean getAsBoolean() { - return getAsInt() != 0; + return Objects.equals(getAsString(), "true") || Objects.equals(getAsString(), "1"); } public String getAsString() { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/common/BoolOption.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/common/BoolOption.java index 22017e0..ae9548f 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/common/BoolOption.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/config/common/BoolOption.java @@ -6,8 +6,8 @@ import net.minestom.server.item.Material; import java.util.List; -public class BoolOption extends Option { +public class BoolOption extends Option { public BoolOption(String id, Material item, TranslatedComponent name) { - super(id, item, name, List.of(1, 0)); + super(id, item, name, List.of("true", "false")); } } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index b52376d..7e8f310 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -4,6 +4,8 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.TetrisGame; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.Tetromino; +import eu.mhsl.minenet.minigames.message.Icon; +import eu.mhsl.minenet.minigames.message.type.ChatMessage; import eu.mhsl.minenet.minigames.score.PointsWinScore; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Pos; @@ -129,8 +131,9 @@ class Tetris extends StatelessGame { getScore().insertResult(event.getPlayer(), tetrisGame.getScore()); if(!setTimeLimit) { - this.setTimeLimit(120); + this.setTimeLimit(90); setTimeLimit = true; + new ChatMessage(Icon.SCIENCE).appendStatic("Noch 90 Sekunden!").send(getPlayers()); } } } From 55be88b7daa766c8b3c3a9f2db9d1059e24bde82 Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 4 Nov 2024 15:04:09 +0100 Subject: [PATCH 24/30] removed countdown when no player left --- build.gradle | 2 +- .../game/stateless/types/tetris/Tetris.java | 29 +++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 6607b2c..5d7a77d 100644 --- a/build.gradle +++ b/build.gradle @@ -89,5 +89,5 @@ tasks.register('copyJarToServer', Exec) { dependsOn shadowJar mustRunAfter shadowJar - commandLine 'scp', 'build/libs/Minigames-1.0-SNAPSHOT.jar', 'root@10.20.6.5:/root/minigames' + commandLine 'scp', 'build/libs/Minigames-1.0-SNAPSHOT.jar', '/home/lars/Documents/Minecraft Server/minigames' } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 7e8f310..3b5dfe1 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -69,6 +69,7 @@ class Tetris extends StatelessGame { @Override protected void onPlayerLeave(Player p) { this.tetrisGames.get(p).sidebar.removeViewer(p); + this.letPlayerLoose(p); } @Override @@ -124,17 +125,27 @@ class Tetris extends StatelessGame { } protected void onPlayerTick(PlayerTickEvent event) { - TetrisGame tetrisGame = this.tetrisGames.get(event.getPlayer()); + Player player = event.getPlayer(); + TetrisGame tetrisGame = this.tetrisGames.get(player); if(tetrisGame == null) return; - if(tetrisGame.lost && event.getPlayer().getGameMode() != GameMode.SPECTATOR) { - event.getPlayer().setGameMode(GameMode.SPECTATOR); - getScore().insertResult(event.getPlayer(), tetrisGame.getScore()); + if(tetrisGame.lost && player.getGameMode() != GameMode.SPECTATOR) { + letPlayerLoose(player); + } + } - if(!setTimeLimit) { - this.setTimeLimit(90); - setTimeLimit = true; - new ChatMessage(Icon.SCIENCE).appendStatic("Noch 90 Sekunden!").send(getPlayers()); - } + private void letPlayerLoose(Player player) { + TetrisGame tetrisGame = this.tetrisGames.get(player); + player.setGameMode(GameMode.SPECTATOR); + getScore().insertResult(player, tetrisGame.getScore()); + + boolean allGamesLost = this.tetrisGames.values().stream() + .filter(tetrisGame1 -> !tetrisGame1.lost) + .toList() + .isEmpty(); + if(!setTimeLimit && !allGamesLost) { + this.setTimeLimit(90); + setTimeLimit = true; + new ChatMessage(Icon.SCIENCE).appendStatic("Noch 90 Sekunden!").send(getPlayers()); } } From e663f3f105d8f53fd38d8a248b456c8dcffc235c Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 4 Nov 2024 21:53:54 +0100 Subject: [PATCH 25/30] made tetris spectators invisible, added barrier walls to elytra race --- .../eu/mhsl/minenet/minigames/instance/game/Game.java | 7 ++++++- .../game/stateless/types/elytraRace/ElytraRace.java | 11 +++++------ .../instance/game/stateless/types/tetris/Tetris.java | 9 ++++++--- src/main/resources/config.yml | 3 ++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/Game.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/Game.java index dfae886..7cd870b 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/Game.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/Game.java @@ -11,6 +11,7 @@ import eu.mhsl.minenet.minigames.instance.Spawnable; import eu.mhsl.minenet.minigames.instance.room.Room; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Pos; +import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; import net.minestom.server.event.item.ItemDropEvent; import net.minestom.server.event.player.PlayerBlockBreakEvent; @@ -98,7 +99,11 @@ public abstract class Game extends MineNetInstance implements Spawnable { public void unload() { this.onUnload(); - getPlayers().forEach(Room::setOwnRoom); + getPlayers().forEach(player -> { + Room.setOwnRoom(player); + player.setGameMode(GameMode.SURVIVAL); + player.setInvisible(false); + }); scheduler().scheduleTask(() -> { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/elytraRace/ElytraRace.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/elytraRace/ElytraRace.java index 2206789..18d696a 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/elytraRace/ElytraRace.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/elytraRace/ElytraRace.java @@ -39,6 +39,7 @@ public class ElytraRace extends StatelessGame { private final ValeGenerator vale = new ValeGenerator(); private final int gameHeight = 0; + private final int seaLevel = -55; private final int ringSpacing = 100; private final int ringCount; @@ -61,7 +62,7 @@ public class ElytraRace extends StatelessGame { this.ringCount = ringCount; setGenerator(vale); - vale.setCalculateSeaLevel(point -> -55); + vale.setCalculateSeaLevel(point -> seaLevel); vale.setXShiftMultiplier(integer -> NumberUtil.map(integer, 50, 500, 0, 1)); vale.addMixIn(new PlaneTerrainGenerator(gameHeight, Block.BARRIER)); @@ -105,9 +106,7 @@ public class ElytraRace extends StatelessGame { @Override protected void onLoad(@NotNull CompletableFuture callback) { Point spawnpoint = new Pos(vale.getXShiftAtZ(0), -46, 0); - GeneratorUtils.iterateArea(spawnpoint.sub(5, 0, 5), spawnpoint.add(5, 0, 5), point -> { - setBlock(point, BlockPallet.STREET.rnd()); - }); + GeneratorUtils.iterateArea(spawnpoint.sub(5, 0, 5), spawnpoint.add(5, 0, 5), point -> setBlock(point, BlockPallet.STREET.rnd())); generateRing(ringSpacing); generateRing(ringSpacing * 2); @@ -194,8 +193,8 @@ public class ElytraRace extends StatelessGame { Point ringPos = getRingPositionAtZ(zPos); GeneratorUtils.iterateArea( - ringPos.sub(100, 0, 0).withY(0), // TODO 0 was before update getDimensionType().getMinY, might not work correctly - ringPos.add(100, 0, 0).withY(gameHeight), + ringPos.sub(100, 0, 0).withY(0), + ringPos.add(100, 0, 0).withY(seaLevel), point -> batch.setBlock(point, Block.BARRIER) ); GeneratorUtils.iterateArea( diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 3b5dfe1..f7b19ef 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -61,9 +61,11 @@ class Tetris extends StatelessGame { @Override protected void onStop() { - this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.loose()); - this.tetrisGames.forEach((player, tetrisGame) -> getScore().insertResult(player, tetrisGame.getScore())); - this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.sidebar.removeViewer(player)); + this.tetrisGames.forEach((player, tetrisGame) -> { + tetrisGame.loose(); + getScore().insertResult(player, tetrisGame.getScore()); + tetrisGame.sidebar.removeViewer(player); + }); } @Override @@ -136,6 +138,7 @@ class Tetris extends StatelessGame { private void letPlayerLoose(Player player) { TetrisGame tetrisGame = this.tetrisGames.get(player); player.setGameMode(GameMode.SPECTATOR); + player.setInvisible(true); getScore().insertResult(player, tetrisGame.getScore()); boolean allGamesLost = this.tetrisGames.values().stream() diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 9f18e11..39956b0 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -17,4 +17,5 @@ api: port: 8080 admins: - - minetec \ No newline at end of file + - minetec + - 28Pupsi28 \ No newline at end of file From 0699206c21c3cb03cb4502710145477435b6215c Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 23 Nov 2024 14:26:19 +0100 Subject: [PATCH 26/30] started fixing pr comments --- build.gradle | 2 +- .../minigames/command/PrivilegedCommand.java | 4 +--- .../instance/game/stateless/StatelessGame.java | 2 +- .../game/stateless/types/tetris/Tetris.java | 18 +++++++++++------- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/build.gradle b/build.gradle index 5d7a77d..6607b2c 100644 --- a/build.gradle +++ b/build.gradle @@ -89,5 +89,5 @@ tasks.register('copyJarToServer', Exec) { dependsOn shadowJar mustRunAfter shadowJar - commandLine 'scp', 'build/libs/Minigames-1.0-SNAPSHOT.jar', '/home/lars/Documents/Minecraft Server/minigames' + commandLine 'scp', 'build/libs/Minigames-1.0-SNAPSHOT.jar', 'root@10.20.6.5:/root/minigames' } diff --git a/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java b/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java index 7a2cc37..13294f6 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java +++ b/src/main/java/eu/mhsl/minenet/minigames/command/PrivilegedCommand.java @@ -27,9 +27,7 @@ public class PrivilegedCommand extends Command { } protected CommandCondition isPrivileged() { - //TODO -// return (sender, commandString) -> sender.hasPermission("admin"); - return (sender, commandString) -> true; + return (sender, commandString) -> sender.hasPermission("admin"); } protected void addCondition(CommandCondition condition) { diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java index 7bb79c8..cef6668 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java @@ -100,7 +100,7 @@ public class StatelessGame extends Game { countdownUnload(); } - protected void countdownUnload() { + private void countdownUnload() { new TitleMessage(Duration.ofSeconds(1)).appendTranslated("score#done").send(getPlayers()); scheduler().scheduleTask(this::unload, TaskSchedule.seconds(5), TaskSchedule.stop()); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index f7b19ef..a5d506b 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -18,12 +18,13 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Random; +import java.util.WeakHashMap; class Tetris extends StatelessGame { - private final Map tetrisGames = new HashMap<>(); + private final Map tetrisGames = new WeakHashMap<>(); private final int nextTetrominoesCount; private final boolean isFast; private final boolean hasCombat; @@ -53,7 +54,7 @@ class Tetris extends StatelessGame { .forEach(Entity::remove); if(this.hasCombat) { - this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values().stream().toList())); + this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames((List) this.tetrisGames.values())); } this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.start()); @@ -76,6 +77,8 @@ class Tetris extends StatelessGame { @Override protected void onPlayerMove(@NotNull PlayerMoveEvent event) { + event.setCancelled(true); + Player player = event.getPlayer(); Pos previousPosition = event.getPlayer().getPosition(); Pos currentPosition = event.getNewPosition(); @@ -103,15 +106,16 @@ class Tetris extends StatelessGame { double forwardAmount = movementVector.dot(forward); double leftAmount = movementVector.dot(left); - if (forwardAmount > 0.018) { + double buttonPressAmount = 0.018; + if (forwardAmount > buttonPressAmount) { tetrisGame.pressedButton(TetrisGame.Button.W); - } else if (forwardAmount < -0.018) { + } else if (forwardAmount < -buttonPressAmount) { tetrisGame.pressedButton(TetrisGame.Button.S); } - if (leftAmount > 0.018) { + if (leftAmount > buttonPressAmount) { tetrisGame.pressedButton(TetrisGame.Button.D); - } else if (leftAmount < -0.018) { + } else if (leftAmount < -buttonPressAmount) { tetrisGame.pressedButton(TetrisGame.Button.A); } From 3fe57d5fe99f2ee790712c8337ee3884b4bad556 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 23 Nov 2024 22:24:08 +0100 Subject: [PATCH 27/30] continued fixing pr comments --- .../game/stateless/StatelessGame.java | 2 +- .../game/stateless/types/tetris/Tetris.java | 20 +++--- .../types/tetris/game/TetrisGame.java | 69 ++++++------------- .../types/tetris/game/Tetromino.java | 25 +++++-- 4 files changed, 49 insertions(+), 67 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java index cef6668..465e306 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/StatelessGame.java @@ -50,7 +50,7 @@ public class StatelessGame extends Game { int timeLeft = timeLimit - timePlayed; switch (timeLeft) { - case 60, 30, 10, 5, 4, 3, 2, 1 -> + case 90, 60, 30, 10, 5, 4, 3, 2, 1 -> new ChatMessage(Icon.SCIENCE).appendStatic("Noch " + timeLeft + " Sekunden!").send(getPlayers()); } diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index a5d506b..d08e009 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -4,8 +4,6 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.TetrisGame; import eu.mhsl.minenet.minigames.instance.Dimension; import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.Tetromino; -import eu.mhsl.minenet.minigames.message.Icon; -import eu.mhsl.minenet.minigames.message.type.ChatMessage; import eu.mhsl.minenet.minigames.score.PointsWinScore; import net.kyori.adventure.text.Component; import net.minestom.server.coordinate.Pos; @@ -18,7 +16,6 @@ import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; import org.jetbrains.annotations.NotNull; -import java.util.List; import java.util.Map; import java.util.Random; import java.util.WeakHashMap; @@ -54,7 +51,7 @@ class Tetris extends StatelessGame { .forEach(Entity::remove); if(this.hasCombat) { - this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames((List) this.tetrisGames.values())); + this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values())); } this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.start()); @@ -146,13 +143,12 @@ class Tetris extends StatelessGame { getScore().insertResult(player, tetrisGame.getScore()); boolean allGamesLost = this.tetrisGames.values().stream() - .filter(tetrisGame1 -> !tetrisGame1.lost) + .filter(game -> !game.lost) .toList() .isEmpty(); if(!setTimeLimit && !allGamesLost) { this.setTimeLimit(90); setTimeLimit = true; - new ChatMessage(Icon.SCIENCE).appendStatic("Noch 90 Sekunden!").send(getPlayers()); } } @@ -161,8 +157,8 @@ class Tetris extends StatelessGame { p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build()); p.setSprinting(false); - if(this.tetrisGames.get(p) == null) { - this.tetrisGames.put(p, new TetrisGame( + this.tetrisGames.computeIfAbsent(p, player -> { + TetrisGame newTetrisGame = new TetrisGame( this, getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*30, 0, 0), Tetromino.Shape.J, @@ -170,10 +166,12 @@ class Tetris extends StatelessGame { this.isFast, this.hasCombat, this.randomSeed - )); + ); this.tetrisGames.get(p).generate(); - this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values().stream().toList())); - } + this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values())); + return newTetrisGame; + }); + TetrisGame tetrisGame = this.tetrisGames.get(p); p.teleport(tetrisGame.getPlayerSpawnPosition()); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java index 5057f0b..20d2902 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/TetrisGame.java @@ -45,10 +45,6 @@ public class TetrisGame { space } - public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, long randomSeed) { - this(instance, lowerLeftCorner, Tetromino.Shape.J, 3, false, false, randomSeed); - } - public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino.Shape startTetrominoShape, int nextTetrominoesCount, boolean isfast, boolean hasCombat, long randomSeed) { this.isFast = isfast; this.hasCombat = hasCombat; @@ -68,19 +64,24 @@ public class TetrisGame { } public void pressedButton(Button button) { - if(this.lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-100) return; + final int standardButtonDelay = 100; + final int buttonDebounce = 70; + + if(this.lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-standardButtonDelay) return; this.lastPresses.put(button, System.currentTimeMillis()); - if(button == Button.W) this.lastPresses.put(button, System.currentTimeMillis()+70); - if(button == Button.S) this.lastPresses.put(button, System.currentTimeMillis()-70); + if(button == Button.W) this.lastPresses.put(button, System.currentTimeMillis()+buttonDebounce); + if(button == Button.S) this.lastPresses.put(button, System.currentTimeMillis()-buttonDebounce); + + if(this.lost || this.paused) return; switch (button) { - case A -> this.moveLeft(); + case A -> this.currentTetromino.moveLeft(); case S -> this.moveDown(); - case D -> this.moveRight(); + case D -> this.currentTetromino.moveRight(); case W -> this.hardDrop(); - case mouseLeft -> this.rotate(false); - case mouseRight -> this.rotate(true); + case mouseLeft -> this.currentTetromino.rotate(false); + case mouseRight -> this.currentTetromino.rotate(true); case space -> this.switchHold(); } } @@ -96,18 +97,16 @@ public class TetrisGame { if(this.lost) return TaskSchedule.stop(); int standardTickDelay = 40; if(this.isFast) standardTickDelay = 20; - if(this.paused) return TaskSchedule.tick(Math.round((float) standardTickDelay /this.level)); + + TaskSchedule nextTick = TaskSchedule.tick(Math.round((float) standardTickDelay /this.level)); + if(this.paused) return nextTick; this.tick(); - return TaskSchedule.tick(Math.round((float) standardTickDelay /this.level)); + return nextTick; }); this.updateInfo(); this.nextTetrominoes.forEach(tetromino -> { - double xChange; - switch (tetromino.shape) { - case O, I -> xChange = 0; - case null, default -> xChange = -0.5; - } + double xChange = -tetromino.getXChange(); tetromino.setPosition(this.nextPosition.sub(xChange, 4*this.nextTetrominoes.indexOf(tetromino), 0)); tetromino.drawAsEntities(); }); @@ -131,7 +130,7 @@ public class TetrisGame { return this.score; } - public void updateOtherTetrisGames(List tetrisGames) { + public void updateOtherTetrisGames(Collection tetrisGames) { List games = new ArrayList<>(tetrisGames); games.remove(this); games.removeIf(tetrisGame -> tetrisGame.lost); @@ -151,23 +150,7 @@ public class TetrisGame { } - private boolean rotate(boolean clockwise) { - if(this.lost || this.paused) return false; - return this.currentTetromino.rotate(clockwise); - } - - private boolean moveLeft() { - if(this.lost || this.paused) return false; - return this.currentTetromino.moveLeft(); - } - - private boolean moveRight() { - if(this.lost || this.paused) return false; - return this.currentTetromino.moveRight(); - } - private boolean moveDown() { - if(this.lost || this.paused) return false; if(!this.currentTetromino.moveDown()) { this.setActiveTetrominoDown(); return false; @@ -178,7 +161,6 @@ public class TetrisGame { } private boolean hardDrop() { - if(this.lost || this.paused) return false; if(!this.currentTetromino.moveDown()) { this.setActiveTetrominoDown(); return false; @@ -195,7 +177,6 @@ public class TetrisGame { private boolean switchHold() { if(!holdPossible) return false; - if(this.lost || this.paused) return false; Tetromino newCurrentTetromino; if(this.holdTetromino == null) { @@ -208,18 +189,14 @@ public class TetrisGame { } this.currentTetromino.remove(); - this.holdTetromino = new Tetromino(this.instance, this.currentTetromino.shape); + this.holdTetromino = new Tetromino(this.instance, this.currentTetromino.getShape()); this.currentTetromino = newCurrentTetromino; this.currentTetromino.setPosition(this.tetrominoSpawnPosition); this.currentTetromino.draw(); if(!this.currentTetromino.moveDown()) loose(); - double xChange; - switch (this.holdTetromino.shape) { - case O, I -> xChange = 0; - case null, default -> xChange = 0.5; - } + double xChange = this.holdTetromino.getXChange(); this.holdTetromino.setPosition(this.holdPosition.add(xChange, 0, 0)); this.holdTetromino.drawAsEntities(); this.holdPossible = false; @@ -239,11 +216,7 @@ public class TetrisGame { Tetromino newTetromino = this.tetrominoBag.removeFirst(); this.nextTetrominoes.add(newTetromino); this.nextTetrominoes.forEach(tetromino -> { - double xChange; - switch (tetromino.shape) { - case O, I -> xChange = 0; - case null, default -> xChange = -0.5; - } + double xChange = -tetromino.getXChange(); tetromino.setPosition(this.nextPosition.sub(xChange, 4*this.nextTetrominoes.indexOf(tetromino), 0)); tetromino.drawAsEntities(); }); diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java index 5a08ff8..f673961 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/game/Tetromino.java @@ -14,7 +14,7 @@ import java.util.List; import java.util.UUID; public class Tetromino { - public final Shape shape; + private final Shape shape; private final StatelessGame instance; private Pos position; private int[][] shapeArray; @@ -90,12 +90,10 @@ public class Tetromino { getBlockPositions().forEach(pos -> { Entity ghostBlock = new Entity(ghostEntityType); ((FallingBlockMeta) ghostBlock.getEntityMeta()).setBlock(this.getGhostBlock()); -// ((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(this.getGhostBlock()); ghostBlock.setNoGravity(true); ghostBlock.setGlowing(true); ghostBlock.setTag(uuidTag, this.uuid.toString()); ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(0.5, 0, 0.5)); -// ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(1, 0, 1)); }); } @@ -106,11 +104,9 @@ public class Tetromino { getBlockPositions().forEach(pos -> { Entity ghostBlock = new Entity(ghostEntityType); ((FallingBlockMeta) ghostBlock.getEntityMeta()).setBlock(this.getColoredBlock()); -// ((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(this.getGhostBlock()); ghostBlock.setNoGravity(true); ghostBlock.setTag(uuidTag, this.uuid.toString()); ghostBlock.setInstance(this.instance, pos.add(0.5, 0, 0.5)); -// ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(1, 0, 1)); }); } @@ -138,12 +134,27 @@ public class Tetromino { this.instance.getEntities().stream() .filter(entity -> { String tagValue = entity.getTag(uuidTag); - if(tagValue != null) return entity.getTag(uuidTag).equals(this.uuid.toString()); - return false; + if(tagValue == null) return false; + return entity.getTag(uuidTag).equals(this.uuid.toString()); }) .forEach(Entity::remove); } + public double getXChange() { + switch (this.shape) { + case O, I -> { + return 0; + } + case null, default -> { + return 0.5; + } + } + } + + + public Shape getShape() { + return this.shape; + } private Block getGhostBlock() { Block returnBlock; From 18689ac0df420ae9137e90f2dc87c711e426f49f Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 23 Nov 2024 23:56:18 +0100 Subject: [PATCH 28/30] fixed score --- .../game/stateless/types/tetris/Tetris.java | 22 +++++++----- .../minigames/score/FirstWinsScore.java | 10 ------ .../minigames/score/LastWinsScore.java | 10 ------ .../mhsl/minenet/minigames/score/NoScore.java | 10 ------ .../minigames/score/PointsWinScore.java | 12 ++----- .../mhsl/minenet/minigames/score/Score.java | 34 +++++++++++-------- 6 files changed, 35 insertions(+), 63 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index d08e009..9966aa5 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -16,9 +16,7 @@ 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.*; class Tetris extends StatelessGame { private final Map tetrisGames = new WeakHashMap<>(); @@ -42,6 +40,8 @@ class Tetris extends StatelessGame { Random random = new Random(); this.randomSeed = random.nextLong(); + + System.out.println("1"); } @Override @@ -68,21 +68,23 @@ class Tetris extends StatelessGame { @Override protected void onPlayerLeave(Player p) { + System.out.println("2"); this.tetrisGames.get(p).sidebar.removeViewer(p); this.letPlayerLoose(p); } @Override protected void onPlayerMove(@NotNull PlayerMoveEvent event) { - event.setCancelled(true); - Player player = event.getPlayer(); Pos previousPosition = event.getPlayer().getPosition(); Pos currentPosition = event.getNewPosition(); TetrisGame tetrisGame = this.tetrisGames.get(player); - if(tetrisGame == null) return; + if(tetrisGame == null) { + event.setCancelled(true); + return; + } if(tetrisGame.lost) return; if(player.getGameMode() == GameMode.SPECTATOR) return; @@ -132,11 +134,13 @@ class Tetris extends StatelessGame { TetrisGame tetrisGame = this.tetrisGames.get(player); if(tetrisGame == null) return; if(tetrisGame.lost && player.getGameMode() != GameMode.SPECTATOR) { + System.out.println("3"); letPlayerLoose(player); } } private void letPlayerLoose(Player player) { + System.out.println("4"); TetrisGame tetrisGame = this.tetrisGames.get(player); player.setGameMode(GameMode.SPECTATOR); player.setInvisible(true); @@ -167,8 +171,10 @@ class Tetris extends StatelessGame { this.hasCombat, this.randomSeed ); - this.tetrisGames.get(p).generate(); - this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values())); + newTetrisGame.generate(); + List games = new ArrayList<>(this.tetrisGames.values()); + games.add(newTetrisGame); + this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames(games)); return newTetrisGame; }); diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/FirstWinsScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/FirstWinsScore.java index 9595e6f..bc505dd 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/FirstWinsScore.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/FirstWinsScore.java @@ -8,21 +8,11 @@ import java.time.Duration; import java.util.Set; public class FirstWinsScore extends Score { - @Override - public void insertResultImplementation(Set p, int points) { - - } - @Override public void insertResultImplementation(Set p) { getScores().add(p); } - @Override - public void insertResult(Player p, int points) { - - } - @Override protected TranslatableMessage scoreMessage() { return new TitleMessage(Duration.ofMillis(1000), Duration.ofSeconds(1)).appendTranslated("score#finish"); diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/LastWinsScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/LastWinsScore.java index c4a40b3..c37cb96 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/LastWinsScore.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/LastWinsScore.java @@ -8,21 +8,11 @@ import java.time.Duration; import java.util.Set; public class LastWinsScore extends Score { - @Override - public void insertResultImplementation(Set p, int points) { - - } - @Override public void insertResultImplementation(Set p) { getScores().addFirst(p); } - @Override - public void insertResult(Player p, int points) { - - } - @Override protected TranslatableMessage scoreMessage() { return new TitleMessage(Duration.ofMillis(1000), Duration.ofSeconds(1)).appendTranslated("score#death"); diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/NoScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/NoScore.java index 232d874..91478d5 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/NoScore.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/NoScore.java @@ -10,21 +10,11 @@ public class NoScore extends Score { protected void checkGameEnd() { } - @Override - public void insertResultImplementation(Set p, int points) { - - } - @Override public void insertResultImplementation(Set p) { } - @Override - public void insertResult(Player p, int points) { - - } - @Override protected TranslatableMessage scoreMessage() { return null; diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java b/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java index 209cfe1..d9190f7 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/PointsWinScore.java @@ -15,8 +15,8 @@ public class PointsWinScore extends Score { private Map, Integer> scoreOrder = new HashMap<>(); @Override - public void insertResultImplementation(Set p, int points) { - this.scoreOrder.put(p, points); + protected void insertResultImplementation(Set p, int currentPoints) { + this.scoreOrder.put(p, currentPoints); this.scoreOrder = MapUtil.sortByValue(this.scoreOrder); getScores().clear(); this.scoreOrder.forEach((player, integer) -> getScores().addFirst(player)); @@ -27,14 +27,6 @@ public class PointsWinScore extends Score { this.insertResultImplementation(p, 0); } - @Override - public void insertResult(Player p, int points) { - if(hasResult(p)) return; - this.scoreMessage().send(p); - this.insertResultImplementation(Set.of(p), points); - this.checkGameEnd(); - } - @Override public void setDone() { if(isClosed()) return; diff --git a/src/main/java/eu/mhsl/minenet/minigames/score/Score.java b/src/main/java/eu/mhsl/minenet/minigames/score/Score.java index 383a9e5..dce3e92 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/score/Score.java +++ b/src/main/java/eu/mhsl/minenet/minigames/score/Score.java @@ -8,6 +8,7 @@ import net.minestom.server.entity.Player; import net.minestom.server.event.instance.AddEntityToInstanceEvent; import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent; import net.minestom.server.event.player.PlayerDisconnectEvent; +import org.apache.commons.lang3.NotImplementedException; import java.util.ArrayList; import java.util.List; @@ -22,10 +23,19 @@ public abstract class Score { public Score() {} - public Score(int ignoreLastPlayers) { - this.ignoreLastPlayers = ignoreLastPlayers; + protected abstract void insertResultImplementation(Set p); + + protected void insertResultImplementation(Set p, int points) { + throw new NotImplementedException("This Score type is not able to process points"); } + public void insertResult(Player p) { + this.insertResultProcessor(p, () -> this.insertResultImplementation(Set.of(p))); + } + + public void insertResult(Player p, int points) { + this.insertResultProcessor(p, () -> this.insertResultImplementation(Set.of(p), points)); + } public void attachListeners() { this.instance.eventNode() @@ -46,21 +56,8 @@ public abstract class Score { } } - public abstract void insertResultImplementation(Set p, int points); - - protected abstract void insertResultImplementation(Set p); - - public abstract void insertResult(Player p, int points); - protected abstract TranslatableMessage scoreMessage(); - public void insertResult(Player p) { - if(hasResult(p)) return; - this.scoreMessage().send(p); - this.insertResultImplementation(Set.of(p)); - this.checkGameEnd(); - } - public void insertRemainingPlayers(Set players) { this.insertResultImplementation(players.stream().filter(p -> !hasResult(p)).collect(Collectors.toSet())); setDone(); @@ -99,6 +96,13 @@ public abstract class Score { instance.stop(); } + private void insertResultProcessor(Player p, Runnable callback) { + if(hasResult(p)) return; + this.scoreMessage().send(p); + callback.run(); + this.checkGameEnd(); + } + public boolean isClosed() { return isClosed; } From bc27c35f1a7c6b2d96df8644787b19b01410f743 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 23 Nov 2024 23:58:54 +0100 Subject: [PATCH 29/30] removed debug outputs --- .../instance/game/stateless/types/tetris/Tetris.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 9966aa5..73b1e39 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -40,8 +40,6 @@ class Tetris extends StatelessGame { Random random = new Random(); this.randomSeed = random.nextLong(); - - System.out.println("1"); } @Override @@ -68,7 +66,6 @@ class Tetris extends StatelessGame { @Override protected void onPlayerLeave(Player p) { - System.out.println("2"); this.tetrisGames.get(p).sidebar.removeViewer(p); this.letPlayerLoose(p); } @@ -134,13 +131,11 @@ class Tetris extends StatelessGame { TetrisGame tetrisGame = this.tetrisGames.get(player); if(tetrisGame == null) return; if(tetrisGame.lost && player.getGameMode() != GameMode.SPECTATOR) { - System.out.println("3"); letPlayerLoose(player); } } private void letPlayerLoose(Player player) { - System.out.println("4"); TetrisGame tetrisGame = this.tetrisGames.get(player); player.setGameMode(GameMode.SPECTATOR); player.setInvisible(true); From 378d8722835906471d8994d91da5c09fb8c6e507 Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 24 Nov 2024 00:47:15 +0100 Subject: [PATCH 30/30] changed computeIfAbsent back to if statement --- .../game/stateless/types/tetris/Tetris.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java index 73b1e39..84be942 100644 --- a/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java +++ b/src/main/java/eu/mhsl/minenet/minigames/instance/game/stateless/types/tetris/Tetris.java @@ -156,22 +156,19 @@ class Tetris extends StatelessGame { p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build()); p.setSprinting(false); - this.tetrisGames.computeIfAbsent(p, player -> { - TetrisGame newTetrisGame = new TetrisGame( - this, - getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*30, 0, 0), - Tetromino.Shape.J, - this.nextTetrominoesCount, - this.isFast, - this.hasCombat, - this.randomSeed - ); - newTetrisGame.generate(); - List games = new ArrayList<>(this.tetrisGames.values()); - games.add(newTetrisGame); - this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames(games)); - return newTetrisGame; - }); + if(this.tetrisGames.get(p) == null) { + this.tetrisGames.put(p, new TetrisGame( + this, + getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*30, 0, 0), + Tetromino.Shape.J, + this.nextTetrominoesCount, + this.isFast, + this.hasCombat, + this.randomSeed + )); + this.tetrisGames.get(p).generate(); + this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values())); + } TetrisGame tetrisGame = this.tetrisGames.get(p);