from typing import List, Optional, Dict, Any, Set from bemani.common import GameConstants, ValidatedDict, Parallel from bemani.data.api.base import BaseGlobalData from bemani.data.types import Item class GlobalGameData(BaseGlobalData): def __translate_sdvx_song_unlock(self, entry: Dict[str, Any]) -> Item: return Item( "song_unlock", int(entry["catalogid"]), { "musicid": int(entry["song"]), "chart": int(entry["chart"]), "blocks": int(entry["price"]), }, ) def __translate_sdvx_appealcard(self, entry: Dict[str, Any]) -> Item: return Item( "appealcard", int(entry["appealid"]), {}, ) def __translate_jubeat_emblems(self, entry: Dict[str, Any]) -> Item: return Item( "emblem", int(entry["index"]), { "music_id": int(entry["song"]), "layer": int(entry["layer"]), "evolved": int(entry["evolved"]), "rarity": int(entry["rarity"]), "name": entry["name"], }, ) def __translate_iidx_qpros(self, entry: Dict[str, Any]) -> Item: return Item( f'qp_{entry["type"]}', int(entry["id"]), { "identifier": entry["identifier"], "name": entry["name"], "type": entry["type"], } ) def get_items(self, game: GameConstants, version: int) -> List[Item]: """ Given a game/userid, find all items in the catalog. Parameters: game - Enum value identifier of the game looking up the catalog. version - Integer identifier of the version looking up this catalog. Returns: A list of item objects. """ catalogs: List[Dict[str, List[Dict[str, Any]]]] = Parallel.call( [client.get_catalog for client in self.clients], game, version ) retval: List[Item] = [] seen: Set[str] = set() for catalog in catalogs: for catalogtype in catalog: # Simple LUT for now, might need to be complicated later if game == GameConstants.SDVX: translation = { "purchases": self.__translate_sdvx_song_unlock, "appealcards": self.__translate_sdvx_appealcard, }.get(catalogtype, None) elif game == GameConstants.JUBEAT: translation = { "emblems": self.__translate_jubeat_emblems, }.get(catalogtype, None) elif game == GameConstants.IIDX: translation = { "qpros": self.__translate_iidx_qpros, }.get(catalogtype, None) else: translation = None # If we don't have a mapping for this, ignore it if translation is None: continue for entry in catalog[catalogtype]: # Translate the entry item = translation(entry) # Now, see if it is unique, and if so, remember it key = f"{item.type}_{item.id}" if key in seen: continue retval.append(item) seen.add(key) return retval def get_item(self, game: GameConstants, version: int, catid: int, cattype: str) -> Optional[ValidatedDict]: """ Given a game/userid and catalog id/type, find that catalog entry. Note that there can be more than one catalog entry with the same ID and game/userid as long as each one is a different type. Essentially, cattype namespaces catalog entry. Parameters: game - Enum value identifier of the game looking up this entry. version - Integer identifier of the version looking up this entry. catid - Integer ID, as provided by a game. cattype - The type of catalog entry. Returns: A dictionary as stored by a game class previously, or None if not found. """ all_items = self.get_items(game, version) for item in all_items: if item.id == catid and item.type == cattype: return item.data return None