11import asyncio
22import json
33import logging
4+ import re
45import time
56from collections import defaultdict
67from typing import Any , Iterable , Optional
@@ -47,6 +48,9 @@ class GameError(Exception):
4748 pass
4849
4950
51+ MAP_FILE_PATH_PATTERN = re .compile (r"maps/(.+)\.zip" )
52+
53+
5054class Game :
5155 """
5256 Object that lasts for the lifetime of a game on FAF.
@@ -62,7 +66,7 @@ def __init__(
6266 game_stats_service : "GameStatsService" ,
6367 host : Optional [Player ] = None ,
6468 name : str = "None" ,
65- map_ : str = "SCMP_007" ,
69+ map_name : str = "SCMP_007" ,
6670 game_mode : str = FeaturedModType .FAF ,
6771 matchmaker_queue_id : Optional [int ] = None ,
6872 rating_type : Optional [str ] = None ,
@@ -89,7 +93,7 @@ def __init__(
8993 self .host = host
9094 self .name = name
9195 self .map_id = None
92- self .map_file_path = f"maps/ { map_ } .zip"
96+ self .map_name = map_name
9397 self .map_scenario_path = None
9498 self .password = None
9599 self ._players_at_launch : list [Player ] = []
@@ -153,6 +157,30 @@ def set_name_unchecked(self, value: str):
153157 max_len = game_stats .c .gameName .type .length
154158 self ._name = value [:max_len ]
155159
160+ @property
161+ def map_name (self ):
162+ return self ._map_name
163+
164+ @map_name .setter
165+ def map_name (self , name : str ):
166+ self ._map_name = name
167+ self ._map_file_path = f"maps/{ name } .zip"
168+
169+ @property
170+ def map_file_path (self ):
171+ return self ._map_file_path
172+
173+ @map_file_path .setter
174+ def map_file_path (self , path : str ):
175+ m = re .match (MAP_FILE_PATH_PATTERN , path )
176+ if m is None :
177+ raise ValueError (
178+ "Map path must start with 'maps/' and end with '.zip'"
179+ )
180+
181+ self ._map_name = m .group (1 )
182+ self ._map_file_path = path
183+
156184 @property
157185 def armies (self ) -> frozenset [int ]:
158186 return frozenset (
@@ -253,7 +281,7 @@ def get_team_sets(self) -> list[set[Player]]:
253281 raise GameError (
254282 "Missing team for at least one player. (player, team): {}"
255283 .format ([(player , self .get_player_option (player .id , "Team" ))
256- for player in self .players ])
284+ for player in self .players ])
257285 )
258286
259287 teams = defaultdict (set )
@@ -439,7 +467,7 @@ async def on_game_finish(self):
439467 await self .process_game_results ()
440468
441469 self ._process_pending_army_stats ()
442- except Exception : # pragma: no cover
470+ except Exception : # pragma: no cover
443471 self ._logger .exception ("Error during game end" )
444472 finally :
445473 self .state = GameState .ENDED
@@ -565,6 +593,7 @@ async def persist_results(self):
565593 def get_basic_info (self ) -> BasicGameInfo :
566594 return BasicGameInfo (
567595 self .id ,
596+ self .game_type ,
568597 self .rating_type ,
569598 self .map_id ,
570599 self .game_mode ,
@@ -936,10 +965,7 @@ def map_folder_name(self) -> str:
936965 try :
937966 return str (self .map_scenario_path .split ("/" )[2 ]).lower ()
938967 except (IndexError , AttributeError ):
939- if self .map_file_path :
940- return self .map_file_path [5 :- 4 ].lower ()
941- else :
942- return "scmp_009"
968+ return self .map_name
943969
944970 def __eq__ (self , other ):
945971 if not isinstance (other , Game ):
@@ -955,3 +981,9 @@ def __str__(self) -> str:
955981 f"Game({ self .id } , { self .host .login if self .host else '' } , "
956982 f"{ self .map_file_path } )"
957983 )
984+
985+ def wait_launched (self , param ):
986+ pass
987+
988+ def wait_hosted (self , param ):
989+ pass
0 commit comments