Source code for yawning_titan.game_modes.game_mode_db
"""Provides an API for the ``game_mode.json`` TinyDB file, and a Schema class that defines the game_mode DB fields."""from__future__importannotationsimportosfromloggingimportgetLoggerfrompathlibimportPathfromtypingimportFinal,List,Optional,UnionfromtinydbimportTinyDBfromtinydb.queriesimportQueryInstancefromtinydb.tableimportDocumentfromyawning_titan.configimport_LIB_CONFIG_ROOT_PATHfromyawning_titan.db.compatibility_queryimport(EntryNodeCompatibilityQuery,HighValueNodeCompatibilityQuery,NetworkCompatibilityQuery,NetworkNodeCompatibilityQuery,)fromyawning_titan.db.doc_metadataimportDocMetadata,DocMetadataSchemafromyawning_titan.db.queryimportYawningTitanQueryfromyawning_titan.db.schemasimportGameModeConfigurationSchemafromyawning_titan.db.yawning_titan_dbimportYawningTitanDBfromyawning_titan.game_modes.game_modeimportGameMode__all__=["GameModeDB","GameModeSchema"]_LOGGER=getLogger(__name__)
[docs]classGameModeSchema:""" A schema-like class that defines the game_mode DB fields. Fields are defined using the :class:`~yawning_titan.db.query.YawningTitanQuery` class so that schema paths can be used directly within :func:`tinydb.table.Table.search` function calls. All fields are mapped to a property in the :class:~`yawning_titan.game_modes.game_mode.GameMode` class. :Example: >>> from yawning_titan.game_modes.game_mode_db import GameModeDB, GameModeSchema >>> db = GameModeDB() >>> game_modes = db.search(GameModeSchema.NODE_COUNT.min(18)) """NETWORK_NODES:Final[NetworkNodeCompatibilityQuery]=NetworkNodeCompatibilityQuery().game_rules.network_compatibility.node_count"""Mapped to :attr:`~yawning_titan.game_modes.game_mode.GameMode.game_rules.network_compatibility.node_count`."""ENTRY_NODES:Final[EntryNodeCompatibilityQuery]=EntryNodeCompatibilityQuery().game_rules.network_compatibility.entry_node_count"""Mapped to :attr:`~yawning_titan.game_modes.game_mode.GameMode.game_rules.network_compatibility.entry_node_count``."""HIGH_VALUE_NODES:Final[HighValueNodeCompatibilityQuery]=(HighValueNodeCompatibilityQuery().game_rules.network_compatibility.high_value_node_count)"""Mapped to :attr:`~yawning_titan.game_modes.game_mode.GameMode.game_rules.network_compatibility.high_value_node_count`."""NETWORK_COMPATIBILITY:Final[NetworkCompatibilityQuery]=NetworkCompatibilityQuery().game_rules.network_compatibility"""Mapped to :attr:`~yawning_titan.game_modes.game_mode.GameMode.game_rules.network_compatibility`."""CONFIGURATION:Final[GameModeConfigurationSchema]=GameModeConfigurationSchema"""Use this to access the full schema of the database structured in the same nested format as :class:~`yawning_titan.game_modes.game_mode.GameMode`."""
[docs]classGameModeDB:""" The :class:`~yawning_titan.config.game_modes.GameModeDB` class extends :class:`~yawning_titan.db.YawningTitanDB`. The below code blocks demonstrate how to use the :class:`~yawning_titan.config.game_modes.GameModeDB` class. - Instantiate the GameMode DB: .. code:: python >>> from yawning_titan.game_modes.game_mode_db import GameModeDB, GameModeSchema >>> db = GameModeDB() - Search for all game modes that work with a minimum of 18 nodes in the game_mode: .. code:: python >>> db.search(GameModeSchema.NODE_COUNT.min(18)) """
def__enter__(self)->GameModeDB:returnGameModeDB()def__exit__(self,exc_type,exc_val,exc_tb):self._db.__exit__(exc_type,exc_val,exc_tb)@classmethoddef_doc_to_game_mode(cls,doc:Document):"""Convert the document. Converts a :class:`tinydb.table.Document` from the :class:`~yawning_titan.config.game_modes.GameModeDB` to an instance of :class:~yawning_titan.game_modes.game_mode.GameMode`. :param doc: A :class:`tinydb.table.Document`. :return: The doc as a :class:`~yawning_titan.game_modes.game_mode.GameMode`. """doc["_doc_metadata"]=DocMetadata(**doc["_doc_metadata"])game_mode:GameMode=GameMode()game_mode.set_from_dict(doc)returngame_mode
[docs]definsert(self,game_mode:GameMode,name:Optional[str]=None,description:Optional[str]=None,author:Optional[str]=None,)->GameMode:""" Insert a :class:`~yawning_titan.game_modes.game_mode.GameMode` into the DB as ``.json``. :param game_mode: An instance of :class:`~yawning_titan.game_modes.game_mode.GameMode` :class:`~yawning_titan.db.doc_metadata.DocMetadata`. :class:`~yawning_titan.db.doc_metadata.DocMetadata`. :class:`~yawning_titan.db.doc_metadata.DocMetadata`. :param name: The config name. :param description: The config description. :param author: The config author. :return: The inserted :class:`~yawning_titan.game_modes.game_mode.GameMode`. """game_mode.doc_metadata.update(name,description,author)self._db.insert(game_mode.to_dict(json_serializable=True,include_none=True,values_only=True))returngame_mode
[docs]defall(self)->List[GameMode]:""" Get all :class:`~yawning_titan.game_modes.game_mode.GameMode` from the game mode DB. :return: A :class:`list` of :class:`~yawning_titan.game_modes.game_mode.GameMode`. """return[self._doc_to_game_mode(doc)fordocinself._db.all()]
[docs]defshow(self,verbose=False):""" Show details of all entries in the db. :param verbose: If True, all doc metadata details are shown, otherwise just the name is shown. """self._db.show(verbose)
[docs]defget(self,uuid:str)->Union[GameMode,None]:""" Get a game_mode config document from its uuid. :param uuid: A target document uuid. :return: The game_mode config document as an instance of :class:~yawning_titan.game_modes.game_mode.GameMode` if the uuid exists, otherwise :class:`None`. """# self._db.db.clear_cache()doc=self._db.get(uuid)ifdoc:returnself._doc_to_game_mode(doc)returnNone
[docs]defsearch(self,query:YawningTitanQuery)->List[GameMode]:""" Searches the :class:`~yawning_titan.game_modes.game_mode.GameMode` with a :class:`GameModeSchema` query. :param query: A :class:`~yawning_titan.db.query.YawningTitanQuery`. :return: A :class:`list` of :class:`~yawning_titan.game_modes.game_mode.GameMode`. """game_mode_configs=[]fordocinself._db.search(query):game_mode_configs.append(self._doc_to_game_mode(doc))returngame_mode_configs
[docs]defcount(self,cond:Optional[QueryInstance]=None)->int:""" Count how many docs are in the db. Extends :class:`tinydb.table.Table.count`. A :class:`~yawning_titan.db.query.YawningTitanQuery` can be used to filter the count. :param cond: An optional :class:`~yawning_titan.db.query.YawningTitanQuery`. Has a default value of ``None``. :return: The number of docs counted. """ifcond:returnself._db.count(cond)returnlen(self._db.all())
[docs]defupdate(self,game_mode:GameMode,name:Optional[str]=None,description:Optional[str]=None,author:Optional[str]=None,)->GameMode:""" Update a :class:`~yawning_titan.game_modes.game_mode.GameMode`. in the db. :param game_mode: An instance of :class:`~yawning_titan.game_modes.game_mode.GameMode`. :param name: The config name. :param description: The config description. :param author: The config author. :return: The updated :class:`~yawning_titan.game_modes.game_mode.GameMode`. """# Update the configs metadatagame_mode.doc_metadata.update(name,description,author)# Perform the update and retrieve the returned docdoc=self._db.update(game_mode.to_dict(json_serializable=True),game_mode.doc_metadata.uuid,name,description,author,)ifdoc:# Update the configs metadata created atgame_mode.doc_metadata.updated_at=doc["_doc_metadata"]["updated_at"]returngame_mode
[docs]defupsert(self,game_mode:GameMode,name:Optional[str]=None,description:Optional[str]=None,author:Optional[str]=None,)->GameMode:""" Upsert a :class:`~yawning_titan.game_modes.game_mode.GameMode`. in the db. :param game_mode: An instance of :class:`~yawning_titan.game_modes.game_mode.GameMode`. :param name: The config name. :param description: The config description. :param author: The config author. :return: The upserted :class:`~yawning_titan.game_modes.game_mode.GameMode`. """game_mode.doc_metadata.update(name,description,author)doc=self._db.upsert(game_mode.to_dict(json_serializable=True),game_mode.doc_metadata.uuid,name,description,author,)# Update the configs metadata created atifdocand"updated_at"indoc["_doc_metadata"]:game_mode.doc_metadata.updated_at=doc["_doc_metadata"]["updated_at"]returngame_mode
[docs]defremove(self,game_mode:GameMode)->Union[str,None]:""" Remove a :class:`~yawning_titan.game_modes.game_mode.GameMode`. from the db. :param game_mode: An instance of :class:`~yawning_titan.game_modes.game_mode.GameMode`. :return: The uuid of the removed :class:`~yawning_titan.game_modes.game_mode.GameMode`. """returnself._db.remove(game_mode.doc_metadata.uuid)
[docs]defremove_by_cond(self,cond:QueryInstance)->List[str]:""" Remove :class:`~yawning_titan.game_modes.game_mode.GameMode`. from the db that match the query. :param cond: A :class:`~yawning_titan.db.query.YawningTitanQuery`. :return: The list of uuids of the removed :class:`~yawning_titan.game_modes.game_mode.GameMode`. """returnself._db.remove_by_cond(cond)
[docs]defreset_default_game_modes_in_db(self,force=False):""" Reset the default game_mode in the db. Achieves this by loading the default `yawning_titan/game_modes/_package_data/game_mode.json` db file into TinyDB, then iterating over all docs and forcing an update of each one in the main game_modes db from its uuid if they do not match. :param force: Forces a reset without checking for equality when True. Has a default value of False. """# Obtain the path to the default db file in package dataself._db.db.clear_cache()game_mode_root=Path(__file__).parent.resolve()default_game_mode_path=os.path.join(game_mode_root,"_package_data","game_modes.json")# Load the default db file into TinyDBdefault_db=TinyDB(default_game_mode_path)# Iterate over all default game_modes, and force an update in the# main GameModeDB by uuid.forgame_modeindefault_db.all():uuid=game_mode["_doc_metadata"]["uuid"]name=game_mode["_doc_metadata"]["name"]# Get the matching game_mode from the game_modes dbtry:db_game_mode=self.get(uuid)exceptKeyError:db_game_mode=None# If the game_mode doesn't match the default, or it doesn't exist,# perform an upsert.ifnotforceanddb_game_mode:reset=Falseelse:reset=Trueifreset:self._db.db.upsert(game_mode,DocMetadataSchema.UUID==uuid)_LOGGER.info(f"Reset default game_mode '{name}' in the "f"{self._db.name} db with uuid='{uuid}'.")# Clear the default db cache and close the file.default_db.clear_cache()default_db.close()
[docs]defrebuild_db(self):""" Rebuild the db. Actions taken: - clear the query cache - truncate the db - call :func:`~yawning_titan.game_modes.game_mode_db.GameModeDB.reset_default_game_modes_in_db` .. warning:: This function completely rebuilds the database. Any custom game_modes saved in the db will be lost. The default game_modes can be reset using the :func:`~yawning_titan.game_modes.game_mode_db.GameModeDB.reset_default_game_modes_in_db` function. """_LOGGER.info(f"Rebuilding the {self._db.name} db.")self._db.db.clear_cache()self._db.db.truncate()self.reset_default_game_modes_in_db()
[docs]defadd_yaml_game_modes_to_db(self,directory:Path=None):"""Add all yaml game modes in a given directory to the database. :param directory: The directory containing the files to add as a Path. """ifdirectoryisNone:directory=_LIB_CONFIG_ROOT_PATH/"_package_data"/"game_modes"forgame_mode_pathindirectory.iterdir():game_mode=GameMode()game_mode.set_from_yaml(game_mode_path,infer_legacy=True)self.insert(game_mode,name=game_mode_path.stem)
[docs]defdefault_game_mode()->GameMode:""" The default Yawning Titan game mode. :return: An instance of :class:`~yawning_titan.game_modes.game_mode.GameMode`. """withGameModeDB()asdb:returndb.get("900a704f-6271-4994-ade7-40b74d3199b1")
[docs]defdcbo_game_mode()->GameMode:""" The DCBO game mode. :return: An instance of :class:`~yawning_titan.game_modes.game_mode.GameMode`. """withGameModeDB()asdb:returndb.get("bac2cb9d-b24b-426c-88a5-5edd0c2de4131")