Compare commits

..

2 Commits

Author SHA1 Message Date
cdd002ea20 feat: Synchronize game items
kinda
2026-02-03 21:40:13 +01:00
faadc92dbc feat: Player disconnect handler 2026-02-03 20:52:36 +01:00
17 changed files with 178 additions and 27 deletions

View File

@@ -0,0 +1,9 @@
package cz.jzitnik.common.socket.messages.items;
import cz.jzitnik.common.socket.SocketMessage;
public record ItemTookFromChest(
String roomId, // For faster lookup i guess
int id
) implements SocketMessage {
}

View File

@@ -3,6 +3,6 @@ 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, RoomCords playerCords, boolean arrived,
boolean rerender) implements SocketMessage {
public record PlayerArrivalChange(int id, RoomCords playerCords, PlayerRotation playerRotation,
boolean arrived, boolean rerender) implements SocketMessage {
}

View File

@@ -0,0 +1,6 @@
package cz.jzitnik.common.socket.messages.player;
import cz.jzitnik.common.socket.SocketMessage;
public record PlayerDisconnected(int playerId) implements SocketMessage {
}

View File

@@ -20,6 +20,10 @@ public class GameState {
@Setter
private GameRoom currentRoom;
@Getter
@Setter
private List<GameRoom> allRooms;
@Getter
@Setter
private Player player;

View File

@@ -14,14 +14,17 @@ public class GameItem implements Renderable {
@JsonIgnore
private final BufferedImage texture;
private final String name;
private final int id;
@JsonCreator
public GameItem(
@JsonProperty("id") int id,
@JsonProperty("name") String name,
@JsonProperty("type") ItemType<?> type,
@JsonProperty("texture") ResourceManager.Resource resource,
@JacksonInject ResourceManager resourceManager
) {
this.id = id;
this.name = name;
this.type = type;
this.texture = resourceManager.getResource(resource);

View File

@@ -10,10 +10,7 @@ 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.InventoryRerender;
import cz.jzitnik.client.events.MouseAction;
import cz.jzitnik.client.events.RerenderPart;
import cz.jzitnik.client.events.RerenderScreen;
import cz.jzitnik.client.events.*;
import cz.jzitnik.client.game.GameRoom;
import cz.jzitnik.client.game.GameState;
import cz.jzitnik.client.game.Player;
@@ -30,9 +27,12 @@ import cz.jzitnik.client.ui.pixels.Pixel;
import cz.jzitnik.client.utils.RerenderUtils;
import cz.jzitnik.client.utils.UIRoomClickHandlerRepository;
import cz.jzitnik.client.utils.events.EventManager;
import cz.jzitnik.common.socket.messages.items.ItemTookFromChest;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.awt.image.BufferedImage;
import java.net.Socket;
import java.util.HashSet;
import java.util.List;
@@ -40,8 +40,11 @@ import java.util.List;
public final class Chest extends GameObject implements UIClickHandler {
private static final int RENDER_PADDING = 1;
@Getter
private final List<GameItem> items;
private boolean rendered;
private int listenerHashCode;
private int actualDisplayStartX;
@@ -164,6 +167,7 @@ public final class Chest extends GameObject implements UIClickHandler {
guiStart.getRow() - start.getY(),
guiEnd.getRow() - start.getY()
));
rendered = true;
}
private void clearPreviousUI(
@@ -257,15 +261,23 @@ public final class Chest extends GameObject implements UIClickHandler {
if (!added) {
return true;
}
eventManager.emitEvent(new InventoryRerender());
eventManager.emitEvent(new SendSocketMessageEvent(new ItemTookFromChest(gameState.getCurrentRoom().getId(), item.getId())));
return true;
}
public void handleItemRemoval(GameItem item) {
items.remove(item);
if (!rendered) {
return;
}
eventManager.emitEvent(new InventoryRerender());
if (items.isEmpty()) {
uiRoomClickHandlerRepository.removeHandlerForCurrentRoom(listenerHashCode);
}
render(true);
return true;
}
}

View File

@@ -47,5 +47,6 @@ public class GameSetup {
);
gameState.setCurrentRoom(rooms.getFirst());
gameState.setAllRooms(rooms);
}
}

View File

@@ -3,10 +3,11 @@ 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.events.TerminalResizeEvent;
import cz.jzitnik.client.game.GameState;
import cz.jzitnik.client.game.Player;
import cz.jzitnik.client.socket.AbstractSocketEventHandler;
import cz.jzitnik.client.states.TerminalState;
import cz.jzitnik.client.utils.events.EventManager;
import cz.jzitnik.common.socket.messages.game.creation.CreateGameResponse;
import lombok.extern.slf4j.Slf4j;
@@ -16,6 +17,8 @@ import lombok.extern.slf4j.Slf4j;
public class CreateGameHandler extends AbstractSocketEventHandler<CreateGameResponse> {
@InjectState
private GameState gameState;
@InjectState
private TerminalState terminalState;
@InjectDependency
private EventManager eventManager;
@@ -24,6 +27,6 @@ public class CreateGameHandler extends AbstractSocketEventHandler<CreateGameResp
log.debug("Game code: {}", event.getGamePassword());
gameState.setPlayer(new Player(event.getOwnerPlayer()));
gameState.setScreen(null);
eventManager.emitEvent(new FullRoomDraw());
eventManager.emitEvent(new TerminalResizeEvent(terminalState.getTerminalScreen().getTerminalSize()));
}
}

