Skip to content

Commit ddb3ffa

Browse files
committed
chore: clean up among them roster checks
1 parent f06a18c commit ddb3ffa

3 files changed

Lines changed: 122 additions & 23 deletions

File tree

.github/workflows/among-them.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Among Them
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- ".github/workflows/among-them.yml"
7+
- "among_them/**"
8+
- "bitworld.nimble"
9+
- "clients/global_client.nim"
10+
- "common/**"
11+
- "config.nims"
12+
- "nim.cfg"
13+
- "nimby.lock"
14+
- "src/**"
15+
push:
16+
branches:
17+
- master
18+
paths:
19+
- ".github/workflows/among-them.yml"
20+
- "among_them/**"
21+
- "bitworld.nimble"
22+
- "clients/global_client.nim"
23+
- "common/**"
24+
- "config.nims"
25+
- "nim.cfg"
26+
- "nimby.lock"
27+
- "src/**"
28+
29+
jobs:
30+
roster-tests:
31+
name: Roster Tests
32+
runs-on: ubuntu-latest
33+
34+
steps:
35+
- uses: actions/checkout@v4
36+
37+
- uses: jiro4989/setup-nim-action@v2
38+
with:
39+
nim-version: "2.2.4"
40+
41+
- name: Install Nim dependencies
42+
run: nimble install -y --depsOnly
43+
44+
- name: Run slot tests
45+
run: nim c --nimcache:/tmp/bitworld-ci-test-slots -r among_them/tests/test_slots.nim
46+
47+
- name: Run stats tests
48+
run: nim c --nimcache:/tmp/bitworld-ci-test-stats -r among_them/tests/test_stats.nim
49+
50+
- name: Run start-wait tests
51+
run: nim c --nimcache:/tmp/bitworld-ci-test-start-wait -r among_them/tests/test_start_wait.nim
52+
53+
wasm-replay-viewer:
54+
name: Wasm Replay Viewer
55+
runs-on: ubuntu-latest
56+
57+
steps:
58+
- uses: actions/checkout@v4
59+
60+
- uses: jiro4989/setup-nim-action@v2
61+
with:
62+
nim-version: "2.2.4"
63+
64+
- uses: mymindstorm/setup-emsdk@v14
65+
66+
- name: Install Nim dependencies
67+
run: nimble install -y --depsOnly
68+
69+
- name: Compile replay viewer
70+
run: nim c -d:emscripten --nimcache:/tmp/bitworld-ci-replay-viewer among_them/replay_viewer.nim

among_them/sim.nim

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ type
249249
hasRole*: bool
250250
hasColor*: bool
251251

252+
SlotCredentialMatch = enum
253+
SlotCredentialNone,
254+
SlotCredentialValid,
255+
SlotCredentialConflict
256+
252257
GameConfig* = object
253258
motionScale*: int
254259
accel*: int
@@ -1478,6 +1483,14 @@ proc canAddPlayer*(sim: SimServer): bool =
14781483
## Returns whether the game has room for another player.
14791484
sim.players.len < sim.config.playerSlotLimit()
14801485

1486+
proc playerLimitError(config: GameConfig): string =
1487+
## Returns a user-facing message for the current player cap.
1488+
if config.closedRoster:
1489+
let limit = config.playerSlotLimit()
1490+
return "Configured roster is full (" & $limit &
1491+
(if limit == 1: " player)." else: " players).")
1492+
"can't do more than " & $MaxPlayers & " players."
1493+
14811494
proc slotConfig(config: GameConfig, slotIndex: int): PlayerSlotConfig =
14821495
## Returns one slot config or an empty config for missing entries.
14831496
if slotIndex >= 0 and slotIndex < config.slots.len:
@@ -1523,6 +1536,24 @@ proc validatePlayerSlot(
15231536
"Player token does not match configured slot " & $slotIndex & "."
15241537
)
15251538

