Skip to content

Commit 9788672

Browse files
committed
Support CL68360 co-op replays
1 parent 76f0809 commit 9788672

File tree

8 files changed

+176
-125
lines changed

8 files changed

+176
-125
lines changed

shroudstone/replay.py

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ def summarize_replay(replay: Union[Path, BinaryIO]) -> ReplaySummary:
128128
)
129129
elif slot.client_id is not None:
130130
client = state.clients.pop(slot.client_id)
131+
if client.nickname is None:
132+
raise ReplayParsingError(f"No nickname found for client {client.client_id} = {client.uuid}?")
131133
info.players.append(
132134
p := Player(
133135
nickname=client.nickname,
@@ -148,6 +150,8 @@ def summarize_replay(replay: Union[Path, BinaryIO]) -> ReplaySummary:
148150
for client in state.clients.values():
149151
if client.slot_number != 255:
150152
raise ReplayParsingError("Player not in a slot but slot_number != 255?")
153+
if client.nickname is None:
154+
raise ReplayParsingError(f"No nickname found for client {client.client_id} = {client.uuid}?")
151155
info.spectators.append(
152156
Spectator(
153157
nickname=client.nickname,
@@ -222,13 +226,18 @@ class LeftGameReason(IntEnum):
222226
class Client(BaseModel):
223227
uuid: UUID
224228
client_id: int
225-
nickname: str
226-
discriminator: str
229+
nickname: Optional[str] = None
230+
discriminator: Optional[str] = None
227231
slot_number: Optional[int] = None # 255 means spectator
228232
left_game_time: Optional[float] = None
229233
left_game_reason: LeftGameReason = LeftGameReason.unknown
230234

231235

236+
class SlotAssignment(BaseModel):
237+
slot_number: int
238+
nickname: str
239+
240+
232241
def parse_uuid(uuid: pb.UUID) -> UUID:
233242
return UUID(bytes=struct.pack(">qq", uuid.part1, uuid.part2))
234243

@@ -239,7 +248,7 @@ class GameState(BaseModel):
239248
map_name: Optional[str] = None
240249
slots: Dict[int, Slot] = {}
241250
clients: Dict[int, Client] = {}
242-
slot_assignments: Dict[UUID, int] = {}
251+
slot_assignments: Dict[UUID, SlotAssignment] = {}
243252
game_started: bool = False
244253
game_started_time: Optional[float] = None
245254

@@ -272,7 +281,9 @@ def handle_map(self, msg: pb.Map, **__):
272281
self.slots[i] = Slot()
273282

274283
def handle_assign_player_slot(self, msg: pb.AssignPlayerSlot, **__):
275-
self.slot_assignments[parse_uuid(msg.uuid)] = msg.slot
284+
self.slot_assignments[parse_uuid(msg.uuid)] = SlotAssignment(
285+
slot_number=msg.slot, nickname=msg.nickname
286+
)
276287
logger.debug(f"Assigning slot {msg.slot} to {msg.uuid}")
277288

278289
def handle_player(self, msg: pb.Player, client_id, **__):
@@ -284,11 +295,32 @@ def handle_player(self, msg: pb.Player, client_id, **__):
284295
)
285296
logger.debug(f"Setting up player {client_id}: {client.nickname} {client.uuid}")
286297
# If we're in a matchmaking game, the server has pre-assigned a slot for the player:
287-
if (slot_number := self.slot_assignments.get(client.uuid)) is not None:
288-
client.slot_number = slot_number
289-
self.slots[slot_number].client_id = client_id
298+
if (assignment := self.slot_assignments.get(client.uuid)) is not None:
299+
client.slot_number = assignment.slot_number
300+
self.slots[assignment.slot_number].client_id = client_id
301+
logger.debug(
302+
f"Putting player {client_id} in pre-assigned slot {client.slot_number}"
303+
)
304+
305+
def handle_player_start_game(self, msg: pb.PlayerStartGame, **__):
306+
if not msg.HasField("uuid"):
307+
# We should have already filled in the player details in handle_player,
308+
# don't worry about it
309+
return
310+
self.clients[msg.client_id] = client = Client(
311+
client_id=msg.client_id,
312+
uuid=parse_uuid(msg.uuid),
313+
)
314+
logger.debug(f"Setting up player {client.client_id}: {client.uuid}")
315+
if (assignment := self.slot_assignments.get(client.uuid)) is not None:
316+
client.slot_number = assignment.slot_number
317+
if client.nickname is not None:
318+
assert client.nickname == assignment.nickname
319+
else:
320+
client.nickname = assignment.nickname
321+
self.slots[assignment.slot_number].client_id = client.client_id
290322
logger.debug(
291-
f"Putting player {client_id} in pre-assigned slot {slot_number}"
323+
f"Putting player {client.client_id} in pre-assigned slot {client.slot_number}"
292324
)
293325

294326
def handle_player_left_game(self, msg: pb.PlayerLeftGame, client_id, timestamp):

shroudstone/stormgate_pb2.py

Lines changed: 37 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)