View File

@@ -0,0 +1,43 @@
package cz.jzitnik.client.socket.events;
import cz.jzitnik.client.annotations.SocketEventHandler;
import cz.jzitnik.client.annotations.injectors.InjectState;
import cz.jzitnik.client.game.GameRoom;
import cz.jzitnik.client.game.GameState;
import cz.jzitnik.client.game.items.GameItem;
import cz.jzitnik.client.game.objects.Chest;
import cz.jzitnik.client.game.objects.GameObject;
import cz.jzitnik.client.socket.AbstractSocketEventHandler;
import cz.jzitnik.common.socket.messages.items.ItemTookFromChest;
@SocketEventHandler(ItemTookFromChest.class)
public class ItemTookFromChestHandler extends AbstractSocketEventHandler<ItemTookFromChest> {
@InjectState
private GameState gameState;
@Override
public void handle(ItemTookFromChest event) {
for (GameRoom room : gameState.getAllRooms()) {
if (!room.getId().equals(event.roomId())) {
continue;
}
for (GameObject object : room.getObjects()) {
if (object instanceof Chest chest) {
var items = chest.getItems();
for (GameItem item : items) {
if (item.getId() != event.id()) {
continue;
}
items.remove(item);
chest.handleItemRemoval(item);
return;
}
}
}
}
}
}

View File

@@ -51,6 +51,7 @@ public class PlayerArrivalChangeHandler extends AbstractSocketEventHandler<Playe
OtherPlayer otherPlayer = gameState.getAllOtherPlayers().stream().filter(otherPlayer1 -> otherPlayer1.getId() == event.id()).findFirst().get();
otherPlayer.setVisible(event.arrived());
otherPlayer.getPlayerCords().updateCords(event.playerCords());
otherPlayer.setPlayerRotation(event.playerRotation());
GameRoom currentRoom = gameState.getCurrentRoom();
BufferedImage playerTexture = otherPlayer.getTexture(resourceManager);

View File

@@ -0,0 +1,18 @@
package cz.jzitnik.client.socket.events;
import cz.jzitnik.client.annotations.SocketEventHandler;
import cz.jzitnik.client.annotations.injectors.InjectState;
import cz.jzitnik.client.game.GameState;
import cz.jzitnik.client.socket.AbstractSocketEventHandler;
import cz.jzitnik.common.socket.messages.player.PlayerDisconnected;
@SocketEventHandler(PlayerDisconnected.class)
public class PlayerDisconnectedHandler extends AbstractSocketEventHandler<PlayerDisconnected> {
@InjectState
private GameState gameState;
@Override
public void handle(PlayerDisconnected event) {
gameState.getAllOtherPlayers().removeIf(player -> player.getId() == event.playerId());
}
}

View File

@@ -41,12 +41,14 @@
x: 100
y: 45
items:
- name: "Wooden sword"
- id: 1
name: "Wooden sword"
type:
name: "weapon_sword"
dealDamage: 1
texture: "WOODEN_SWORD"
- name: "Apple"
- id: 2
name: "Apple"
type:
name: "food"
addHealth: 1
@@ -78,12 +80,14 @@
x: 100
y: 45
items:
- name: "Wooden sword"
- id: 3
name: "Wooden sword"
type:
name: "weapon_sword"
dealDamage: 1
texture: "WOODEN_SWORD"
- name: "Apple"
- id: 4
name: "Apple"
type:
name: "food"
addHealth: 1
@@ -124,7 +128,8 @@
y: 78
health: 10
itemsDrops:
- name: "Apple"
- id: 5
name: "Apple"
type:
name: "food"
addHealth: 1
@@ -159,7 +164,8 @@
y: 78
health: 10
itemsDrops:
- name: "Apple"
- id: 6
name: "Apple"
type:
name: "food"
addHealth: 1
@@ -189,12 +195,14 @@
x: 100
y: 45
items:
- name: "Wooden sword"
- id: 7
name: "Wooden sword"
type:
name: "weapon_sword"
dealDamage: 1
texture: "WOODEN_SWORD"
- name: "Apple"
- id: 8
name: "Apple"
type:
name: "food"
addHealth: 1

View File

