feat: Some more multiplayer stuff

Hello miss Meitnerova... If you are not Meitnerova but some random
person stalking my projects go get a life.

Anyways have a great time reading this awful code :)
This commit is contained in:
2026-02-02 18:51:51 +01:00
parent f987b2bed6
commit 92eb93815d
24 changed files with 572 additions and 57 deletions

View File

@@ -2,23 +2,52 @@ package cz.jzitnik.server.context;
import cz.jzitnik.server.game.Client;
import cz.jzitnik.server.events.EventManager;
import cz.jzitnik.server.socket.SocketSession;
import cz.jzitnik.server.game.Game;
import jakarta.websocket.Session;
import lombok.Getter;
import lombok.Setter;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
public class GlobalContext {
@Getter
private final HashMap<Session, Client> sessions = new HashMap<>();
@Getter
private final Set<Game> games = new HashSet<>();
@Getter
@Setter
private EventManager eventManager;
public void registerClient(Session session) {
Client client = new Client(new SocketSession(session));
sessions.put(session, client);
@Getter
private final Properties properties;
public void registerClient(Client client) {
sessions.put(client.getSession().getSession(), client);
}
public GlobalContext() {
Properties props = new Properties();
try (InputStream input = GlobalContext.class
.getClassLoader()
.getResourceAsStream("config.properties")) {
if (input == null) {
throw new RuntimeException("config.properties not found");
}
props.load(input);
this.properties = props;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -1,5 +1,6 @@
package cz.jzitnik.server.events.handlers;
import cz.jzitnik.common.Config;
import cz.jzitnik.common.models.player.PlayerCreation;
import cz.jzitnik.common.socket.messages.game.creation.CreateGame;
import cz.jzitnik.common.socket.messages.game.creation.CreateGameResponse;
@@ -7,11 +8,17 @@ 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.Game;
import cz.jzitnik.server.game.Player;
import cz.jzitnik.server.utils.PasswordGenerator;
import lombok.RequiredArgsConstructor;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.ObjectReader;
import tools.jackson.dataformat.yaml.YAMLFactory;
import java.util.ArrayList;
import java.util.List;
@RequiredArgsConstructor
@EventHandler(CreateGame.class)
public class CreateGameHandler extends AbstractEventHandler<CreateGame> {
@@ -20,13 +27,24 @@ public class CreateGameHandler extends AbstractEventHandler<CreateGame> {
@Override
public void handle(CreateGame event, Client client) {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
String pass = "nevim"; // TODO: Generate
String pass = PasswordGenerator.generatePassword(Config.WORLD_PASSWORD_LENGTH); // TODO: Generate
int id = 0; // Owners id is always 0
ObjectReader playerReader = objectMapper.readerFor(PlayerCreation.class);
PlayerCreation player = playerReader.readValue(getClass().getClassLoader().getResourceAsStream("setup/player.yaml"));
player.setId(id);
client.setPlayer(new Player(id, player.getPlayerCords()));
CreateGameResponse gameResponse = new CreateGameResponse(pass, player);
Game game = new Game(
pass,
new ArrayList<>(List.of(client))
);
client.setGame(game);
client.getPlayer().setCurrentRoom(globalContext.getProperties().getProperty("rooms.default"));
globalContext.getGames().add(game);
client.session().sendMessage(gameResponse);
client.getSession().sendMessage(gameResponse);
}
}

View File

@@ -0,0 +1,26 @@
package cz.jzitnik.server.events.handlers;
import cz.jzitnik.common.socket.messages.player.PlayerMove;
import cz.jzitnik.common.socket.messages.player.PlayerMovedInUrRoom;
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.RequiredArgsConstructor;
@RequiredArgsConstructor
@EventHandler(PlayerMove.class)
public class PlayerMoveHandler extends AbstractEventHandler<PlayerMove> {
private final GlobalContext globalContext;
@Override
public void handle(PlayerMove event, Client client) {
client.getPlayer().getCords().updateCords(event.newCords());
for (Client player : client.getGame().getPlayers()) {
if (player.getPlayer().getCurrentRoom().equals(client.getPlayer().getCurrentRoom()) && player.getPlayer().getId() != client.getPlayer().getId()) {
player.getSession().sendMessage(new PlayerMovedInUrRoom(client.getPlayer().getId(), event.newCords()));
}
}
}
}

View File

@@ -1,5 +1,25 @@
package cz.jzitnik.server.game;
import cz.jzitnik.server.socket.SocketSession;
import lombok.Getter;
import lombok.Setter;
public record Client(SocketSession session) {}
@Getter
public final class Client {
private final SocketSession session;
@Setter
private Player player;
@Setter
private Game game;
public Client(SocketSession session, Player player, Game game) {
this.session = session;
this.player = player;
this.game = game;
}
public Client(SocketSession session, Player player) {
this(session, player, null);
}
}

View File

@@ -1,4 +1,13 @@
package cz.jzitnik.server.game;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
@Getter
@AllArgsConstructor
public class Game {
private String password;
private List<Client> players;
}

View File

@@ -0,0 +1,15 @@
package cz.jzitnik.server.game;
import cz.jzitnik.common.models.coordinates.RoomCords;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
@Getter
@RequiredArgsConstructor
public class Player {
private final int id;
private final RoomCords cords;
@Setter
private String currentRoom;
}

View File

@@ -18,7 +18,8 @@ public class WebSocket {
@OnOpen
public void onOpen(Session session, EndpointConfig config) {
this.globalContext = (GlobalContext) config.getUserProperties().get("globalContext");
globalContext.registerClient(session);
globalContext.registerClient(new Client(new SocketSession(session), null));
log.debug("Client connected: {}", session.getId());
}

View File

@@ -0,0 +1,23 @@
package cz.jzitnik.server.utils;
import java.security.SecureRandom;
public class PasswordGenerator {
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static final SecureRandom RANDOM = new SecureRandom();
public static String generatePassword(int length) {
if (length <= 0) {
throw new IllegalArgumentException("Password length must be greater than 0");
}
StringBuilder password = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int index = RANDOM.nextInt(CHARACTERS.length());
password.append(CHARACTERS.charAt(index));
}
return password.toString();
}
}

View File

@@ -0,0 +1 @@
rooms.default=spawn