""" GameAdapterRegistry — singleton that holds all registered game adapters. Adapters register themselves at import time. """ from __future__ import annotations import logging logger = logging.getLogger(__name__) class GameAdapterRegistry: _adapters: dict[str, object] = {} # game_type -> GameAdapter @classmethod def register(cls, adapter) -> None: """Register a game adapter. Called at import time by each adapter package.""" if adapter.game_type in cls._adapters: logger.warning( "Adapter for '%s' already registered. Overwriting.", adapter.game_type ) cls._adapters[adapter.game_type] = adapter logger.info("Registered game adapter: %s (%s)", adapter.game_type, adapter.display_name) @classmethod def get(cls, game_type: str): """ Get adapter by game_type. Raises KeyError if not registered. Core code calls this whenever game-specific behavior is needed. """ adapter = cls._adapters.get(game_type) if adapter is None: raise KeyError( f"No adapter registered for game type '{game_type}'. " f"Available: {list(cls._adapters.keys())}" ) return adapter @classmethod def all(cls) -> list: """Return all registered adapters.""" return list(cls._adapters.values()) @classmethod def list_game_types(cls) -> list[dict]: """Return metadata list for API /games endpoint.""" result = [] for adapter in cls._adapters.values(): caps = [] for cap in [ "config_generator", "process_config", "log_parser", "remote_admin", "mission_manager", "mod_manager", "ban_manager", ]: if adapter.has_capability(cap): caps.append(cap) result.append({ "game_type": adapter.game_type, "display_name": adapter.display_name, "version": adapter.version, "capabilities": caps, }) return result @classmethod def is_registered(cls, game_type: str) -> bool: return game_type in cls._adapters