Fix: Server Persistence

This commit is contained in:
rubenpirreram
2026-05-10 20:09:19 +02:00
parent 6491eb3a85
commit 8106adb0d0
3 changed files with 143 additions and 78 deletions
@@ -42,6 +42,7 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
BlockingQueue<NetworkEvent> actionQueue; BlockingQueue<NetworkEvent> actionQueue;
private LimitedMap<String, Boolean> playerList; private LimitedMap<String, Boolean> playerList;
private boolean serverCrashed;
public RMIServer(GameController controller, int nPort, public RMIServer(GameController controller, int nPort,
BlockingQueue<NetworkEvent> actionQueue, BlockingQueue<NetworkEvent> actionQueue,
@@ -71,6 +72,28 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
if (preferredInt < 2 || preferredInt > 5) return false; if (preferredInt < 2 || preferredInt > 5) return false;
synchronized (controller) { synchronized (controller) {
if(serverCrashed)
{
if(controller.getModel().getPlayers().stream().anyMatch(p -> p.getUserName().equals(username))&& !playerList.containsKey(username)) {
clients.put(username, callback);
playerList.put(username, true);
startWatchdog(username);
System.out.println("(After crash)Reconnected player: " + username);
return true;
}
if (playerList.containsKey(username) && !playerList.get(username)) {
playerList.put(username, true);
clients.put(username, callback);
System.out.println("Reconnected player: " + username);
startWatchdog(username);
callback.onGameInit(model);
System.out.println("Model sent: " + username);
actionQueue.add(new ReconnectPlayer(username));
return true;
}
}
else
{
if (playerList.isEmpty()) { if (playerList.isEmpty()) {
model = new Game(preferredInt); model = new Game(preferredInt);
controller.setModel(model); controller.setModel(model);
@@ -94,6 +117,7 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
actionQueue.add(new ReconnectPlayer(username)); actionQueue.add(new ReconnectPlayer(username));
return true; return true;
} }
}
return false; return false;
} }
} }
@@ -263,7 +287,8 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
* Starts the RMI server. * Starts the RMI server.
* @return true if the server starts successfully, false otherwise * @return true if the server starts successfully, false otherwise
*/ */
public boolean start() { public boolean start(boolean serverCrashed) {
this.serverCrashed = serverCrashed;
try { try {
System.setProperty("java.rmi.server.hostname", host); System.setProperty("java.rmi.server.hostname", host);
registry = LocateRegistry.createRegistry(nPort); registry = LocateRegistry.createRegistry(nPort);
@@ -35,6 +35,7 @@ public class TCPServer {
LimitedMap<String, Boolean> playerList; LimitedMap<String, Boolean> playerList;
List<ClientHandler> clientHandlers; List<ClientHandler> clientHandlers;
boolean serverCrashed;
// Mappa temporanea: username → ClientHandler // Mappa temporanea: username → ClientHandler
// Serve per associare il socket heartbeat al giusto ClientHandler // Serve per associare il socket heartbeat al giusto ClientHandler
private final Map<String, ClientHandler> pendingHeartbeat = new ConcurrentHashMap<>(); private final Map<String, ClientHandler> pendingHeartbeat = new ConcurrentHashMap<>();
@@ -50,7 +51,8 @@ public class TCPServer {
this.clientHandlers = new ArrayList<>(); this.clientHandlers = new ArrayList<>();
} }
public void start() { public void start(boolean serverCrashed) {
this.serverCrashed = serverCrashed;
try { try {
socketTCP = new ServerSocket(port); socketTCP = new ServerSocket(port);
heartbeatSocketTCP = new ServerSocket(heartbeatPort); heartbeatSocketTCP = new ServerSocket(heartbeatPort);
@@ -90,23 +92,55 @@ public class TCPServer {
} }
synchronized (controller) { synchronized (controller) {
String username = eventAddPlayer.getUsername();
if(serverCrashed){
if(controller.getModel().getPlayers().stream().anyMatch(p -> p.getUserName().equals(username))&& !playerList.containsKey(username)){
playerList.put(username, true);
System.out.println("(After crash)Reconnected player: " + username);
ClientHandler handler = new ClientHandler(
username, clientSocket, clientSend, clientReceive,
clientHandlers,playerList, actionQueue
);
clientSocket.getOutputStream().write(1);
pendingHeartbeat.put(username, handler);
Thread thread = new Thread(handler);
thread.start();
clientHandlers.add(handler);
connectedPlayers++;
}
else if(playerList.containsKey(username) && !playerList.get(username)){
// riconnessione
playerList.put(username, true);
System.out.println("Reconnected player: " + username);
ClientHandler handler = new ClientHandler(
username, clientSocket, clientSend, clientReceive,
clientHandlers, playerList, actionQueue
);
clientSocket.getOutputStream().write(1);
pendingHeartbeat.put(username, handler);
handler.notifyModel(controller.getModel());
Thread thread = new Thread(handler);
thread.start();
clientHandlers.add(handler);
connectedPlayers++;
actionQueue.add(new ReconnectPlayer(username));
}
else
{
clientSocket.getOutputStream().write(-1);
clientSocket.close();
System.out.println("Player could not be added. Connection terminated.");
}
}
else
{
if (playerList.isEmpty()) { if (playerList.isEmpty()) {
if(controller.getModel() == null){
Game model = new Game(eventAddPlayer.getProposedNPlayer()); Game model = new Game(eventAddPlayer.getProposedNPlayer());
controller.setModel(model); controller.setModel(model);
playerList.setLimit(eventAddPlayer.getProposedNPlayer()); playerList.setLimit(eventAddPlayer.getProposedNPlayer());
} }
else
{
for(Player p:controller.getModel().getPlayers()) {
playerList.put(p.getUserName(),false);
}
}
}
String username = eventAddPlayer.getUsername();
if (controller.addPlayer(username)) { if (controller.addPlayer(username)) {
// nuovo giocatore // nuovo giocatore
playerList.put(username, true); playerList.put(username, true);
@@ -122,8 +156,6 @@ public class TCPServer {
clientHandlers.add(handler); clientHandlers.add(handler);
connectedPlayers++; connectedPlayers++;
// metti in attesa del socket heartbeat // metti in attesa del socket heartbeat
} }
else if(playerList.containsKey(username) && !playerList.get(username)){ else if(playerList.containsKey(username) && !playerList.get(username)){
// riconnessione // riconnessione
@@ -150,6 +182,8 @@ public class TCPServer {
} }
} }
}
} }
catch(IOException | ClassNotFoundException e){ catch(IOException | ClassNotFoundException e){
@@ -4,6 +4,7 @@ package it.polimi.ingsw.gc14;
import it.polimi.ingsw.gc14.Controller.GameController; import it.polimi.ingsw.gc14.Controller.GameController;
import it.polimi.ingsw.gc14.Model.Game; import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.Model.GamePackage.GameStages; import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
import it.polimi.ingsw.gc14.Model.Player;
import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.NetworkEvents.DisconnectedPlayer; import it.polimi.ingsw.gc14.Network.NetworkEvents.DisconnectedPlayer;
import it.polimi.ingsw.gc14.Network.RMI.Server.RMIServer; import it.polimi.ingsw.gc14.Network.RMI.Server.RMIServer;
@@ -126,7 +127,7 @@ public class ServerLauncher {
BlockingQueue<NetworkEvent> actionQueue = new LinkedBlockingQueue<>(); BlockingQueue<NetworkEvent> actionQueue = new LinkedBlockingQueue<>();
GameController gameController = new GameController(); GameController gameController = new GameController();
String IP; String IP;
boolean serverCrashed;
try { try {
IP=chooseNetworkInterface(new Scanner(System.in)); IP=chooseNetworkInterface(new Scanner(System.in));
} catch (Exception e) { } catch (Exception e) {
@@ -136,7 +137,12 @@ public class ServerLauncher {
RMIServer serverRMI = new RMIServer(gameController, 1099, actionQueue, playerList,IP); RMIServer serverRMI = new RMIServer(gameController, 1099, actionQueue, playerList,IP);
TCPServer serverTCP = new TCPServer(gameController, 8080, 8081,actionQueue, playerList); TCPServer serverTCP = new TCPServer(gameController, 8080, 8081,actionQueue, playerList);
ServerLauncher launcher = new ServerLauncher(actionQueue, gameController, serverRMI, serverTCP); ServerLauncher launcher = new ServerLauncher(actionQueue, gameController, serverRMI, serverTCP);
if(gameController.getModel() != null){
playerList.setLimit(gameController.getModel().getNPlayers());
serverCrashed = true;
} else {
serverCrashed = false;
}
playerList.setAction(()->{ playerList.setAction(()->{
new Thread(()->{ new Thread(()->{
try { try {
@@ -149,8 +155,8 @@ public class ServerLauncher {
}).start(); }).start();
}); });
serverRMI.start(); serverRMI.start(serverCrashed);
new Thread(()->{serverTCP.start();}).start(); new Thread(()->{serverTCP.start(serverCrashed);}).start();
} }