LAN Servidor - vykymoon/rpg-character-creator GitHub Wiki
Paquete com.proyecto.rpg.adapters.server.
int port = args.length > 0 ? Integer.parseInt(args[0]) : 8887;
GameServer server = new GameServer(port);
server.start(); // no bloqueanteImprime Servidor host levantado en ws://localhost:<puerto> y deja el proceso vivo hasta Ctrl+C.
| Forma | Comando / acción |
|---|---|
| Desde la aplicación | Botón Iniciar Servidor en la galería (puerto 8887) |
| Sin interfaz | mvn compile exec:java@server |
| Otro puerto | mvn compile exec:java@server -Dexec.args="9000" |
Extiende org.java_websocket.server.WebSocketServer.
super(new InetSocketAddress(port)); // todas las interfaces de redEscucha en todas las interfaces (no solo localhost), lo que permite que otras máquinas de la LAN se conecten.
| Campo | Uso |
|---|---|
GameSessionService sessionService |
Fuente de verdad del juego |
Map<WebSocket, String> playerIdByConnection |
Asocia cada conexión con su jugador (ConcurrentHashMap) |
Gson gson |
Parseo de los mensajes entrantes |
| Callback | Comportamiento |
|---|---|
onOpen |
Solo registra cliente conectado: <dirección>
|
onMessage |
Parsea el JSON y despacha por type (ver abajo) |
onClose |
Quita la conexión del mapa, llama a sessionService.remove(playerId), hace broadcast y registra jugador desconectado
|
onError |
Imprime el error en consola |
onStart |
Imprime GameServer autoritativo escuchando en puerto <n>
|
JsonObject json = gson.fromJson(message, JsonObject.class);
String type = json.get("type").getAsString();
String playerId = json.get("playerId").getAsString();
switch (type) {
case "join" -> { … }
case "move" -> { … }
default -> System.err.println("tipo de mensaje desconocido: " + type);
}Todo el bloque está dentro de un try/catch (Exception): un mensaje inválido se registra y no tumba el servidor.
join
-
playerIdByConnection.put(conn, playerId). - Lee
name,race,characterClass(con el helperstr, que tolera campos ausentes onull) eitems. -
sessionService.join(...). -
conn.send(sessionService.mapAsJson())— el mapa va solo a este cliente. -
broadcastState().
move
- Lee
xeycomo enteros. -
sessionService.move(playerId, x, y). -
broadcastState().
String json = sessionService.stateAsJson();
for (WebSocket conn : getConnections()) conn.send(json);Envía la foto completa del estado a todas las conexiones abiertas.
-
GameSessionServiceusaConcurrentHashMapy métodossynchronized. - Java-WebSocket atiende las conexiones en hilos propios, por eso el acceso al estado está protegido.
-
mapAsJson()no está sincronizado: el mapa es de solo lectura tras la construcción.
stateDiagram-v2
[*] --> Conectado: onOpen
Conectado --> EnJuego: join (spawn en 2,2)
EnJuego --> EnJuego: move válido
EnJuego --> [*]: onClose (se elimina y se notifica)
Conectado --> [*]: onClose sin join
Ver Limitaciones y Mejoras. Las más relevantes: no valida que el movimiento sea de una sola casilla, confía en el playerId y los datos de personaje que envía el cliente, y no hay forma de detenerlo desde la interfaz.