@@ -5,17 +5,16 @@ import cz.jzitnik.common.socket.messages.game.connection.ConnectToAGame;
import cz.jzitnik.common.socket.messages.game.connection.ConnectToAGameResponse;
import cz.jzitnik.common.socket.messages.player.PlayerArrivalChange;
import cz.jzitnik.common.socket.messages.player.PlayerJoined;
import cz.jzitnik.common.socket.messages.player.PlayerRotation;
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 cz.jzitnik.server.game.Player;
import lombok.extern.slf4j.Slf4j;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.ObjectReader;
import tools.jackson.dataformat.yaml.YAMLFactory;
@Slf4j
@EventHandler(ConnectToAGame.class)
public class ConnectToAGameHandler extends AbstractEventHandler<ConnectToAGame> {
public ConnectToAGameHandler(GlobalContext globalContext) {
@@ -24,7 +23,6 @@ public class ConnectToAGameHandler extends AbstractEventHandler<ConnectToAGame>
@Override
public void handle(ConnectToAGame event, Client client) {
log.debug("Pepa");
var gameOptional = globalContext.getGame(event.gamePass().toUpperCase());
if (gameOptional.isEmpty()) {
@@ -49,8 +47,8 @@ public class ConnectToAGameHandler extends AbstractEventHandler<ConnectToAGame>
cl.getSession().sendMessage(new PlayerJoined(player));
if (cl.getPlayer().getCurrentRoom().equals(defaultRoomId)) {
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));
cl.getSession().sendMessage(new PlayerArrivalChange(client.getPlayer().getId(), player.getPlayerCords(), PlayerRotation.FRONT, true, true));
client.getSession().sendMessage(new PlayerArrivalChange(cl.getPlayer().getId(), cl.getPlayer().getCords(), PlayerRotation.FRONT, true, false));
}
}

View File

@@ -0,0 +1,23 @@
package cz.jzitnik.server.events.handlers;
import cz.jzitnik.common.socket.messages.items.ItemTookFromChest;
import cz.jzitnik.server.annotations.EventHandler;
import cz.jzitnik.server.context.GlobalContext;
import cz.jzitnik.server.events.AbstractEventHandler;
import cz.jzitnik.server.game.Client;
@EventHandler(ItemTookFromChest.class)
public class ItemTookFromChestHandler extends AbstractEventHandler<ItemTookFromChest> {
public ItemTookFromChestHandler(GlobalContext globalContext) {
super(globalContext);
}
@Override
public void handle(ItemTookFromChest event, Client client) {
client.getGame().getItemModifiers().add(event);
for (Client client1 : client.getGame().getPlayers()) {
client1.getSession().sendMessage(event);
}
}
}

View File

@@ -40,9 +40,9 @@ public class MovePlayerRoomHandler extends AbstractEventHandler<MovePlayerRoom>
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));
player.getSession().sendMessage(new PlayerArrivalChange(client.getPlayer().getId(), event.oldCords(), client.getPlayer().getPlayerRotation(), false, true));
} else if (player.getPlayer().getCurrentRoom().equals(event.newRoomId())) {
player.getSession().sendMessage(new PlayerArrivalChange(client.getPlayer().getId(), event.newCords(), true, true));
player.getSession().sendMessage(new PlayerArrivalChange(client.getPlayer().getId(), event.newCords(), client.getPlayer().getPlayerRotation(), true, true));
}
}
}

View File

@@ -1,8 +1,10 @@
package cz.jzitnik.server.game;
import cz.jzitnik.common.socket.messages.items.ItemTookFromChest;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
@Getter
@@ -10,4 +12,5 @@ import java.util.List;
public class Game {
private String password;
private List<Client> players;
private final List<ItemTookFromChest> itemModifiers = new ArrayList<>();
}

View File

@@ -1,6 +1,8 @@
package cz.jzitnik.server.socket;
import cz.jzitnik.common.socket.SocketMessage;
import cz.jzitnik.common.socket.messages.player.PlayerArrivalChange;
import cz.jzitnik.common.socket.messages.player.PlayerDisconnected;
import cz.jzitnik.server.game.Client;
import cz.jzitnik.server.context.GlobalContext;
import jakarta.websocket.*;
@@ -37,7 +39,24 @@ public class WebSocket {
@OnClose
public void onClose(Session session, CloseReason reason) {
System.out.println("Connection closed: " + reason);
Client client = globalContext.getSessions().get(session);
client.getGame().getPlayers().remove(client);
for (Client otherClient : client.getGame().getPlayers()) {
if (otherClient.getPlayer().getCurrentRoom().equals(client.getPlayer().getCurrentRoom())) {
otherClient.getSession().sendMessage(new PlayerArrivalChange(
client.getPlayer().getId(),
client.getPlayer().getCords(),
client.getPlayer().getPlayerRotation(),
false,
true
));
}
otherClient.getSession().sendMessage(new PlayerDisconnected(client.getPlayer().getId()));
}
log.debug("Connection closed: {}", reason);
}
@OnError