1- import asyncio
21import random
32import string
43import time
@@ -47,8 +46,6 @@ def _expire_player_effects(status: PlayerStatus, now: float) -> None:
4746class GameManager :
4847 def __init__ (self , store : RedisStore ) -> None :
4948 self ._store = store
50- # Map data is immutable after creation — cache it in-process to avoid Redis GETs on every move.
51- self ._map_cache : dict [str , MapData ] = {}
5249
5350 # ── create_room ───────────────────────────────────────────
5451
@@ -71,7 +68,6 @@ async def create_room(self, sid: str) -> tuple[str, GameState, MapData]:
7168 "score" : {"red" : 0 , "blue" : 0 },
7269 }
7370 if await self ._store .create_room_atomic (room_id , state , map_data , sid ):
74- self ._map_cache [room_id ] = map_data
7571 break
7672
7773 return room_id , state , map_data
@@ -105,7 +101,6 @@ async def join_room(self, sid: str, room_id: str) -> tuple[GameState, MapData]:
105101 map_data = await self ._store .load_map (room_id )
106102 if map_data is None :
107103 raise GameError ("room_not_found" )
108- self ._map_cache [room_id ] = map_data
109104 return state , map_data
110105
111106 # ── start_game ────────────────────────────────────────────
@@ -137,7 +132,7 @@ async def move_player(self, sid: str, direction: str) -> tuple[str, GameState] |
137132 return None
138133
139134 try :
140- async with self ._store .lock (room_id , timeout = 2.0 , blocking_timeout = 0.5 ):
135+ async with self ._store .lock (room_id , timeout = 5.0 ):
141136 state = await self ._store .load_state (room_id )
142137 if state is None or state ["status" ] != "playing" :
143138 return None
@@ -146,12 +141,9 @@ async def move_player(self, sid: str, direction: str) -> tuple[str, GameState] |
146141 if player is None :
147142 return None
148143
149- map_data = self ._map_cache . get (room_id )
144+ map_data = await self ._store . load_map (room_id )
150145 if map_data is None :
151- map_data = await self ._store .load_map (room_id )
152- if map_data is None :
153- return None
154- self ._map_cache [room_id ] = map_data
146+ return None
155147
156148 now = time .time ()
157149 status = player ["status" ]
@@ -201,12 +193,11 @@ async def move_player(self, sid: str, direction: str) -> tuple[str, GameState] |
201193
202194 async def tick (self , room_id : str ) -> GameState | None :
203195 async with self ._store .lock (room_id , blocking_timeout = 0.5 ):
204- state , end_time = await asyncio .gather (
205- self ._store .load_state (room_id ),
206- self ._store .get_game_end_time (room_id ),
207- )
196+ state = await self ._store .load_state (room_id )
208197 if state is None or state ["status" ] != "playing" :
209198 return None
199+
200+ end_time = await self ._store .get_game_end_time (room_id )
210201 if end_time is None :
211202 return None
212203
@@ -230,9 +221,7 @@ async def tick(self, room_id: str) -> GameState | None:
230221 still_waiting .append (pending )
231222
232223 if respawning :
233- map_data = self ._map_cache .get (room_id ) or await self ._store .load_map (room_id )
234- if map_data is not None :
235- self ._map_cache [room_id ] = map_data
224+ map_data = await self ._store .load_map (room_id )
236225 if map_data is None :
237226 # マップ取得失敗 → 次 tick で再試行
238227 still_waiting .extend (respawning )
@@ -267,6 +256,9 @@ async def disconnect(self, sid: str) -> tuple[str | None, GameState | None]:
267256 if room_id is None :
268257 return None , None
269258
259+ if not await self ._store .room_exists (room_id ):
260+ return room_id , None
261+
270262 remaining : GameState | None = None
271263
272264 async with self ._store .lock (room_id ):
@@ -278,7 +270,6 @@ async def disconnect(self, sid: str) -> tuple[str | None, GameState | None]:
278270
279271 if not state ["players" ]:
280272 await self ._store .delete_room (room_id )
281- self ._map_cache .pop (room_id , None )
282273 remaining = None
283274 else :
284275 if state ["host" ] == sid and state ["status" ] == "waiting" :
0 commit comments