feat: Multiplayer (#3)
Reviewed-on: https://gitea.local.jzitnik.dev/jzitnik/game/pulls/3 Co-authored-by: jzitnik-dev <email@jzitnik.dev> Co-committed-by: jzitnik-dev <email@jzitnik.dev>
This commit is contained in:
28
server/src/main/java/cz/jzitnik/server/Main.java
Normal file
28
server/src/main/java/cz/jzitnik/server/Main.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package cz.jzitnik.server;
|
||||
|
||||
import cz.jzitnik.server.context.AppContext;
|
||||
import cz.jzitnik.server.context.GlobalContext;
|
||||
import cz.jzitnik.server.events.EventManager;
|
||||
import cz.jzitnik.server.socket.WebSocket;
|
||||
import jakarta.websocket.DeploymentException;
|
||||
import org.glassfish.tyrus.server.Server;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) throws DeploymentException {
|
||||
GlobalContext globalContext = new GlobalContext();
|
||||
AppContext.set(globalContext);
|
||||
|
||||
EventManager eventManager = new EventManager(new Reflections("cz.jzitnik.server"), globalContext);
|
||||
globalContext.setEventManager(eventManager);
|
||||
eventManager.start();
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
Server server = new Server("localhost", 8025, "/", properties, WebSocket.class);
|
||||
|
||||
server.start();
|
||||
new Scanner(System.in).nextLine();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cz.jzitnik.server.annotations;
|
||||
|
||||
import cz.jzitnik.common.socket.SocketMessage;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface EventHandler {
|
||||
Class<? extends SocketMessage> value();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package cz.jzitnik.server.context;
|
||||
|
||||
public class AppContext {
|
||||
private static GlobalContext globalContext;
|
||||
|
||||
public static void set(GlobalContext context) {
|
||||
globalContext = context;
|
||||
}
|
||||
|
||||
public static GlobalContext get() {
|
||||
return globalContext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package cz.jzitnik.server.context;
|
||||
|
||||
public class GameManager {
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package cz.jzitnik.server.context;
|
||||
|
||||
import cz.jzitnik.server.game.Client;
|
||||
import cz.jzitnik.server.events.EventManager;
|
||||
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.*;
|
||||
|
||||
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;
|
||||
|
||||
@Getter
|
||||
private final Properties properties;
|
||||
|
||||
public void registerClient(Client client) {
|
||||
sessions.put(client.getSession().getSession(), client);
|
||||
}
|
||||
|
||||
public Optional<Game> getGame(String pass) {
|
||||
return games.stream().filter(game -> game.getPassword().equals(pass)).findFirst();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cz.jzitnik.server.events;
|
||||
|
||||
import cz.jzitnik.common.socket.SocketMessage;
|
||||
import cz.jzitnik.server.context.GlobalContext;
|
||||
import cz.jzitnik.server.game.Client;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class AbstractEventHandler<T extends SocketMessage> {
|
||||
protected final GlobalContext globalContext;
|
||||
public abstract void handle(T event, Client client);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package cz.jzitnik.server.events;
|
||||
|
||||
import cz.jzitnik.common.socket.SocketMessage;
|
||||
import cz.jzitnik.server.game.Client;
|
||||
import cz.jzitnik.server.annotations.EventHandler;
|
||||
import cz.jzitnik.server.context.GlobalContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
@Slf4j
|
||||
public class EventManager extends Thread {
|
||||
private ExecutorService eventExecutor;
|
||||
private final HashMap<Class<? extends SocketMessage>, AbstractEventHandler<?>> handlers = new HashMap<>();
|
||||
private final BlockingQueue<Registry> eventQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
private record Registry(SocketMessage event, Client client) {}
|
||||
|
||||
public void emitEvent(SocketMessage event, Client client) {
|
||||
eventQueue.add(new Registry(event, client));
|
||||
}
|
||||
|
||||
public EventManager(Reflections reflections, GlobalContext globalContext) {
|
||||
setDaemon(true);
|
||||
|
||||
var classes = reflections.getTypesAnnotatedWith(EventHandler.class);
|
||||
|
||||
for (var clazz : classes) {
|
||||
EventHandler eventHandler = clazz.getAnnotation(EventHandler.class);
|
||||
try {
|
||||
var instance = (AbstractEventHandler<?>) clazz.getDeclaredConstructor(GlobalContext.class).newInstance(globalContext);
|
||||
handlers.put(eventHandler.value(), instance);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||
NoSuchMethodException e) {
|
||||
log.error("Failed to instantiate socket event handler: {}", clazz.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
eventExecutor = Executors.newFixedThreadPool(6);
|
||||
while (true) {
|
||||
try {
|
||||
Registry registry = eventQueue.take();
|
||||
handleEvent(registry.event, registry.client);
|
||||
} catch (InterruptedException e) {
|
||||
eventExecutor.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
//eventExecutor.shutdown();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends SocketMessage> AbstractEventHandler<T> getHandler(Class<T> type) {
|
||||
return (AbstractEventHandler<T>) handlers.get(type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleEvent(SocketMessage event, Client client) {
|
||||
eventExecutor.submit(() -> {
|
||||
try {
|
||||
AbstractEventHandler<SocketMessage> handler = getHandler((Class<SocketMessage>) event.getClass());
|
||||
handler.handle(event, client);
|
||||
} catch (Exception e) {
|
||||
log.error("Error", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package cz.jzitnik.server.events.handlers;
|
||||
|
||||
import cz.jzitnik.common.models.player.PlayerCreation;
|
||||
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 tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectReader;
|
||||
import tools.jackson.dataformat.yaml.YAMLFactory;
|
||||
|
||||
@EventHandler(ConnectToAGame.class)
|
||||
public class ConnectToAGameHandler extends AbstractEventHandler<ConnectToAGame> {
|
||||
public ConnectToAGameHandler(GlobalContext globalContext) {
|
||||
super(globalContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ConnectToAGame event, Client client) {
|
||||
var gameOptional = globalContext.getGame(event.gamePass().toUpperCase());
|
||||
|
||||
if (gameOptional.isEmpty()) {
|
||||
client.getSession().sendMessage(new ConnectToAGameResponse());
|
||||
return;
|
||||
}
|
||||
|
||||
var game = gameOptional.get();
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
|
||||
ObjectReader playerReader = objectMapper.readerFor(PlayerCreation.class);
|
||||
PlayerCreation player = playerReader.readValue(getClass().getClassLoader().getResourceAsStream("setup/player.yaml"));
|
||||
player.setId(game.getPlayers().size());
|
||||
client.setPlayer(new Player(player));
|
||||
client.setGame(game);
|
||||
String defaultRoomId = globalContext.getProperties().getProperty("rooms.default");
|
||||
client.getPlayer().setCurrentRoom(defaultRoomId);
|
||||
|
||||
client.getSession().sendMessage(new ConnectToAGameResponse(player, game.getPlayers().stream().map(client1 -> client1.getPlayer().toPlayerCreation()).toList()));
|
||||
|
||||
for (Client cl : game.getPlayers()) {
|
||||
cl.getSession().sendMessage(new PlayerJoined(player));
|
||||
|
||||
if (cl.getPlayer().getCurrentRoom().equals(defaultRoomId)) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
game.getPlayers().add(client);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
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;
|
||||
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;
|
||||
|
||||
@EventHandler(CreateGame.class)
|
||||
public class CreateGameHandler extends AbstractEventHandler<CreateGame> {
|
||||
public CreateGameHandler(GlobalContext globalContext) {
|
||||
super(globalContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(CreateGame event, Client client) {
|
||||
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
|
||||
String pass = PasswordGenerator.generatePassword(Config.WORLD_PASSWORD_LENGTH);
|
||||
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(player));
|
||||
|
||||
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.getSession().sendMessage(gameResponse);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
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<MovePlayerRoom> {
|
||||
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 ->
|
||||
new MovePlayerRoomResponse.Registry(
|
||||
client1.getPlayer().getId(),
|
||||
client1.getPlayer().getCords(),
|
||||
client1.getPlayer().getPlayerRotation()
|
||||
)
|
||||
).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(), client.getPlayer().getPlayerRotation(), false, true));
|
||||
} else if (player.getPlayer().getCurrentRoom().equals(event.newRoomId())) {
|
||||
player.getSession().sendMessage(new PlayerArrivalChange(client.getPlayer().getId(), event.newCords(), client.getPlayer().getPlayerRotation(), true, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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;
|
||||
|
||||
@EventHandler(PlayerMove.class)
|
||||
public class PlayerMoveHandler extends AbstractEventHandler<PlayerMove> {
|
||||
public PlayerMoveHandler(GlobalContext globalContext) {
|
||||
super(globalContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(PlayerMove event, Client client) {
|
||||
client.getPlayer().getCords().updateCords(event.newCords());
|
||||
client.getPlayer().setPlayerRotation(event.playerRotation());
|
||||
|
||||
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(), event.playerRotation()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
server/src/main/java/cz/jzitnik/server/game/Client.java
Normal file
25
server/src/main/java/cz/jzitnik/server/game/Client.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package cz.jzitnik.server.game;
|
||||
|
||||
import cz.jzitnik.server.socket.SocketSession;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
16
server/src/main/java/cz/jzitnik/server/game/Game.java
Normal file
16
server/src/main/java/cz/jzitnik/server/game/Game.java
Normal file
@@ -0,0 +1,16 @@
|
||||
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
|
||||
@AllArgsConstructor
|
||||
public class Game {
|
||||
private String password;
|
||||
private List<Client> players;
|
||||
private final List<ItemTookFromChest> itemModifiers = new ArrayList<>();
|
||||
}
|
||||
27
server/src/main/java/cz/jzitnik/server/game/Player.java
Normal file
27
server/src/main/java/cz/jzitnik/server/game/Player.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package cz.jzitnik.server.game;
|
||||
|
||||
import cz.jzitnik.common.models.coordinates.RoomCords;
|
||||
import cz.jzitnik.common.models.player.PlayerCreation;
|
||||
import cz.jzitnik.common.socket.messages.player.PlayerRotation;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
public class Player {
|
||||
private final int id;
|
||||
private final RoomCords cords;
|
||||
@Setter
|
||||
private PlayerRotation playerRotation;
|
||||
@Setter
|
||||
private String currentRoom;
|
||||
|
||||
public Player(PlayerCreation creation) {
|
||||
id = creation.getId();
|
||||
cords = creation.getPlayerCords();
|
||||
playerRotation = PlayerRotation.FRONT;
|
||||
}
|
||||
|
||||
public PlayerCreation toPlayerCreation() {
|
||||
return new PlayerCreation(cords, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cz.jzitnik.server.socket;
|
||||
|
||||
import cz.jzitnik.server.context.AppContext;
|
||||
import jakarta.websocket.HandshakeResponse;
|
||||
import jakarta.websocket.server.HandshakeRequest;
|
||||
import jakarta.websocket.server.ServerEndpointConfig;
|
||||
|
||||
public class GlobalContextConfigurator extends ServerEndpointConfig.Configurator {
|
||||
|
||||
@Override
|
||||
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
|
||||
sec.getUserProperties().put("globalContext", AppContext.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cz.jzitnik.server.socket;
|
||||
|
||||
import cz.jzitnik.common.socket.SocketMessage;
|
||||
import jakarta.websocket.Session;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public class SocketSession {
|
||||
private final Session session;
|
||||
|
||||
public void sendMessage(SocketMessage message) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(message);
|
||||
oos.flush();
|
||||
session.getBasicRemote().sendBinary(java.nio.ByteBuffer.wrap(baos.toByteArray()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
server/src/main/java/cz/jzitnik/server/socket/WebSocket.java
Normal file
66
server/src/main/java/cz/jzitnik/server/socket/WebSocket.java
Normal file
@@ -0,0 +1,66 @@
|
||||
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.*;
|
||||
import jakarta.websocket.server.ServerEndpoint;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@Slf4j
|
||||
@ServerEndpoint(value = "/ws", configurator = GlobalContextConfigurator.class)
|
||||
public class WebSocket {
|
||||
|
||||
private GlobalContext globalContext;
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session, EndpointConfig config) {
|
||||
this.globalContext = (GlobalContext) config.getUserProperties().get("globalContext");
|
||||
|
||||
globalContext.registerClient(new Client(new SocketSession(session), null));
|
||||
log.debug("Client connected: {}", session.getId());
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(byte[] bytes, Session session) {
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(bais)) {
|
||||
SocketMessage socketMessage = (SocketMessage) ois.readObject();
|
||||
Client client = globalContext.getSessions().get(session);
|
||||
globalContext.getEventManager().emitEvent(socketMessage, client);
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(Session session, CloseReason 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
|
||||
public void onError(Session session, Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package cz.jzitnik.server.utils;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class PasswordGenerator {
|
||||
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
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();
|
||||
}
|
||||
}
|
||||
1
server/src/main/resources/config.properties
Normal file
1
server/src/main/resources/config.properties
Normal file
@@ -0,0 +1 @@
|
||||
rooms.default=spawn
|
||||
11
server/src/main/resources/setup/player.yaml
Normal file
11
server/src/main/resources/setup/player.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
playerCords:
|
||||
x: 90
|
||||
y: 100
|
||||
|
||||
collider:
|
||||
start:
|
||||
x: 0
|
||||
y: 52
|
||||
end:
|
||||
x: 44
|
||||
y: 78
|
||||
Reference in New Issue
Block a user