Skip to content

Commit f74572a

Browse files
committed
fix(server): appropriately handle empty slots at game start
1 parent 8952424 commit f74572a

File tree

4 files changed

+25
-5
lines changed

4 files changed

+25
-5
lines changed

sdk/src/main/server-api/sc/framework/plugins/Player.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.thoughtworks.xstream.annotations.XStreamOmitField
77
import org.slf4j.LoggerFactory
88
import sc.api.plugins.ITeam
99
import sc.api.plugins.host.IPlayerListener
10+
import sc.networking.clients.XStreamClient.DisconnectCause
1011
import sc.protocol.room.MoveRequest
1112
import sc.protocol.room.RoomMessage
1213
import sc.util.PlayerConverter
@@ -37,9 +38,9 @@ class Player @JvmOverloads constructor(
3738
var canTimeout: Boolean = false
3839

3940
@XStreamOmitField
40-
var left = false
41+
var left: DisconnectCause? = null
4142

42-
fun hasLeft() = left
43+
fun hasLeft() = left != null
4344

4445
@XStreamOmitField
4546
var softTimeout = false

sdk/src/main/server-api/sc/protocol/RemovedFromGame.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ import com.thoughtworks.xstream.annotations.XStreamAsAttribute
88
data class RemovedFromGame(
99
@XStreamAsAttribute
1010
val roomId: String
11-
): ProtocolPacket
11+
): ResponsePacket

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,10 @@ public synchronized void step(boolean forced) {
367367
if (getStatus() == GameStatus.CREATED) {
368368
if (forced) {
369369
logger.warn("Forcing game start for {}", game);
370-
start();
370+
if(getClients().size() < 2)
371+
cancel();
372+
else
373+
start();
371374
} else {
372375
logger.info("Game isn't active yet, step was not forced.");
373376
}
@@ -406,7 +409,10 @@ protected void setStatus(GameStatus status) {
406409
/** Remove a player and stop the game. */
407410
public void removePlayer(Player player, XStreamClient.DisconnectCause cause) {
408411
logger.info("Removing {} from {}", player, this);
409-
player.setLeft(true);
412+
// Mark all non-joined players as left to trigger a draw when noone joined
413+
// Might be superfluous through the check in "step", but keeping for safety
414+
playerSlots.forEach(slot -> slot.getPlayer().setLeft(slot.isEmpty() ? cause : null));
415+
player.setLeft(cause);
410416
if (!isOver())
411417
cancel();
412418
}

server/src/test/java/sc/server/network/LobbyGameTest.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import io.kotest.matchers.collections.*
1010
import io.kotest.matchers.nulls.*
1111
import io.kotest.matchers.string.*
1212
import sc.api.plugins.Team
13+
import sc.protocol.RemovedFromGame
1314
import sc.protocol.ResponsePacket
1415
import sc.protocol.requests.JoinPreparedRoomRequest
1516
import sc.protocol.requests.PrepareGameRequest
@@ -95,6 +96,18 @@ class LobbyGameTest: WordSpec({
9596
room.clients.shouldBeEmpty()
9697
room.isPauseRequested shouldBe true
9798
}
99+
100+
"return GameResult on step" {
101+
val roomListener = observeRoom(room.id)
102+
admin.control(room.id).step(true)
103+
val result = roomListener.waitForMessage(GameResult::class)
104+
withClue("No Winner") {
105+
result.winner shouldBe null
106+
}
107+
adminListener.waitForMessage(RemovedFromGame::class)
108+
roomListener.clearMessages() shouldBe 0
109+
admin.closed shouldBe false
110+
}
98111

99112
val reservations = prepared.reservations
100113
players[0].joinGameWithReservation(reservations[0])

0 commit comments

Comments
 (0)