Multijugador LAN - vykymoon/rpg-character-creator GitHub Wiki
El modo LAN permite que varios jugadores, cada uno con un personaje creado en el wizard, compartan un mapa y se vean moverse en tiempo real dentro de una red local.
-
Commit de implementación:
827ab59— feat: implementar multijugador LAN con servidor autoritativo (ADR-001) -
Mejoras posteriores:
05081c5(imagen de fondo del mapa y botones en la galería)
El servidor es la única fuente de verdad del estado del juego (posiciones, mapa, jugadores conectados). Los clientes:
- Envían intenciones ("quiero moverme a x,y").
- Dibujan el estado que el servidor les devuelve.
Un cliente nunca modifica su propia posición: solo cambia cuando el servidor confirma.
| Aspecto | Valor |
|---|---|
| Transporte | WebSocket (org.java-websocket:Java-WebSocket:1.5.6) |
| Formato | JSON (Gson 2.11.0) |
| Puerto por defecto | 8887 |
| Mapa | 50×50 celdas, generado de forma determinista en el servidor |
| Punto de aparición | Celda (2, 2)
|
flowchart LR
subgraph Cliente
GA[ui/GameApp<br/>JavaFX] --> GC[adapters/client/GameClient]
CL[ui/CharacterLoader] --> GA
end
subgraph Servidor
GS[adapters/server/GameServer] --> SVC[application/GameSessionService]
SVC --> MR[domain/MovementRules]
MR --> MAP[domain/GameMap]
SVC --> PS[domain/PlayerState]
end
GC <-->|WebSocket + JSON| GS
JSON[(characters.json)] --> CL
Flujo de dependencias: adapters → application → domain. El dominio no conoce WebSocket ni JavaFX.
com.proyecto.rpg
├── domain/
│ ├── GameMap.java Mapa 50x50 con terreno
│ ├── MovementRules.java Valida movimientos
│ ├── PlayerState.java Estado de un jugador (se serializa)
│ └── Position.java (sin uso actual)
├── application/
│ └── GameSessionService.java Fuente de verdad + serialización JSON
├── adapters/server/
│ ├── GameServer.java WebSocketServer
│ ├── ServerMain.java main() del servidor
│ └── client/
│ ├── GameClient.java WebSocketClient con callback
│ └── ClientMain.java Cliente de consola
└── ui/
├── GameApp.java Cliente gráfico JavaFX
├── CharacterLoader.java Lee characters.json tolerantemente
└── GalleryController.java Botones "Iniciar Servidor" / "Multijugador LAN"
Cuadrícula char[][] de width × height. La generación usa new Random(42), así que siempre produce el mismo mapa.
| Carácter | Terreno | ¿Caminable? |
|---|---|---|
. |
Pasto | Sí |
= |
Camino | Sí |
# |
Piedra (borde del mapa) | No |
T |
Árbol (8 % de las celdas interiores) | No |
~ |
Agua | No |
Elementos generados: borde de piedra, árboles aleatorios, dos lagos (en (10,8) de 8×6 y en (32,30) de 10×8), caminos en cruz por el centro y una zona de aparición despejada (celdas 1 a 5 en x e y).
isValidMove(x, y) delega en map.isWalkable(x, y). Hoy solo valida el terreno de destino.
Campos públicos: playerId, x, y, name, race, characterClass, items (lista de strings).
Guarda un ConcurrentHashMap<String, PlayerState> y el GameMap. Los métodos son synchronized.
| Método | Comportamiento |
|---|---|
join(id, name, race, class, items) |
Crea al jugador en (2,2) si no existe y actualiza sus datos de personaje |
move(id, x, y) |
Valida con MovementRules; si es válido actualiza y devuelve true, si no ignora y devuelve false
|
remove(id) |
Elimina al jugador |
stateAsJson() |
{"type":"state","players":{…}} |
mapAsJson() |
{"type":"map","width":50,"height":50,"rows":[…]} |
-
Iniciar Servidor (
onStartServer): ejecutaServerMain.main(new String[]{})en un hilo nuevo para no congelar la UI → puerto 8887. -
Multijugador LAN (
onPlayMultiplayer): cierra la ventana del menú y ejecutanew GameApp().start(new Stage()).