Fixed: Temporary fix Concurrent access disconnected player game (nextPlayerSetup)

This commit is contained in:
rubenpirreram
2026-05-27 19:16:15 +02:00
parent d14126f198
commit 29de0a9ed8
3 changed files with 29 additions and 19 deletions
@@ -40,7 +40,7 @@ public class GameController {
* {@code false} if no player with the specified username exists * {@code false} if no player with the specified username exists
* or if the operation fails. * or if the operation fails.
*/ */
public boolean DisconnectedPlayer(String username) public synchronized boolean DisconnectedPlayer(String username)
{ {
Player player= model.getPlayerByUsername(username); Player player= model.getPlayerByUsername(username);
if(player==null) if(player==null)
@@ -56,7 +56,7 @@ public class GameController {
* {@code false} if no player with the specified username exists * {@code false} if no player with the specified username exists
* or if the operation fails. * or if the operation fails.
*/ */
public boolean ReconnectPlayer(String username) public synchronized boolean ReconnectPlayer(String username)
{ {
Player player= model.getPlayerByUsername(username); Player player= model.getPlayerByUsername(username);
if(player==null) if(player==null)
@@ -89,7 +89,7 @@ public class GameController {
* @return {@code true} if the player is successfully added, * @return {@code true} if the player is successfully added,
* {@code false} otherwise. * {@code false} otherwise.
*/ */
public boolean addPlayer(String username) { public synchronized boolean addPlayer(String username) {
return model.addPlayer(new Player(username)); return model.addPlayer(new Player(username));
} }
@@ -102,7 +102,7 @@ public class GameController {
* @return {@code true} if the action succeeds, * @return {@code true} if the action succeeds,
* {@code false} if the player does not exist or if the draw operation fails. * {@code false} if the player does not exist or if the draw operation fails.
*/ */
public boolean drawUpperTribeCard(String playerUsername,int pos) { public synchronized boolean drawUpperTribeCard(String playerUsername,int pos) {
Player player= model.getPlayerByUsername(playerUsername); Player player= model.getPlayerByUsername(playerUsername);
if(player==null) if(player==null)
return false; return false;
@@ -118,7 +118,7 @@ public class GameController {
* @return {@code true} if the action succeeds, * @return {@code true} if the action succeeds,
* {@code false} if the player does not exist or if the draw operation fails. * {@code false} if the player does not exist or if the draw operation fails.
*/ */
public boolean drawLowerTribeCard(String playerUsername,int pos) { public synchronized boolean drawLowerTribeCard(String playerUsername,int pos) {
Player player= model.getPlayerByUsername(playerUsername); Player player= model.getPlayerByUsername(playerUsername);
if(player==null) if(player==null)
return false; return false;
@@ -134,7 +134,7 @@ public class GameController {
* @return {@code true} if the action succeeds, * @return {@code true} if the action succeeds,
* {@code false} if the player does not exist or if the draw operation fails. * {@code false} if the player does not exist or if the draw operation fails.
*/ */
public boolean drawUpperBuildingCard(String playerUsername,int pos) { public synchronized boolean drawUpperBuildingCard(String playerUsername,int pos) {
Player player= model.getPlayerByUsername(playerUsername); Player player= model.getPlayerByUsername(playerUsername);
if(player==null) if(player==null)
return false; return false;
@@ -150,7 +150,7 @@ public class GameController {
* @return {@code true} if the action succeeds, * @return {@code true} if the action succeeds,
* {@code false} if the player does not exist or if the draw operation fails. * {@code false} if the player does not exist or if the draw operation fails.
*/ */
public boolean drawLowerBuildingCard(String playerUsername,int pos) { public synchronized boolean drawLowerBuildingCard(String playerUsername,int pos) {
Player player= model.getPlayerByUsername(playerUsername); Player player= model.getPlayerByUsername(playerUsername);
if(player==null) if(player==null)
return false; return false;
@@ -165,7 +165,7 @@ public class GameController {
* @return {@code true} if the skip action is valid and successfully performed, * @return {@code true} if the skip action is valid and successfully performed,
* {@code false} if the player does not exist or if the action is not valid. * {@code false} if the player does not exist or if the action is not valid.
*/ */
public boolean SkipTurn(String playerUsername) { public synchronized boolean SkipTurn(String playerUsername) {
Player player= model.getPlayerByUsername(playerUsername); Player player= model.getPlayerByUsername(playerUsername);
if(player==null) if(player==null)
return false; return false;
@@ -183,7 +183,7 @@ public class GameController {
* @return {@code true} if the action succeeds, * @return {@code true} if the action succeeds,
* {@code false} if the player does not exist or if the slot choice operation fails. * {@code false} if the player does not exist or if the slot choice operation fails.
*/ */
public boolean slotChoice(String playerUsername,int pos) { public synchronized boolean slotChoice(String playerUsername,int pos) {
Player player= model.getPlayerByUsername(playerUsername); Player player= model.getPlayerByUsername(playerUsername);
if(player==null) if(player==null)
return false; return false;
@@ -199,10 +199,15 @@ public class GameController {
* {@code false} if no player with the specified username exists * {@code false} if no player with the specified username exists
* or if the choice operation fails. * or if the choice operation fails.
*/ */
public boolean TotemChoice(String playerUsername,String totem) { public synchronized boolean TotemChoice(String playerUsername,String totem) {
Player player= model.getPlayerByUsername(playerUsername); Player player= model.getPlayerByUsername(playerUsername);
if(player==null) if(player==null)
return false; return false;
return model.TotemChoice(player, Totems.valueOf(totem)); return model.TotemChoice(player, Totems.valueOf(totem));
} }
//TODO
public synchronized void EndGameForFeit(){
model.EndGameForFeit();
}
} }
@@ -83,7 +83,7 @@ public class Game implements Serializable {
* @param totem the selected totem. * @param totem the selected totem.
* @return {@code true} if the choice is applied successfully, {@code false} otherwise. * @return {@code true} if the choice is applied successfully, {@code false} otherwise.
*/ */
public boolean TotemChoice(Player player,Totems totem) { public synchronized boolean TotemChoice(Player player,Totems totem) {
if(!currentState.getGameStage().equals(GameStages.TOTEM_CHOICE)) if(!currentState.getGameStage().equals(GameStages.TOTEM_CHOICE))
return false; return false;
if(!getCurrentState().getCurrentPlayer().equals(player)) if(!getCurrentState().getCurrentPlayer().equals(player))
@@ -135,7 +135,7 @@ public class Game implements Serializable {
* @return {@code true} if the disconnection is handled successfully, * @return {@code true} if the disconnection is handled successfully,
* {@code false} if the player was already marked as disconnected. * {@code false} if the player was already marked as disconnected.
*/ */
public boolean DisconnectedPlayer(Player player) public synchronized boolean DisconnectedPlayer(Player player)
{ {
if(disconnetedPlayers.containsKey(player) && disconnetedPlayers.get(player)) if(disconnetedPlayers.containsKey(player) && disconnetedPlayers.get(player))
{ {
@@ -177,7 +177,7 @@ public class Game implements Serializable {
* @return {@code true} if the reconnection is handled successfully, * @return {@code true} if the reconnection is handled successfully,
* {@code false} if the player was not previously marked as disconnected. * {@code false} if the player was not previously marked as disconnected.
*/ */
public boolean ReconnectPlayer(Player player) public synchronized boolean ReconnectPlayer(Player player)
{ {
if(!disconnetedPlayers.containsKey(player)) if(!disconnetedPlayers.containsKey(player))
{ {
@@ -198,7 +198,7 @@ public class Game implements Serializable {
/** /**
* Clears the collection of disconnected players. * Clears the collection of disconnected players.
*/ */
public void ClearDisconnected() public synchronized void ClearDisconnected()
{ {
disconnetedPlayers.clear(); disconnetedPlayers.clear();
} }
@@ -689,7 +689,7 @@ public class Game implements Serializable {
* If the current stage is {@code OPTIONAL_CARD_EFFECT}, the next player is taken from the optional card queue. * If the current stage is {@code OPTIONAL_CARD_EFFECT}, the next player is taken from the optional card queue.
* If no player is available, the game stage is updated to {@code RESOLVING_EVENT}. * If no player is available, the game stage is updated to {@code RESOLVING_EVENT}.
*/ */
private void nextPlayerSetup() { private synchronized void nextPlayerSetup() {
if (GameStages.SLOT_CHOICE == currentState.getGameStage()) { if (GameStages.SLOT_CHOICE == currentState.getGameStage()) {
Player tempPlayer = orderLogicCard.pull(); Player tempPlayer = orderLogicCard.pull();
@@ -796,7 +796,7 @@ public class Game implements Serializable {
} }
} }
//TODO //TODO
private void transitionToOptionalOrNextRound() { private synchronized void transitionToOptionalOrNextRound() {
currentState.GameStageUpdate(GameStages.OPT_CARD_E); currentState.GameStageUpdate(GameStages.OPT_CARD_E);
OptionalCardQueue = new LinkedList<>(); OptionalCardQueue = new LinkedList<>();
@@ -986,7 +986,7 @@ public class Game implements Serializable {
* in the first position of the final ranking. The remaining players are * in the first position of the final ranking. The remaining players are
* ordered by prestige value and, in case of a tie, by food value. * ordered by prestige value and, in case of a tie, by food value.
*/ */
public void EndGameForFeit() { public synchronized void EndGameForFeit() {
Player winner=playersList.stream().filter(x->!disconnetedPlayers.containsKey(x)||!disconnetedPlayers.get(x)).toList().get(0); Player winner=playersList.stream().filter(x->!disconnetedPlayers.containsKey(x)||!disconnetedPlayers.get(x)).toList().get(0);
currentState.GameStageUpdate(GameStages.ENDED); currentState.GameStageUpdate(GameStages.ENDED);
playerStanding=new ArrayList<>(playersList); playerStanding=new ArrayList<>(playersList);
@@ -154,7 +154,7 @@ public class ServerLauncher {
disconnectionTimer = timerExecutor.schedule(() -> { disconnectionTimer = timerExecutor.schedule(() -> {
synchronized (gameController) synchronized (gameController)
{ {
game.EndGameForFeit(); gameController.EndGameForFeit();
serverRMI.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); serverRMI.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding()));
serverTCP.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding())); serverTCP.notifyAll(new EndedGame(game.getSlotMap(), game.orderLogicCard, game.getCurrentState(),game.getPlayerStanding()));
System.out.println("Timer expired: no player reconnected in 60s."); System.out.println("Timer expired: no player reconnected in 60s.");
@@ -283,7 +283,8 @@ public class ServerLauncher {
new Thread(()-> { new Thread(()-> {
try { try {
launcher.run(); launcher.run();
} catch (Exception e) }
catch (Exception e)
{ {
System.out.println("Generic exception occurred"); System.out.println("Generic exception occurred");
e.printStackTrace(); e.printStackTrace();
@@ -310,6 +311,10 @@ public class ServerLauncher {
try{ try{
this.doFirstEvent(); this.doFirstEvent();
} }
catch (ConcurrentModificationException e)
{
System.err.println("Concurrent Exception");
}
catch(InterruptedException e){ catch(InterruptedException e){
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
break; break;