Skip to content

Commit c511259

Browse files
committed
bug fix
1 parent 3c9aa86 commit c511259

3 files changed

Lines changed: 17 additions & 28 deletions

File tree

backend/app/game_manager.py

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import asyncio
21
import random
32
import string
43
import time
@@ -47,8 +46,6 @@ def _expire_player_effects(status: PlayerStatus, now: float) -> None:
4746
class 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":

backend/app/redis_store.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1+
import json
12
from typing import Optional
23

3-
import orjson
4-
54
import redis.asyncio as aioredis
65

76
from app.models import GameState, MapData
@@ -34,28 +33,28 @@ async def create_room_atomic(
3433
"""
3534
# SET NX で room_id の唯一性を保証
3635
room_set = await self._client.set(
37-
f"room:{room_id}", orjson.dumps(state), nx=True, ex=ROOM_TTL
36+
f"room:{room_id}", json.dumps(state), nx=True, ex=ROOM_TTL
3837
)
3938
if not room_set:
4039
return False
4140

4241
# 成功したら map と sid をパイプラインで一括書き込み
4342
# (transaction=False: MULTI/EXEC を使わず RTT を 1 回に圧縮)
4443
async with self._client.pipeline(transaction=False) as pipe:
45-
pipe.set(f"map:{room_id}", orjson.dumps(map_data), ex=MAP_TTL)
44+
pipe.set(f"map:{room_id}", json.dumps(map_data), ex=MAP_TTL)
4645
pipe.set(f"sid:{sid}", room_id, ex=SID_TTL)
4746
await pipe.execute()
4847

4948
return True
5049

5150
async def save_state(self, room_id: str, state: GameState) -> None:
5251
await self._client.set(
53-
f"room:{room_id}", orjson.dumps(state), ex=ROOM_TTL
52+
f"room:{room_id}", json.dumps(state), ex=ROOM_TTL
5453
)
5554

5655
async def load_state(self, room_id: str) -> Optional[GameState]:
5756
raw = await self._client.get(f"room:{room_id}")
58-
return orjson.loads(raw) if raw else None
57+
return json.loads(raw) if raw else None
5958

6059
async def room_exists(self, room_id: str) -> bool:
6160
return bool(await self._client.exists(f"room:{room_id}"))
@@ -64,12 +63,12 @@ async def room_exists(self, room_id: str) -> bool:
6463

6564
async def save_map(self, room_id: str, map_data: MapData) -> None:
6665
await self._client.set(
67-
f"map:{room_id}", orjson.dumps(map_data), ex=MAP_TTL
66+
f"map:{room_id}", json.dumps(map_data), ex=MAP_TTL
6867
)
6968

7069
async def load_map(self, room_id: str) -> Optional[MapData]:
7170
raw = await self._client.get(f"map:{room_id}")
72-
return orjson.loads(raw) if raw else None
71+
return json.loads(raw) if raw else None
7372

7473
# ── SID ↔ Room ────────────────────────────────────────────
7574

backend/requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@ python-socketio
44
python-dotenv
55
redis[asyncio]
66
gunicorn
7-
orjson

0 commit comments

Comments
 (0)