Fix: Only one player logic (todo go to end-game)

This commit is contained in:
rubenpirreram
2026-05-11 18:05:53 +02:00
parent ef34f780a3
commit 3a39d889e4
6 changed files with 80 additions and 30 deletions
@@ -14,7 +14,7 @@ public enum EventType {
PICK_OPTIONAL_TRIBE, PICK_OPTIONAL_TRIBE,
PICK_OPTIONAL_BUILD, PICK_OPTIONAL_BUILD,
SKIP_NO_DRAWABLE, SKIP_NO_DRAWABLE,
SKIP_PLAYER_DISCONNECTED, DISCONNECTED_PLAYER,
RECONNECT_PLAYER, RECONNECT_PLAYER,
NO_OPTIONAL_CARD NO_OPTIONAL_CARD
} }
@@ -17,7 +17,7 @@ public class DisconnectedPlayer extends NetworkEvent implements Serializable{
* @param username the name of the player requesting the event * @param username the name of the player requesting the event
*/ */
public DisconnectedPlayer(String username){ public DisconnectedPlayer(String username){
super(username, EventType.SKIP_PLAYER_DISCONNECTED, false); super(username, EventType.DISCONNECTED_PLAYER, false);
} }
/** /**
@@ -17,7 +17,7 @@ public class SkipNoDrawable extends NetworkEvent implements Serializable{
* @param username the name of the player requesting the event * @param username the name of the player requesting the event
*/ */
public SkipNoDrawable(String username){ public SkipNoDrawable(String username){
super(username, EventType.SKIP_PLAYER_DISCONNECTED, false); super(username, EventType.SKIP_NO_DRAWABLE, false);
} }
/** /**
@@ -43,6 +43,9 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
private LimitedMap<String, Boolean> playerList; private LimitedMap<String, Boolean> playerList;
private boolean serverCrashed; private boolean serverCrashed;
public void setServerCrashed(boolean serverCrashed) {
this.serverCrashed = serverCrashed;
}
public RMIServer(GameController controller, int nPort, public RMIServer(GameController controller, int nPort,
BlockingQueue<NetworkEvent> actionQueue, BlockingQueue<NetworkEvent> actionQueue,
@@ -36,6 +36,10 @@ public class TCPServer {
List<ClientHandler> clientHandlers; List<ClientHandler> clientHandlers;
boolean serverCrashed; boolean serverCrashed;
public void setServerCrashed(boolean serverCrashed) {
this.serverCrashed = 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<>();
@@ -5,6 +5,7 @@ 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.Model.Player;
import it.polimi.ingsw.gc14.Network.EventType;
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;
@@ -17,8 +18,7 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.rmi.RemoteException; import java.rmi.RemoteException;
import java.util.*; import java.util.*;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.net.*; import java.net.*;
@@ -64,9 +64,13 @@ public class ServerLauncher {
*/ */
static LimitedMap<String,Boolean> playerList; static LimitedMap<String,Boolean> playerList;
TUI view; static TUI view;
// Campo da aggiungere in ServerLauncher
private final ScheduledExecutorService timerExecutor = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> disconnectionTimer;
/** /**
* Class constructor that initializes the attributes. * Class constructor that initializes the attributes.
* @param actionQueue The queue containing the events * @param actionQueue The queue containing the events
@@ -93,23 +97,57 @@ public class ServerLauncher {
*/ */
public boolean doFirstEvent() throws InterruptedException, RemoteException { public boolean doFirstEvent() throws InterruptedException, RemoteException {
NetworkEvent event = actionQueue.take(); NetworkEvent event = actionQueue.take();
synchronized(gameController){ if(gameController.getModel()!=null && !gameController.getModel().getCurrentState().equals(GameStages.ENDED))
{
event.setIsError(!event.apply(gameController)); if(disconnectionTimer!=null && event.getEventType() != EventType.RECONNECT_PLAYER)
serverRMI.notifyAll(event); {
serverTCP.notifyAll(event); event.setIsError(true);
serverRMI.notifyAll(event);
if(!event.getIsError()){ serverTCP.notifyAll(event);
if(this.gameController.getModel().getCurrentState().getGameStage() == GameStages.ENDED){ return false;
this.deleteSave(); }
} if (event.getEventType() == EventType.RECONNECT_PLAYER && disconnectionTimer != null && !disconnectionTimer.isDone()) {
else if(!this.gameSave() ){ disconnectionTimer.cancel(false);
System.out.println("\n!!! Save failed !!!\n"); disconnectionTimer = null;
} }
synchronized(gameController){
event.setIsError(!event.apply(gameController));
serverRMI.notifyAll(event);
serverTCP.notifyAll(event);
if(!event.getIsError()){
if(this.gameController.getModel().getCurrentState().getGameStage() == GameStages.ENDED){
this.deleteSave();
for(Map.Entry<String,Boolean> entry:playerList.entrySet()){
if(entry.getValue())
playerList.remove(entry.getKey());
}
serverRMI.setServerCrashed(false);
serverTCP.setServerCrashed(false);
}
else if(!this.gameSave() ){
System.out.println("\n!!! Save failed !!!\n");
}
}
if (event.getEventType().equals(EventType.DISCONNECTED_PLAYER) && playerList.values().stream().filter(x -> x).count() == 1) {
if (disconnectionTimer != null && !disconnectionTimer.isDone()) {
disconnectionTimer.cancel(false);
}
disconnectionTimer = timerExecutor.schedule(() -> {
System.out.println("Timer scaduto: nessun giocatore riconnesso in 30s.");
}, 500, TimeUnit.MILLISECONDS);
}
return !event.getIsError();
} }
//actionQueue.offer(new DisconnectedPlayer(gameController.getModel().getCurrentState().getCurrentPlayer().getUserName()));
return !event.getIsError();
} }
else{
if(event.getEventType().equals(EventType.DISCONNECTED_PLAYER))
{
playerList.remove(event.getUsername());
}
return false;
}
} }
@@ -153,14 +191,25 @@ public class ServerLauncher {
playerList.setAction(()->{ playerList.setAction(()->{
new Thread(()->{ new Thread(()->{
try { try {
launcher.run(); System.out.println("\n\nNotifying model");
} catch (InterruptedException e) { serverRMI.notifyAll(gameController.getModel());
throw new RuntimeException(e); serverTCP.notifyAll(gameController.getModel());
view = new TUI(gameController.getModel());
view.fullRender();
} catch (RemoteException e) { } catch (RemoteException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
}).start(); }).start();
}); });
new Thread(()-> {
try {
launcher.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}).start();
serverRMI.start(serverCrashed); serverRMI.start(serverCrashed);
new Thread(()->{serverTCP.start(serverCrashed);}).start(); new Thread(()->{serverTCP.start(serverCrashed);}).start();
@@ -175,12 +224,6 @@ public class ServerLauncher {
* @throws RemoteException if an RMI error occurs * @throws RemoteException if an RMI error occurs
*/ */
public void run() throws InterruptedException, RemoteException { public void run() throws InterruptedException, RemoteException {
// Game creation
System.out.println("\n\nNotifying model");
serverRMI.notifyAll(gameController.getModel());
serverTCP.notifyAll(gameController.getModel());
this.view = new TUI(gameController.getModel());
this.view.fullRender();
// Game execution // Game execution
while (true) { while (true) {