Skip to content

Commit 86dbcd6

Browse files
committed
fix: simplify Game & GameRoom termination
1 parent 001af2f commit 86dbcd6

File tree

4 files changed

+30
-61
lines changed

4 files changed

+30
-61
lines changed

sdk/src/server-api/sc/api/plugins/IGameInstance.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ import sc.api.plugins.host.IGameListener
55
import sc.framework.plugins.Player
66
import sc.shared.InvalidMoveException
77
import sc.shared.PlayerScore
8-
import sc.shared.ScoreCause
8+
99
import kotlin.jvm.Throws
1010

1111
interface IGameInstance {
1212
/** @return the player that joined. */
1313
fun onPlayerJoined(): Player
14-
fun onPlayerLeft(player: Player, cause: ScoreCause? = null)
1514

1615
/**
1716
* Called by the Server upon receiving a Move.
@@ -28,13 +27,13 @@ interface IGameInstance {
2827

2928
/** Server or an administrator requests the game to start now. */
3029
fun start()
31-
30+
3231
/**
33-
* Destroys the Game.
34-
* Might be invoked by the server at any time. Any open handles should be removed.
32+
* Stops the Game, removing any open handles.
33+
*
3534
* No events (GameOver etc) should be sent out after this method has been called.
3635
*/
37-
fun destroy()
36+
fun stop()
3837

3938
/**
4039
* Returns the players that have won the game, empty if the game has no winners,

sdk/src/server-api/sc/framework/plugins/AbstractGame.kt

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ abstract class AbstractGame<P : Player>(override val pluginUUID: String) : IGame
4646
if (timer.didTimeout()) {
4747
logger.warn("Client hit soft-timeout.")
4848
fromPlayer.softTimeout = true
49-
onPlayerLeft(fromPlayer, ScoreCause.SOFT_TIMEOUT)
49+
stop()
5050
} else {
5151
onRoundBasedAction(fromPlayer, move)
5252
}
@@ -68,15 +68,12 @@ abstract class AbstractGame<P : Player>(override val pluginUUID: String) : IGame
6868
*/
6969
abstract fun checkWinCondition(): WinCondition?
7070

71-
/**
72-
* At any time this method might be invoked by the server.
73-
* Any open handles should be removed.
74-
* No events should be sent out (GameOver etc) after this method has been called.
75-
*/
76-
override fun destroy() {
77-
logger.info("Destroying Game")
71+
/** Stops pending MoveRequests and invokes [notifyOnGameOver]. */
72+
override fun stop() {
73+
logger.info("Stopping {}", this)
7874
moveRequestTimeout?.stop()
7975
moveRequestTimeout = null
76+
notifyOnGameOver(generateScoreMap())
8077
}
8178

8279
/** Starts the game by sending a [WelcomeMessage] to all players and calling [next]. */
@@ -85,28 +82,6 @@ abstract class AbstractGame<P : Player>(override val pluginUUID: String) : IGame
8582
next(players.first())
8683
}
8784

88-
/**
89-
* Handle leave of a player.
90-
*
91-
* @param player the player that left.
92-
* @param cause the cause for the leave. If none is provided, then it will either be {@link ScoreCause#RULE_VIOLATION} or {$link ScoreCause#LEFT}, depending on whether the player has {@link Player#hasViolated()}.
93-
*/
94-
override fun onPlayerLeft(player: Player, cause: ScoreCause?) {
95-
if (cause == ScoreCause.REGULAR) return
96-
val newCause = cause ?:
97-
if (!player.hasViolated()) {
98-
player.left = true
99-
ScoreCause.LEFT
100-
} else {
101-
ScoreCause.RULE_VIOLATION
102-
}
103-
val scores = HashMap(generateScoreMap())
104-
scores[player]?.let { score ->
105-
scores[player] = PlayerScore(newCause, score.reason, score.parts)
106-
}
107-
notifyOnGameOver(scores)
108-
}
109-
11085
/** Advances the Game to [nextPlayer].
11186
* - sends out a state update
11287
* - invokes [notifyOnGameOver] if the game is over
@@ -119,7 +94,7 @@ abstract class AbstractGame<P : Player>(override val pluginUUID: String) : IGame
11994

12095
if (checkWinCondition() != null) {
12196
logger.debug("Game over")
122-
notifyOnGameOver(generateScoreMap())
97+
stop()
12398
} else {
12499
logger.debug("Next player: $nextPlayer")
125100

@@ -155,7 +130,7 @@ abstract class AbstractGame<P : Player>(override val pluginUUID: String) : IGame
155130
timeout.start {
156131
logger.warn("Player $player reached the timeout of ${timeout.hardTimeout}ms")
157132
player.hardTimeout = true
158-
onPlayerLeft(player, ScoreCause.HARD_TIMEOUT)
133+
stop()
159134
}
160135

161136
logger.info("Sending MoveRequest to player $activePlayer")

server/src/sc/server/gaming/GameRoom.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,8 @@
1414
import sc.framework.HelperMethods;
1515
import sc.framework.plugins.AbstractGame;
1616
import sc.framework.plugins.Player;
17-
import sc.framework.HelperMethods;
1817
import sc.networking.XStreamProvider;
1918
import sc.networking.clients.IClient;
20-
import sc.networking.clients.LobbyClient;
21-
import sc.networking.clients.ObservingClient;
2219
import sc.networking.clients.XStreamClient;
2320
import sc.protocol.ProtocolPacket;
2421
import sc.protocol.RemovedFromGame;
@@ -95,8 +92,7 @@ public synchronized void onGameOver(Map<Player, PlayerScore> results) {
9592
}
9693
}
9794

98-
kickAllClients();
99-
cancel();
95+
destroy();
10096
}
10197

10298
public File createReplayFile() throws IOException {
@@ -262,8 +258,8 @@ private void startIfReady() {
262258
}
263259

264260
private synchronized void start() {
265-
setStatus(GameStatus.ACTIVE);
266261
this.game.start();
262+
setStatus(GameStatus.ACTIVE);
267263
logger.info("Started {}", game);
268264
}
269265

@@ -326,7 +322,7 @@ public synchronized void onEvent(Client source, IMove move) throws GameRoomExcep
326322
player.notifyListeners(errorMessage);
327323
observerBroadcast(errorMessage);
328324
history.add(errorMessage);
329-
game.onPlayerLeft(player, ScoreCause.RULE_VIOLATION);
325+
cancel();
330326
throw new GameLogicException(e.toString(), e);
331327
} catch (GameLogicException e) {
332328
player.notifyListeners(new ErrorMessage(move, e.getMessage()));
@@ -416,11 +412,12 @@ public synchronized void step(boolean forced) throws GameRoomException {
416412

417413
/** Kick all players, destroy the game and remove it from the manager. */
418414
public void cancel() {
419-
if (!isOver()) {
420-
kickAllClients();
421-
setStatus(GameStatus.OVER);
422-
}
423-
this.game.destroy();
415+
// this will invoked onGameOver and thus stop everything else
416+
this.game.stop();
417+
}
418+
419+
private void destroy() {
420+
kickAllClients();
424421
this.gameRoomManager.remove(this);
425422
}
426423

@@ -455,10 +452,12 @@ protected void setStatus(GameStatus status) {
455452
this.status = status;
456453
}
457454

458-
/** Remove a player by calling {@link IGameInstance#onPlayerLeft(Player, ScoreCause) onPlayerLeft}. */
455+
/** Remove a player and stop the game. */
459456
public void removePlayer(Player player, XStreamClient.DisconnectCause cause) {
460457
logger.info("Removing {} from {}", player, this);
461-
this.game.onPlayerLeft(player, cause == XStreamClient.DisconnectCause.DISCONNECTED ? ScoreCause.REGULAR : null);
458+
player.setLeft(true);
459+
if (!isOver())
460+
cancel();
462461
}
463462

464463
/** Get the saved {@link GameResult result}. */

server/test/sc/server/plugins/TestGame.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,11 @@ data class TestGame(
4444
throw TooManyPlayersException()
4545
}
4646

47-
override fun onPlayerLeft(player: Player, cause: ScoreCause?) {
48-
val result = generateScoreMap().toMutableMap()
49-
result[player] = PlayerScore(cause ?: ScoreCause.LEFT, "Spieler hat das Spiel verlassen.", 0)
50-
notifyOnGameOver(result)
51-
}
52-
53-
override fun getScoreFor(player: Player): PlayerScore {
54-
return PlayerScore(true, "Spieler hat gewonnen.")
55-
}
47+
override fun getScoreFor(player: Player) =
48+
if(player.hasLeft())
49+
PlayerScore(ScoreCause.LEFT, "Spieler ist rausgeflogen.", 0)
50+
else
51+
PlayerScore(true, "Spieler hat gewonnen.")
5652

5753
override fun getTimeoutFor(player: Player): ActionTimeout =
5854
ActionTimeout(false)

0 commit comments

Comments
 (0)