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;
private LimitedMap<String, Boolean> playerList;
private boolean serverCrashed;
public RMIServer(GameController controller, int nPort,
BlockingQueue<NetworkEvent> actionQueue,
@@ -71,6 +72,28 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
if (preferredInt < 2 || preferredInt > 5) return false;
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()) {
model = new Game(preferredInt);
controller.setModel(model);
@@ -94,6 +117,7 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
actionQueue.add(new ReconnectPlayer(username));
return true;
}
}
return false;
}
}
@@ -263,7 +287,8 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
* Starts the RMI server.
* @return true if the server starts successfully, false otherwise
*/
public boolean start() {
public boolean start(boolean serverCrashed) {
this.serverCrashed = serverCrashed;
try {
System.setProperty("java.rmi.server.hostname", host);
registry = LocateRegistry.createRegistry(nPort);
@@ -35,6 +35,7 @@ public class TCPServer {
LimitedMap<String, Boolean> playerList;
List<ClientHandler> clientHandlers;
boolean serverCrashed;
// Mappa temporanea: username → ClientHandler
// Serve per associare il socket heartbeat al giusto ClientHandler
private final Map<String, ClientHandler> pendingHeartbeat = new ConcurrentHashMap<>();
@@ -50,7 +51,8 @@ public class TCPServer {
this.clientHandlers = new ArrayList<>();
}
public void start() {
public void start(boolean serverCrashed) {
this.serverCrashed = serverCrashed;
try {
socketTCP = new ServerSocket(port);
heartbeatSocketTCP = new ServerSocket(heartbeatPort);
@@ -90,23 +92,55 @@ public class TCPServer {
}
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(controller.getModel() == null){
Game model = new Game(eventAddPlayer.getProposedNPlayer());
controller.setModel(model);
playerList.setLimit(eventAddPlayer.getProposedNPlayer());
}
else
{
for(Player p:controller.getModel().getPlayers()) {
playerList.put(p.getUserName(),false);
}
}
}
String username = eventAddPlayer.getUsername();
if (controller.addPlayer(username)) {
// nuovo giocatore
playerList.put(username, true);
@@ -122,8 +156,6 @@ public class TCPServer {
clientHandlers.add(handler);
connectedPlayers++;
// metti in attesa del socket heartbeat
}
else if(playerList.containsKey(username) && !playerList.get(username)){
// riconnessione
@@ -150,6 +182,8 @@ public class TCPServer {
}
}
}
}
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.Model.Game;
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.NetworkEvents.DisconnectedPlayer;
import it.polimi.ingsw.gc14.Network.RMI.Server.RMIServer;
@@ -126,7 +127,7 @@ public class ServerLauncher {
BlockingQueue<NetworkEvent> actionQueue = new LinkedBlockingQueue<>();
GameController gameController = new GameController();
String IP;
boolean serverCrashed;
try {
IP=chooseNetworkInterface(new Scanner(System.in));
} catch (Exception e) {
@@ -136,7 +137,12 @@ public class ServerLauncher {
RMIServer serverRMI = new RMIServer(gameController, 1099, actionQueue, playerList,IP);
TCPServer serverTCP = new TCPServer(gameController, 8080, 8081,actionQueue, playerList);
ServerLauncher launcher = new ServerLauncher(actionQueue, gameController, serverRMI, serverTCP);
if(gameController.getModel() != null){
playerList.setLimit(gameController.getModel().getNPlayers());
serverCrashed = true;
} else {
serverCrashed = false;
}
playerList.setAction(()->{
new Thread(()->{
try {
@@ -149,8 +155,8 @@ public class ServerLauncher {
}).start();
});
serverRMI.start();
new Thread(()->{serverTCP.start();}).start();
serverRMI.start(serverCrashed);
new Thread(()->{serverTCP.start(serverCrashed);}).start();
}