diff --git a/server/core/server.py b/server/core/server.py index e4f299e5..17657274 100644 --- a/server/core/server.py +++ b/server/core/server.py @@ -36,9 +36,10 @@ from .documents.transcriber_role import TranscriberRoleMixin from .virtual_bots import VirtualBotManager from ..network.websocket_server import WebSocketServer, ClientConnection -from ..persistence.database import Database +from ..persistence.database import Database, UserRecord from ..auth.auth import AuthManager, AuthResult from .tables.manager import TableManager +from .tables.table import Table from .users.network_user import NetworkUser from .users.base import MenuItem, EscapeBehavior, TrustLevel from .users.preferences import UserPreferences, DiceKeepingStyle, PREF_CATEGORIES, PrefMeta @@ -1133,7 +1134,7 @@ async def _finalize_login( if not self._restore_login_table(user, username): self._show_main_menu(user) - def _load_user_preferences(self, user_record: "AuthUserRecord") -> UserPreferences: + def _load_user_preferences(self, user_record: "UserRecord") -> UserPreferences: """Load stored preferences, falling back to defaults.""" if user_record.preferences_json: try: @@ -1150,7 +1151,7 @@ async def _attach_or_update_user( self, client: ClientConnection, username: str, - user_record: "AuthUserRecord", + user_record: "UserRecord", preferences: UserPreferences, ) -> tuple[NetworkUser, bool]: """Attach a connection to an existing user or create a new one.""" diff --git a/server/core/virtual_bots.py b/server/core/virtual_bots.py index 2952b4da..e450a3a7 100644 --- a/server/core/virtual_bots.py +++ b/server/core/virtual_bots.py @@ -903,7 +903,7 @@ def _build_admin_guided_snapshot(self) -> list[dict[str, Any]]: """Build snapshot data for guided table rules.""" return [self._build_guided_state_snapshot(state) for state in self._iter_guided_states()] - def _build_guided_state_snapshot(self, state: "GuidedTableRuleState") -> dict[str, Any]: + def _build_guided_state_snapshot(self, state: "GuidedTableState") -> dict[str, Any]: """Build a snapshot for a single guided rule state.""" config = state.config assigned = len(state.assigned_bots) @@ -937,7 +937,7 @@ def _build_guided_state_snapshot(self, state: "GuidedTableRuleState") -> dict[st "unavailable_bots": unavailable, } - def _count_guided_availability(self, state: "GuidedTableRuleState") -> tuple[int, int]: + def _count_guided_availability(self, state: "GuidedTableState") -> tuple[int, int]: """Count guided bots waiting vs unavailable for a rule.""" waiting = 0 unavailable = 0 @@ -958,7 +958,7 @@ def _count_guided_availability(self, state: "GuidedTableRuleState") -> tuple[int return waiting, unavailable def _describe_guided_table( - self, state: "GuidedTableRuleState" + self, state: "GuidedTableState" ) -> tuple[str, str | None, int, int]: """Describe the guided table link and player counts.""" if not state.table_id: diff --git a/server/games/ageofheroes/bot.py b/server/games/ageofheroes/bot.py index f2cafae4..2b81287c 100644 --- a/server/games/ageofheroes/bot.py +++ b/server/games/ageofheroes/bot.py @@ -33,6 +33,7 @@ if TYPE_CHECKING: from .game import AgeOfHeroesGame, AgeOfHeroesPlayer + from .state import TribeState def bot_think(game: AgeOfHeroesGame, player: AgeOfHeroesPlayer) -> str | None: diff --git a/server/games/backgammon/game.py b/server/games/backgammon/game.py index bde2ab8c..afc5b328 100644 --- a/server/games/backgammon/game.py +++ b/server/games/backgammon/game.py @@ -5,6 +5,10 @@ import logging from dataclasses import dataclass, field import random +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from .gnubg import GnubgProcess log = logging.getLogger(__name__) diff --git a/server/games/chaosbear/game.py b/server/games/chaosbear/game.py index 96daf74d..a7f39ffb 100644 --- a/server/games/chaosbear/game.py +++ b/server/games/chaosbear/game.py @@ -406,7 +406,7 @@ def bot_think(self, player: ChaosBearPlayer) -> str | None: # Otherwise roll the dice return "roll_dice" - def _start_next_turn(self, previous_player: "ChaosPlayer | None" = None) -> None: + def _start_next_turn(self, previous_player: "ChaosBearPlayer | None" = None) -> None: """Start the next player's turn with menu rebuild and bot jolt. Args: diff --git a/server/games/sorry/game.py b/server/games/sorry/game.py index b2ec2f3a..db5e45a9 100644 --- a/server/games/sorry/game.py +++ b/server/games/sorry/game.py @@ -28,6 +28,7 @@ ) from .state import ( SorryGameState, + SorryPawnState, SorryPlayerState, build_initial_game_state, discard_current_card, diff --git a/server/tests/test_server_admin_virtual_bots.py b/server/tests/test_server_admin_virtual_bots.py index 8c448bbb..85f0a6c7 100644 --- a/server/tests/test_server_admin_virtual_bots.py +++ b/server/tests/test_server_admin_virtual_bots.py @@ -82,9 +82,6 @@ def clear_bots(self): self.cleared = True return 2, 0 - def save_state(self): - self.saved = True - def get_status(self): return {"online": 0, "total": 0, "offline": 0, "in_game": 0} diff --git a/server/tests/test_virtual_bots.py b/server/tests/test_virtual_bots.py index 229f5650..80c57499 100644 --- a/server/tests/test_virtual_bots.py +++ b/server/tests/test_virtual_bots.py @@ -1311,42 +1311,6 @@ def execute_action(self, player, action_id): assert table.game.actions == [("BotA", "start_game")] -def test_process_leaving_game_logout_branch(monkeypatch): - manager = VirtualBotManager(FakeServer()) - bot = VirtualBot("Leaf", state=VirtualBotState.LEAVING_GAME) - bot.logout_after_game = True - bot.online_ticks = 10 - bot.target_online_ticks = 999 - manager._bots["Leaf"] = bot - monkeypatch.setattr("server.core.virtual_bots.random.randint", lambda a, b: a) - - manager._process_leaving_game_bot(bot) - - assert bot.state == VirtualBotState.ONLINE_IDLE - assert bot.cooldown_ticks == manager._get_config_value(bot, "logout_after_game_min_ticks") - - -def test_process_leaving_game_offline_path(monkeypatch): - manager = VirtualBotManager(FakeServer()) - bot = VirtualBot("Leaf", state=VirtualBotState.LEAVING_GAME) - bot.logout_after_game = False - bot.online_ticks = 100 - bot.target_online_ticks = 50 - manager._bots["Leaf"] = bot - taken_offline = {} - - def fake_take(target_bot): - taken_offline["bot"] = target_bot - target_bot.state = VirtualBotState.OFFLINE - - monkeypatch.setattr(manager, "_take_bot_offline", fake_take) - - manager._process_leaving_game_bot(bot) - - assert taken_offline["bot"] is bot - assert bot.state == VirtualBotState.OFFLINE - - def test_on_tick_processes_all_bots(monkeypatch): manager = _make_single_bot_manager(["BotA", "BotB"]) calls = []