From 6c070e1ce535d1d5209197351c509b98b2864597 Mon Sep 17 00:00:00 2001 From: aleandro Date: Sun, 14 Jun 2026 13:49:54 +0200 Subject: [PATCH] Fix: full FA refactor --- .../ingsw/gc14/Controller/GameController.java | 4 ++-- .../polimi/ingsw/gc14/GameEventProcessor.java | 18 ++++++++++------- .../java/it/polimi/ingsw/gc14/LimitedMap.java | 18 +++++++++-------- .../java/it/polimi/ingsw/gc14/Model/Game.java | 2 +- .../it/polimi/ingsw/gc14/SaveManager.java | 20 ++++++++++++------- 5 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/Controller/GameController.java b/src/main/java/it/polimi/ingsw/gc14/Controller/GameController.java index 2fdd2f1..23b9752 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Controller/GameController.java +++ b/src/main/java/it/polimi/ingsw/gc14/Controller/GameController.java @@ -210,7 +210,7 @@ public class GameController { * Ends the game due to forfeit: all remaining players are absent, * so the game is terminated and final scores are computed. */ - public synchronized void endGameForFeit() { - model.endGameForFeit(); + public synchronized void endGameForfeit() { + model.endGameForfeit(); } } \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/GameEventProcessor.java b/src/main/java/it/polimi/ingsw/gc14/GameEventProcessor.java index ea61e7a..00065d7 100644 --- a/src/main/java/it/polimi/ingsw/gc14/GameEventProcessor.java +++ b/src/main/java/it/polimi/ingsw/gc14/GameEventProcessor.java @@ -29,7 +29,7 @@ import java.util.stream.Collectors; * * *

This class is not thread-safe by itself: it relies on the caller - * (the game loop in {@code ServerLauncherTest}) to drive it from a single + * (the game loop in {@code ServerLauncher}) to drive it from a single * thread via {@link #doFirstEvent()}. */ public class GameEventProcessor { @@ -40,9 +40,13 @@ public class GameEventProcessor { private final CompositeClientBroadcaster broadcaster; private final SaveManager saveManager; - /** Single-thread executor used exclusively for the forfeit timer. */ + /** Single-thread executor used exclusively for the forfeit timer. Daemon so it does not block JVM shutdown. */ private final ScheduledExecutorService timerExecutor = - Executors.newSingleThreadScheduledExecutor(); + Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "forfeit-timer"); + t.setDaemon(true); + return t; + }); /** * Handle to the running forfeit timer, or {@code null} when no timer is active. @@ -267,7 +271,7 @@ public class GameEventProcessor { } disconnectionTimer = timerExecutor.schedule( - () -> endGameForFeit(game), + () -> endGameForfeit(game), 1, TimeUnit.MINUTES ); } @@ -278,9 +282,9 @@ public class GameEventProcessor { * * @param game the game model captured when the timer was scheduled. */ - private void endGameForFeit(Game game) { + private void endGameForfeit(Game game) { synchronized (gameController) { - gameController.endGameForFeit(); + gameController.endGameForfeit(); EndedGame forfeitEnd = new EndedGame( game.getSlotMap(), game.getOrderLogicCard(), game.getCurrentState(), game.getPlayerStanding() @@ -363,7 +367,7 @@ public class GameEventProcessor { List toRemove = playerList.entrySet().stream() .filter(e -> !e.getValue()) .map(Map.Entry::getKey) - .collect(Collectors.toList()); + .toList(); toRemove.forEach(playerList::remove); } } diff --git a/src/main/java/it/polimi/ingsw/gc14/LimitedMap.java b/src/main/java/it/polimi/ingsw/gc14/LimitedMap.java index afaf634..3673b0c 100644 --- a/src/main/java/it/polimi/ingsw/gc14/LimitedMap.java +++ b/src/main/java/it/polimi/ingsw/gc14/LimitedMap.java @@ -1,15 +1,14 @@ package it.polimi.ingsw.gc14; import java.util.Collection; -import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** - * A {@link LinkedHashMap} with a configurable size limit and an associated action. + * A {@link ConcurrentHashMap}-backed map with a configurable size limit and an associated action. * When the number of elements reaches or exceeds the limit, the specified action is automatically triggered. - * This implementation is thread-safe. + * This implementation is thread-safe for {@code put}; callers that need compound operations must synchronize externally. * * @param the type of keys maintained by this map. * @param the type of mapped values. @@ -50,8 +49,8 @@ public class LimitedMap implements Map { @Override public synchronized V put(K key, V value) { boolean added = true; - if(map.size()==limit) { - if(!map.containsKey(key)) + if (map.size() == limit) { + if (!map.containsKey(key)) return null; added = false; } @@ -63,7 +62,7 @@ public class LimitedMap implements Map { } @Override - public V remove(Object key) { return map.remove(key); } + public synchronized V remove(Object key) { return map.remove(key); } @Override public V get(Object key) { return map.get(key); } @@ -112,7 +111,10 @@ public class LimitedMap implements Map { /** * Sets a new action to execute when the map size reaches or exceeds the limit. * - * @param action the new action to set. + * @param action the new action to set; must not be {@code null}. */ - public void setAction(Runnable action) { this.action = action; } + public void setAction(Runnable action) { + if (action == null) throw new IllegalArgumentException("action must not be null"); + this.action = action; + } } \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/Game.java b/src/main/java/it/polimi/ingsw/gc14/Model/Game.java index 23a85c8..345a0f1 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Game.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Game.java @@ -1006,7 +1006,7 @@ public class Game implements Serializable { * 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. */ - public synchronized void endGameForFeit() { + public synchronized void endGameForfeit() { Player winner = playersList.stream() .filter(x -> !disconnectedPlayers.containsKey(x) || !disconnectedPlayers.get(x)) .findFirst().orElse(null); diff --git a/src/main/java/it/polimi/ingsw/gc14/SaveManager.java b/src/main/java/it/polimi/ingsw/gc14/SaveManager.java index 346e926..f699164 100644 --- a/src/main/java/it/polimi/ingsw/gc14/SaveManager.java +++ b/src/main/java/it/polimi/ingsw/gc14/SaveManager.java @@ -2,7 +2,14 @@ package it.polimi.ingsw.gc14; import it.polimi.ingsw.gc14.Model.Game; -import java.io.*; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; @@ -55,8 +62,8 @@ public class SaveManager { public boolean save(Game game) { try { Files.createDirectories(filePath.getParent()); - try (ObjectOutputStream oos = - new ObjectOutputStream(new FileOutputStream(filePath.toFile()))) { + try (ObjectOutputStream oos = new ObjectOutputStream( + new BufferedOutputStream(new FileOutputStream(filePath.toFile())))) { oos.writeObject(game); System.out.println("Game saved to: " + filePath.toAbsolutePath()); return true; @@ -76,8 +83,8 @@ public class SaveManager { * the classpath (indicates a deployment mismatch). */ public Game load() { - try (ObjectInputStream ois = - new ObjectInputStream(new FileInputStream(filePath.toFile()))) { + try (ObjectInputStream ois = new ObjectInputStream( + new BufferedInputStream(new FileInputStream(filePath.toFile())))) { return (Game) ois.readObject(); } catch (FileNotFoundException e) { return null; @@ -97,8 +104,7 @@ public class SaveManager { */ public boolean delete() { try { - Files.delete(filePath); - return true; + return Files.deleteIfExists(filePath); } catch (IOException e) { return false; }