From 9ca3a8d34c2f37ec1e00b705c1c48bb8c64ce95f Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Mon, 2 Feb 2026 21:59:55 +0100 Subject: [PATCH] feat: Multiplayer player moving between rooms --- .../messages/player/PlayerArrivalChange.java | 4 +- .../socket/messages/room/MovePlayerRoom.java | 8 ++ .../messages/room/MovePlayerRoomResponse.java | 8 ++ .../handlers/RoomChangeEventHandler.java | 11 +-- .../events/MovePlayerRoomResponseHandler.java | 29 ++++++++ .../events/PlayerArrivalChangeHandler.java | 74 +++++++++++++++++-- .../handlers/ConnectToAGameHandler.java | 4 +- .../handlers/MovePlayerRoomHandler.java | 39 ++++++++++ 8 files changed, 163 insertions(+), 14 deletions(-) create mode 100644 common/src/main/java/cz/jzitnik/common/socket/messages/room/MovePlayerRoom.java create mode 100644 common/src/main/java/cz/jzitnik/common/socket/messages/room/MovePlayerRoomResponse.java create mode 100644 game/src/main/java/cz/jzitnik/client/socket/events/MovePlayerRoomResponseHandler.java create mode 100644 server/src/main/java/cz/jzitnik/server/events/handlers/MovePlayerRoomHandler.java diff --git a/common/src/main/java/cz/jzitnik/common/socket/messages/player/PlayerArrivalChange.java b/common/src/main/java/cz/jzitnik/common/socket/messages/player/PlayerArrivalChange.java index 4891171..e16aa43 100644 --- a/common/src/main/java/cz/jzitnik/common/socket/messages/player/PlayerArrivalChange.java +++ b/common/src/main/java/cz/jzitnik/common/socket/messages/player/PlayerArrivalChange.java @@ -1,6 +1,8 @@ package cz.jzitnik.common.socket.messages.player; +import cz.jzitnik.common.models.coordinates.RoomCords; import cz.jzitnik.common.socket.SocketMessage; -public record PlayerArrivalChange(int id, boolean arrived) implements SocketMessage { +public record PlayerArrivalChange(int id, RoomCords playerCords, boolean arrived, + boolean rerender) implements SocketMessage { } diff --git a/common/src/main/java/cz/jzitnik/common/socket/messages/room/MovePlayerRoom.java b/common/src/main/java/cz/jzitnik/common/socket/messages/room/MovePlayerRoom.java new file mode 100644 index 0000000..631fd6c --- /dev/null +++ b/common/src/main/java/cz/jzitnik/common/socket/messages/room/MovePlayerRoom.java @@ -0,0 +1,8 @@ +package cz.jzitnik.common.socket.messages.room; + +import cz.jzitnik.common.models.coordinates.RoomCords; +import cz.jzitnik.common.socket.SocketMessage; + +public record MovePlayerRoom(String newRoomId, RoomCords oldCords, RoomCords newCords) implements SocketMessage { + +} diff --git a/common/src/main/java/cz/jzitnik/common/socket/messages/room/MovePlayerRoomResponse.java b/common/src/main/java/cz/jzitnik/common/socket/messages/room/MovePlayerRoomResponse.java new file mode 100644 index 0000000..789cb1f --- /dev/null +++ b/common/src/main/java/cz/jzitnik/common/socket/messages/room/MovePlayerRoomResponse.java @@ -0,0 +1,8 @@ +package cz.jzitnik.common.socket.messages.room; + +import cz.jzitnik.common.socket.SocketMessage; + +import java.util.Set; + +public record MovePlayerRoomResponse(Set players) implements SocketMessage { +} diff --git a/game/src/main/java/cz/jzitnik/client/events/handlers/RoomChangeEventHandler.java b/game/src/main/java/cz/jzitnik/client/events/handlers/RoomChangeEventHandler.java index 0f12a8d..34a762b 100644 --- a/game/src/main/java/cz/jzitnik/client/events/handlers/RoomChangeEventHandler.java +++ b/game/src/main/java/cz/jzitnik/client/events/handlers/RoomChangeEventHandler.java @@ -3,14 +3,15 @@ package cz.jzitnik.client.events.handlers; import cz.jzitnik.client.annotations.EventHandler; import cz.jzitnik.client.annotations.injectors.InjectDependency; import cz.jzitnik.client.annotations.injectors.InjectState; -import cz.jzitnik.client.events.FullRoomDraw; import cz.jzitnik.client.events.RoomChangeEvent; +import cz.jzitnik.client.events.SendSocketMessageEvent; import cz.jzitnik.client.game.GameRoom; import cz.jzitnik.client.game.GameState; import cz.jzitnik.common.models.coordinates.RoomCords; import cz.jzitnik.client.utils.events.AbstractEventHandler; import cz.jzitnik.client.utils.events.EventManager; import cz.jzitnik.client.utils.roomtasks.RoomTaskScheduler; +import cz.jzitnik.common.socket.messages.room.MovePlayerRoom; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.Executors; @@ -31,6 +32,7 @@ public class RoomChangeEventHandler extends AbstractEventHandler currentRoom.getLeft(); @@ -50,10 +52,9 @@ public class RoomChangeEventHandler extends AbstractEventHandler playerCords.updateCords(playerCords.getX(), 10); } + eventManager.emitEvent(new SendSocketMessageEvent(new MovePlayerRoom(newRoom.getId(), oldCords, playerCords))); + gameState.setCurrentRoom(newRoom); - scheduler.schedule(() -> { - roomTaskScheduler.setupNewSchedulers(newRoom); - }, 200, TimeUnit.MILLISECONDS); - eventManager.emitEvent(new FullRoomDraw()); + scheduler.schedule(() -> roomTaskScheduler.setupNewSchedulers(newRoom), 200, TimeUnit.MILLISECONDS); } } diff --git a/game/src/main/java/cz/jzitnik/client/socket/events/MovePlayerRoomResponseHandler.java b/game/src/main/java/cz/jzitnik/client/socket/events/MovePlayerRoomResponseHandler.java new file mode 100644 index 0000000..dff01dc --- /dev/null +++ b/game/src/main/java/cz/jzitnik/client/socket/events/MovePlayerRoomResponseHandler.java @@ -0,0 +1,29 @@ +package cz.jzitnik.client.socket.events; + +import cz.jzitnik.client.annotations.SocketEventHandler; +import cz.jzitnik.client.annotations.injectors.InjectDependency; +import cz.jzitnik.client.annotations.injectors.InjectState; +import cz.jzitnik.client.events.FullRoomDraw; +import cz.jzitnik.client.game.GameState; +import cz.jzitnik.client.game.OtherPlayer; +import cz.jzitnik.client.socket.AbstractSocketEventHandler; +import cz.jzitnik.client.utils.events.EventManager; +import cz.jzitnik.common.socket.messages.room.MovePlayerRoomResponse; + +@SocketEventHandler(MovePlayerRoomResponse.class) +public class MovePlayerRoomResponseHandler extends AbstractSocketEventHandler { + @InjectDependency + private EventManager eventManager; + + @InjectState + private GameState gameState; + + @Override + public void handle(MovePlayerRoomResponse event) { + for (OtherPlayer player : gameState.getAllOtherPlayers()) { + player.setVisible(event.players().contains(player.getId())); + } + + eventManager.emitEvent(new FullRoomDraw()); + } +} diff --git a/game/src/main/java/cz/jzitnik/client/socket/events/PlayerArrivalChangeHandler.java b/game/src/main/java/cz/jzitnik/client/socket/events/PlayerArrivalChangeHandler.java index 0f2ada6..9c2fe33 100644 --- a/game/src/main/java/cz/jzitnik/client/socket/events/PlayerArrivalChangeHandler.java +++ b/game/src/main/java/cz/jzitnik/client/socket/events/PlayerArrivalChangeHandler.java @@ -1,24 +1,86 @@ package cz.jzitnik.client.socket.events; +import com.googlecode.lanterna.TerminalPosition; import cz.jzitnik.client.annotations.SocketEventHandler; +import cz.jzitnik.client.annotations.injectors.InjectConfig; +import cz.jzitnik.client.annotations.injectors.InjectDependency; import cz.jzitnik.client.annotations.injectors.InjectState; +import cz.jzitnik.client.config.Debugging; +import cz.jzitnik.client.events.MouseMoveEvent; +import cz.jzitnik.client.events.RerenderScreen; +import cz.jzitnik.client.game.GameRoom; import cz.jzitnik.client.game.GameState; import cz.jzitnik.client.game.OtherPlayer; +import cz.jzitnik.client.game.ResourceManager; import cz.jzitnik.client.socket.AbstractSocketEventHandler; +import cz.jzitnik.client.states.ScreenBuffer; +import cz.jzitnik.client.states.TerminalState; +import cz.jzitnik.client.ui.Stats; +import cz.jzitnik.client.utils.RerenderUtils; +import cz.jzitnik.client.utils.events.Event; +import cz.jzitnik.client.utils.events.EventManager; import cz.jzitnik.common.socket.messages.player.PlayerArrivalChange; +import lombok.extern.slf4j.Slf4j; +import java.awt.image.BufferedImage; + +@Slf4j @SocketEventHandler(PlayerArrivalChange.class) public class PlayerArrivalChangeHandler extends AbstractSocketEventHandler { @InjectState private GameState gameState; + @InjectDependency + private ResourceManager resourceManager; + + @InjectDependency + private EventManager eventManager; + + @InjectState + private TerminalState terminalState; + + @InjectState + private ScreenBuffer screenBuffer; + + @InjectConfig + private Debugging debugging; + @Override public void handle(PlayerArrivalChange event) { - var allPlayers = gameState.getAllOtherPlayers(); - for (OtherPlayer player : allPlayers) { - if (player.getId() == event.id()) { - player.setVisible(event.arrived()); - } - } + log.debug("Player appear change: {}", event.id()); + OtherPlayer otherPlayer = gameState.getAllOtherPlayers().stream().filter(otherPlayer1 -> otherPlayer1.getId() == event.id()).findFirst().get(); + otherPlayer.setVisible(event.arrived()); + otherPlayer.getPlayerCords().updateCords(event.playerCords()); + + GameRoom currentRoom = gameState.getCurrentRoom(); + BufferedImage playerTexture = otherPlayer.getTexture(resourceManager); + BufferedImage room = resourceManager.getResource(currentRoom.getTexture()); + + int forStartX = event.playerCords().getX(); + int forStartY = event.playerCords().getY(); + int forEndX = forStartX + playerTexture.getWidth(); + int forEndY = forStartY + playerTexture.getHeight(); + + var start = RerenderUtils.getStart(room, terminalState.getTerminalScreen().getTerminalSize()); + int startX = start.getX(); + int startY = start.getY(); + + RerenderUtils.rerenderPart(forStartX, forEndX, forStartY, forEndY, startX, startY, currentRoom, room, gameState.getPlayer(), screenBuffer, resourceManager, debugging, gameState.getOtherPlayers()); + + eventManager.emitEvent(new Event[]{ + new MouseMoveEvent(null), + new RerenderScreen( + new RerenderScreen.ScreenPart[]{ + new RerenderScreen.ScreenPart( + new TerminalPosition(forStartX + startX, forStartY + startY), + new TerminalPosition(forEndX + 1 + startX, forEndY + startY) + ), + new RerenderScreen.ScreenPart( + new TerminalPosition(Stats.OFFSET_X, Stats.OFFSET_X), + new TerminalPosition(Stats.OFFSET_X + Stats.WIDTH, Stats.OFFSET_Y + Stats.HEIGHT) + ) + } + ) + }); } } diff --git a/server/src/main/java/cz/jzitnik/server/events/handlers/ConnectToAGameHandler.java b/server/src/main/java/cz/jzitnik/server/events/handlers/ConnectToAGameHandler.java index ec47661..d72d311 100644 --- a/server/src/main/java/cz/jzitnik/server/events/handlers/ConnectToAGameHandler.java +++ b/server/src/main/java/cz/jzitnik/server/events/handlers/ConnectToAGameHandler.java @@ -49,8 +49,8 @@ public class ConnectToAGameHandler extends AbstractEventHandler cl.getSession().sendMessage(new PlayerJoined(player)); if (cl.getPlayer().getCurrentRoom().equals(defaultRoomId)) { - cl.getSession().sendMessage(new PlayerArrivalChange(client.getPlayer().getId(), true)); - client.getSession().sendMessage(new PlayerArrivalChange(cl.getPlayer().getId(), true)); + cl.getSession().sendMessage(new PlayerArrivalChange(client.getPlayer().getId(), player.getPlayerCords(), true, true)); + client.getSession().sendMessage(new PlayerArrivalChange(cl.getPlayer().getId(), cl.getPlayer().getCords(), true, false)); } } diff --git a/server/src/main/java/cz/jzitnik/server/events/handlers/MovePlayerRoomHandler.java b/server/src/main/java/cz/jzitnik/server/events/handlers/MovePlayerRoomHandler.java new file mode 100644 index 0000000..604854e --- /dev/null +++ b/server/src/main/java/cz/jzitnik/server/events/handlers/MovePlayerRoomHandler.java @@ -0,0 +1,39 @@ +package cz.jzitnik.server.events.handlers; + +import cz.jzitnik.common.socket.messages.player.PlayerArrivalChange; +import cz.jzitnik.common.socket.messages.room.MovePlayerRoom; +import cz.jzitnik.common.socket.messages.room.MovePlayerRoomResponse; +import cz.jzitnik.server.annotations.EventHandler; +import cz.jzitnik.server.context.GlobalContext; +import cz.jzitnik.server.events.AbstractEventHandler; +import cz.jzitnik.server.game.Client; +import lombok.extern.slf4j.Slf4j; + +import java.util.stream.Collectors; + +@Slf4j +@EventHandler(MovePlayerRoom.class) +public class MovePlayerRoomHandler extends AbstractEventHandler { + public MovePlayerRoomHandler(GlobalContext globalContext) { + super(globalContext); + } + + @Override + public void handle(MovePlayerRoom event, Client client) { + String oldRoomId = client.getPlayer().getCurrentRoom(); + + client.getSession().sendMessage(new MovePlayerRoomResponse(client.getGame().getPlayers().stream().filter(player -> player.getPlayer().getCurrentRoom().equals(event.newRoomId())).map(client1 -> client1.getPlayer().getId()).collect(Collectors.toSet()))); + client.getPlayer().setCurrentRoom(event.newRoomId()); + + for (Client player : client.getGame().getPlayers()) { + if (player.getPlayer().getId() != client.getPlayer().getId()) { + if (player.getPlayer().getCurrentRoom().equals(oldRoomId)) { + log.debug("{}", event.oldCords()); + player.getSession().sendMessage(new PlayerArrivalChange(client.getPlayer().getId(), event.oldCords(), false, true)); + } else if (player.getPlayer().getCurrentRoom().equals(event.newRoomId())) { + player.getSession().sendMessage(new PlayerArrivalChange(client.getPlayer().getId(), event.newCords(), true, true)); + } + } + } + } +}