1539+
proc slotCredentialMatch(
1540+
config: GameConfig,
1541+
slotIndex: int,
1542+
address,
1543+
token: string
1544+
): SlotCredentialMatch =
1545+
## Classifies whether a player identity/token pair matches one configured slot.
1546+
let slot = config.slotConfig(slotIndex)
1547+
let
1548+
matchedName = slot.name.len > 0 and slot.name == address
1549+
matchedToken = slot.token.len > 0 and token.len > 0 and slot.token == token
1550+
if not matchedName and not matchedToken:
1551+
return SlotCredentialNone
1552+
if config.slotAuthMatches(slotIndex, address, token):
1553+
SlotCredentialValid
1554+
else:
1555+
SlotCredentialConflict
1556+
15261557
proc configuredPlayerName*(config: GameConfig, requestedSlot: int, token: string): string =
15271558
## Returns the configured identity for a tokenized slot request.
15281559
if token.len == 0:
@@ -1544,11 +1575,7 @@ proc matchingConfiguredSlot(
15441575
): int =
15451576
## Returns a configured slot matched by name or token without occupancy checks.
15461577
for i in 0 ..< config.slots.len:
1547-
let slot = config.slots[i]
1548-
let couldMatchName = slot.name.len > 0 and slot.name == address
1549-
let couldMatchToken = slot.token.len > 0 and slot.token == token
1550-
if (couldMatchName or couldMatchToken) and
1551-
config.slotAuthMatches(i, address, token):
1578+
if config.slotCredentialMatch(i, address, token) == SlotCredentialValid:
15521579
return i
15531580
-1
15541581

@@ -1559,12 +1586,7 @@ proc conflictingConfiguredSlot(
15591586
): int =
15601587
## Returns a configured slot matched by only one required credential.
15611588
for i in 0 ..< config.slots.len:
1562-
let slot = config.slots[i]
1563-
let matchedName = slot.name.len > 0 and slot.name == address
1564-
let matchedToken =
1565-
slot.token.len > 0 and token.len > 0 and slot.token == token
1566-
if (matchedName or matchedToken) and
1567-
not config.slotAuthMatches(i, address, token):
1589+
if config.slotCredentialMatch(i, address, token) == SlotCredentialConflict:
15681590
return i
15691591
-1
15701592

@@ -1596,11 +1618,7 @@ proc matchingConfiguredSlot(
15961618
for i in 0 ..< sim.config.slots.len:
15971619
if sim.slotOccupied(i):
15981620
continue
1599-
let slot = sim.config.slots[i]
1600-
let couldMatchName = slot.name.len > 0 and slot.name == address
1601-
let couldMatchToken = slot.token.len > 0 and slot.token == token
1602-
if (couldMatchName or couldMatchToken) and
1603-
sim.config.slotAuthMatches(i, address, token):
1621+
if sim.config.slotCredentialMatch(i, address, token) == SlotCredentialValid:
16041622
return i
16051623
-1
16061624

@@ -1613,12 +1631,7 @@ proc conflictingConfiguredSlot(
16131631
for i in 0 ..< sim.config.slots.len:
16141632
if sim.slotOccupied(i):
16151633
continue
1616-
let slot = sim.config.slots[i]
1617-
let matchedName = slot.name.len > 0 and slot.name == address
1618-
let matchedToken =
1619-
slot.token.len > 0 and token.len > 0 and slot.token == token
1620-
if (matchedName or matchedToken) and
1621-
not sim.config.slotAuthMatches(i, address, token):
1634+
if sim.config.slotCredentialMatch(i, address, token) == SlotCredentialConflict:
16221635
return i
16231636
-1
16241637

@@ -1793,7 +1806,7 @@ proc addPlayer*(
17931806
): int =
17941807
## Adds one player, optionally validating and using a requested slot.
17951808
if not sim.canAddPlayer():
1796-
raise newException(AmongThemError, "can't do more than 16 players.")
1809+
raise newException(AmongThemError, sim.config.playerLimitError())
17971810
if sim.playerAddressOccupied(address):
17981811
raise newException(
17991812
AmongThemError,

among_them/tests/test_slots.nim

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,22 @@ suite "player slots":
229229
expect AmongThemError:
230230
discard sim.addPlayer("extra")
231231

232+
test "closed configured roster full error names configured limit":
233+
var config = defaultGameConfig()
234+
config.minPlayers = 2
235+
config.update("""{"tokens":["crew-token","imp-token"],"closedRoster":true}""")
236+
var sim = initAmongThemForTest(config)
237+
238+
discard sim.addPlayer("Player1", -1, "crew-token")
239+
discard sim.addPlayer("Player2", -1, "imp-token")
240+
241+
var errorMessage = ""
242+
try:
243+
discard sim.addPlayer("extra")
244+
except AmongThemError as e:
245+
errorMessage = e.msg
246+
check errorMessage == "Configured roster is full (2 players)."
247+
232248
test "closed configured roster rejects explicit slots outside roster":
233249
var config = defaultGameConfig()
234250
config.minPlayers = 2

0 commit comments

Comments
 (0)