mirror of
https://github.com/baiqwerdvd/ArknightsUID.git
synced 2025-05-05 03:23:45 +08:00
✨ 更好的 StoreService
This commit is contained in:
parent
6ce4d3e590
commit
ab3caab461
@ -1,3 +1,4 @@
|
|||||||
|
import asyncio
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from gsuid_core.bot import Bot
|
from gsuid_core.bot import Bot
|
||||||
@ -7,7 +8,7 @@ from gsuid_core.models import Event
|
|||||||
from gsuid_core.sv import SV
|
from gsuid_core.sv import SV
|
||||||
|
|
||||||
from ..utils.resource.download_all_resource import download_all_resource
|
from ..utils.resource.download_all_resource import download_all_resource
|
||||||
from .cachedata import CacheData
|
from .memoryStore import store
|
||||||
from .constants import Excel
|
from .constants import Excel
|
||||||
|
|
||||||
sv_download_config = SV('下载资源', pm=2)
|
sv_download_config = SV('下载资源', pm=2)
|
||||||
@ -25,9 +26,11 @@ async def startup():
|
|||||||
await download_all_resource()
|
await download_all_resource()
|
||||||
logger.info('[资源文件下载] 检查完毕, 正在加载 gamedata')
|
logger.info('[资源文件下载] 检查完毕, 正在加载 gamedata')
|
||||||
|
|
||||||
|
tasks = []
|
||||||
for file_path in Path(
|
for file_path in Path(
|
||||||
get_res_path(['ArknightsUID', 'resource', 'gamedata'])
|
get_res_path(['ArknightsUID', 'resource', 'gamedata'])
|
||||||
).rglob('*.json'):
|
).rglob('*.json'):
|
||||||
CacheData.readFile(file_path)
|
tasks.append(store.get_file(Path(file_path)))
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
Excel.preload_table()
|
await Excel.preload_table()
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
import json
|
|
||||||
from functools import cache
|
|
||||||
from pathlib import Path
|
|
||||||
from time import time
|
|
||||||
from typing import Any, ClassVar, Dict, Union
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from ..utils.file import read_json
|
|
||||||
|
|
||||||
|
|
||||||
class StoreData:
|
|
||||||
data: Dict[Any, Any]
|
|
||||||
modification_time: float
|
|
||||||
|
|
||||||
def __init__(self, data: Dict[Any, Any], modification_time: float) -> None:
|
|
||||||
self.data = data
|
|
||||||
self.modification_time = modification_time
|
|
||||||
|
|
||||||
|
|
||||||
class CacheData:
|
|
||||||
cached_data: ClassVar[Dict[str, StoreData]] = {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@cache
|
|
||||||
def get_cache(cls, local_path: Path) -> Dict[Any, Any]:
|
|
||||||
data_name = local_path.stem
|
|
||||||
if data_name in cls.cached_data:
|
|
||||||
current_modification_time = local_path.stat().st_mtime
|
|
||||||
if current_modification_time == cls.cached_data[data_name].modification_time:
|
|
||||||
return cls.cached_data[data_name].data
|
|
||||||
return cls.set_cache(local_path, data_name)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def set_cache(
|
|
||||||
cls, local_path: Union[Path, None], data_name: str, memory_data: Union[Dict, None] = None
|
|
||||||
) -> Dict[Any, Any]:
|
|
||||||
data = read_json(local_path) if local_path else memory_data
|
|
||||||
if data is None:
|
|
||||||
raise FileNotFoundError
|
|
||||||
modification_time = local_path.stat().st_mtime if local_path else time()
|
|
||||||
cls.cached_data[data_name] = StoreData(data, modification_time)
|
|
||||||
return cls.cached_data[data_name].data
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def readFile(cls, local_path: Path) -> Dict[Any, Any]:
|
|
||||||
try:
|
|
||||||
if isinstance(local_path, str):
|
|
||||||
local_path = Path(local_path)
|
|
||||||
return cls.get_cache(local_path)
|
|
||||||
except json.decoder.JSONDecodeError as e:
|
|
||||||
logger.error(f'Could not load file "{local_path}".')
|
|
||||||
raise FileNotFoundError from e
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def readExcel(cls, table_name: str) -> Dict[Any, Any]:
|
|
||||||
logger.debug(f'loading: {table_name}.json')
|
|
||||||
if table_name not in cls.cached_data:
|
|
||||||
return {}
|
|
||||||
return cls.cached_data[table_name].data
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def readBytesExcel(cls, table_name: str) -> bytes:
|
|
||||||
logger.debug(f'loading: {table_name}.json')
|
|
||||||
if table_name not in cls.cached_data:
|
|
||||||
return bytes({})
|
|
||||||
return json.dumps(cls.cached_data[table_name].data).encode('utf-8')
|
|
@ -1,14 +1,13 @@
|
|||||||
|
import asyncio
|
||||||
import inspect
|
import inspect
|
||||||
from typing import Dict, Union
|
|
||||||
from msgspec import json as msgjson
|
|
||||||
|
|
||||||
from ..utils.models.gamedata.ActivityTable import ActivityTable
|
from ..utils.models.gamedata.ActivityTable import ActivityTable
|
||||||
from ..utils.models.gamedata.AudioData import AudioData
|
from ..utils.models.gamedata.AudioData import AudioData
|
||||||
from ..utils.models.gamedata.BattleEquipTable import BattleEquipData
|
from ..utils.models.gamedata.BattleEquipTable import BattleEquipTable
|
||||||
from ..utils.models.gamedata.BuildingData import BuildingData
|
from ..utils.models.gamedata.BuildingData import BuildingData
|
||||||
from ..utils.models.gamedata.CampaignTable import CampaignTable
|
from ..utils.models.gamedata.CampaignTable import CampaignTable
|
||||||
from ..utils.models.gamedata.ChapterTable import ChapterData
|
from ..utils.models.gamedata.ChapterTable import ChapterTable
|
||||||
from ..utils.models.gamedata.CharacterTable import CharacterData
|
from ..utils.models.gamedata.CharacterTable import CharacterTable
|
||||||
from ..utils.models.gamedata.CharMetaTable import CharMetaTable
|
from ..utils.models.gamedata.CharMetaTable import CharMetaTable
|
||||||
from ..utils.models.gamedata.CharmTable import CharmTable
|
from ..utils.models.gamedata.CharmTable import CharmTable
|
||||||
from ..utils.models.gamedata.CharPatchTable import CharPatchTable
|
from ..utils.models.gamedata.CharPatchTable import CharPatchTable
|
||||||
@ -24,474 +23,516 @@ from ..utils.models.gamedata.GachaTable import GachaTable
|
|||||||
from ..utils.models.gamedata.GamedataConst import GamedataConst
|
from ..utils.models.gamedata.GamedataConst import GamedataConst
|
||||||
from ..utils.models.gamedata.HandbookInfoTable import HandbookInfoTable
|
from ..utils.models.gamedata.HandbookInfoTable import HandbookInfoTable
|
||||||
from ..utils.models.gamedata.HandbookTable import HandbookTable
|
from ..utils.models.gamedata.HandbookTable import HandbookTable
|
||||||
from ..utils.models.gamedata.HandbookTeamTable import HandbookTeam
|
from ..utils.models.gamedata.HandbookTeamTable import HandbookTeamTable
|
||||||
from ..utils.models.gamedata.ItemTable import ItemTable
|
from ..utils.models.gamedata.ItemTable import ItemTable
|
||||||
from ..utils.models.gamedata.MedalTable import MedalTable
|
from ..utils.models.gamedata.MedalTable import MedalTable
|
||||||
from ..utils.models.gamedata.MissionTable import MissionTable
|
from ..utils.models.gamedata.MissionTable import MissionTable
|
||||||
from ..utils.models.gamedata.OpenServerTable import OpenServerTable
|
from ..utils.models.gamedata.OpenServerTable import OpenServerTable
|
||||||
from ..utils.models.gamedata.PlayerAvatarTable import PlayerAvatarTable
|
from ..utils.models.gamedata.PlayerAvatarTable import PlayerAvatarTable
|
||||||
from ..utils.models.gamedata.RangeTable import Stage
|
from ..utils.models.gamedata.RangeTable import RangeTable
|
||||||
from ..utils.models.gamedata.ReplicateTable import ReplicateList
|
from ..utils.models.gamedata.ReplicateTable import ReplicateTable
|
||||||
from ..utils.models.gamedata.RetroTable import RetroTable
|
from ..utils.models.gamedata.RetroTable import RetroTable
|
||||||
from ..utils.models.gamedata.RoguelikeTable import RoguelikeTable
|
from ..utils.models.gamedata.RoguelikeTable import RoguelikeTable
|
||||||
from ..utils.models.gamedata.RoguelikeTopicTable import RoguelikeTopicTable
|
from ..utils.models.gamedata.RoguelikeTopicTable import RoguelikeTopicTable
|
||||||
from ..utils.models.gamedata.SandboxTable import SandboxTable
|
from ..utils.models.gamedata.SandboxTable import SandboxTable
|
||||||
from ..utils.models.gamedata.ShopClientTable import ShopClientTable
|
from ..utils.models.gamedata.ShopClientTable import ShopClientTable
|
||||||
from ..utils.models.gamedata.SkillTable import SkillDataBundle
|
from ..utils.models.gamedata.SkillTable import SkillTable
|
||||||
from ..utils.models.gamedata.SkinTable import SkinTable
|
from ..utils.models.gamedata.SkinTable import SkinTable
|
||||||
from ..utils.models.gamedata.StageTable import StageTable
|
from ..utils.models.gamedata.StageTable import StageTable
|
||||||
from ..utils.models.gamedata.StoryReviewMetaTable import StoryReviewMetaTable
|
from ..utils.models.gamedata.StoryReviewMetaTable import StoryReviewMetaTable
|
||||||
from ..utils.models.gamedata.StoryReviewTable import StoryReviewGroupClientData
|
from ..utils.models.gamedata.StoryReviewTable import StoryReviewTable
|
||||||
from ..utils.models.gamedata.StoryTable import StoryData
|
from ..utils.models.gamedata.StoryTable import StoryTable
|
||||||
from ..utils.models.gamedata.TechBuffTable import TechBuffTable
|
from ..utils.models.gamedata.TechBuffTable import TechBuffTable
|
||||||
from ..utils.models.gamedata.TipTable import TipTable
|
from ..utils.models.gamedata.TipTable import TipTable
|
||||||
from ..utils.models.gamedata.TokenTable import TokenCharacterData
|
from ..utils.models.gamedata.TokenTable import TokenTable
|
||||||
from ..utils.models.gamedata.UniequipData import UniequipData
|
from ..utils.models.gamedata.UniequipData import UniequipData
|
||||||
from ..utils.models.gamedata.UniequipTable import UniEquipTable
|
from ..utils.models.gamedata.UniequipTable import UniEquipTable
|
||||||
from ..utils.models.gamedata.ZoneTable import ZoneTable
|
from ..utils.models.gamedata.ZoneTable import ZoneTable
|
||||||
from .cachedata import CacheData
|
from .memoryStore import store
|
||||||
|
|
||||||
|
|
||||||
class ExcelTableManager:
|
class ExcelTableManager:
|
||||||
activity_table_: Union[ActivityTable, None] = None
|
activity_table_: ActivityTable
|
||||||
audio_data_: Union[AudioData, None] = None
|
audio_data_: AudioData
|
||||||
battle_equip_table_: Union[Dict[str, BattleEquipData], None] = None
|
battle_equip_table_: BattleEquipTable
|
||||||
building_data_: Union[BuildingData, None] = None
|
building_data_: BuildingData
|
||||||
campaign_table_: Union[CampaignTable, None] = None
|
campaign_table_: CampaignTable
|
||||||
chapter_table_: Union[Dict[str, ChapterData], None] = None
|
chapter_table_: ChapterTable
|
||||||
character_table_: Union[Dict[str, CharacterData], None] = None
|
character_table_: CharacterTable
|
||||||
char_meta_table_: Union[CharMetaTable, None] = None
|
char_meta_table_: CharMetaTable
|
||||||
charm_table_: Union[CharmTable, None] = None
|
charm_table_: CharmTable
|
||||||
char_patch_table_: Union[CharPatchTable, None] = None
|
char_patch_table_: CharPatchTable
|
||||||
charword_table_: Union[CharwordTable, None] = None
|
charword_table_: CharwordTable
|
||||||
checkin_table_: Union[CheckinTable, None] = None
|
checkin_table_: CheckinTable
|
||||||
climb_tower_table_: Union[ClimbTowerTable, None] = None
|
climb_tower_table_: ClimbTowerTable
|
||||||
clue_data_: Union[ClueData, None] = None
|
clue_data_: ClueData
|
||||||
crisis_table_: Union[CrisisTable, None] = None
|
crisis_table_: CrisisTable
|
||||||
display_meta_table_: Union[DisplayMetaTable, None] = None
|
display_meta_table_: DisplayMetaTable
|
||||||
enemy_handbook_table_: Union[EnemyHandbookTable, None] = None
|
enemy_handbook_table_: EnemyHandbookTable
|
||||||
favor_table_: Union[FavorTable, None] = None
|
favor_table_: FavorTable
|
||||||
gacha_table_: Union[GachaTable, None] = None
|
gacha_table_: GachaTable
|
||||||
gamedata_const_: Union[GamedataConst, None] = None
|
gamedata_const_: GamedataConst
|
||||||
handbook_info_table_: Union[HandbookInfoTable, None] = None
|
handbook_info_table_: HandbookInfoTable
|
||||||
handbook_table_: Union[HandbookTable, None] = None
|
handbook_table_: HandbookTable
|
||||||
handbook_team_table_: Union[Dict[str, HandbookTeam], None] = None
|
handbook_team_table_: HandbookTeamTable
|
||||||
item_table_: Union[ItemTable, None] = None
|
item_table_: ItemTable
|
||||||
medal_table_: Union[MedalTable, None] = None
|
medal_table_: MedalTable
|
||||||
mission_table_: Union[MissionTable, None] = None
|
mission_table_: MissionTable
|
||||||
open_server_table_: Union[OpenServerTable, None] = None
|
open_server_table_: OpenServerTable
|
||||||
player_avatar_table_: Union[PlayerAvatarTable, None] = None
|
player_avatar_table_: PlayerAvatarTable
|
||||||
range_table_: Union[Dict[str, Stage], None] = None
|
range_table_: RangeTable
|
||||||
replicate_table_: Union[Dict[str, ReplicateList], None] = None
|
replicate_table_: ReplicateTable
|
||||||
retro_table_: Union[RetroTable, None] = None
|
retro_table_: RetroTable
|
||||||
roguelike_table_: Union[RoguelikeTable, None] = None
|
roguelike_table_: RoguelikeTable
|
||||||
roguelike_topic_table_: Union[RoguelikeTopicTable, None] = None
|
roguelike_topic_table_: RoguelikeTopicTable
|
||||||
sandbox_table_: Union[SandboxTable, None] = None
|
sandbox_table_: SandboxTable
|
||||||
shop_client_table_: Union[ShopClientTable, None] = None
|
shop_client_table_: ShopClientTable
|
||||||
skill_table_: Union[Dict[str, SkillDataBundle], None] = None
|
skill_table_: SkillTable
|
||||||
skin_table_: Union[SkinTable, None] = None
|
skin_table_: SkinTable
|
||||||
stage_table_: Union[StageTable, None] = None
|
stage_table_: StageTable
|
||||||
story_review_meta_table_: Union[StoryReviewMetaTable, None] = None
|
story_review_meta_table_: StoryReviewMetaTable
|
||||||
story_review_table_: Union[Dict[str, StoryReviewGroupClientData], None] = None
|
story_review_table_: StoryReviewTable
|
||||||
story_table_: Union[Dict[str, StoryData], None] = None
|
story_table_: StoryTable
|
||||||
tech_buff_table_: Union[TechBuffTable, None] = None
|
tech_buff_table_: TechBuffTable
|
||||||
tip_table_: Union[TipTable, None] = None
|
tip_table_: TipTable
|
||||||
token_table_: Union[Dict[str, TokenCharacterData], None] = None
|
token_table_: TokenTable
|
||||||
uniequip_data_: Union[UniequipData, None] = None
|
uniequip_data_: UniequipData
|
||||||
uniequip_table_: Union[UniEquipTable, None] = None
|
uniequip_table_: UniEquipTable
|
||||||
zone_table_: Union[ZoneTable, None] = None
|
zone_table_: ZoneTable
|
||||||
|
|
||||||
|
async def activity_table(self) -> None:
|
||||||
|
self.activity_table_ = ActivityTable.convert(
|
||||||
|
await store.get_excel("activity_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ACTIVITY_TABLE(self) -> ActivityTable:
|
def ACTIVITY_TABLE(self) -> ActivityTable:
|
||||||
if not self.activity_table_:
|
|
||||||
self.activity_table_ = ActivityTable.convert(
|
|
||||||
CacheData.readExcel('activity_table')
|
|
||||||
)
|
|
||||||
return self.activity_table_
|
return self.activity_table_
|
||||||
|
|
||||||
|
async def audio_data(self) -> None:
|
||||||
|
self.audio_data_ = AudioData.convert(
|
||||||
|
await store.get_excel("audio_data")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def AUDIO_DATA(self) -> AudioData:
|
def AUDIO_DATA(self) -> AudioData:
|
||||||
if not self.audio_data_:
|
|
||||||
self.audio_data_ = AudioData.convert(
|
|
||||||
CacheData.readExcel('audio_data')
|
|
||||||
)
|
|
||||||
return self.audio_data_
|
return self.audio_data_
|
||||||
|
|
||||||
|
async def battle_equip_table(self) -> None:
|
||||||
|
self.battle_equip_table_ = BattleEquipTable.convert(
|
||||||
|
{"equips": await store.get_excel("battle_equip_table")}
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def BATTLE_EQUIP_TABLE(self) -> Dict[str, BattleEquipData]:
|
def BATTLE_EQUIP_TABLE(self) -> BattleEquipTable:
|
||||||
if not self.battle_equip_table_:
|
|
||||||
self.battle_equip_table_ = msgjson.decode(
|
|
||||||
CacheData.readBytesExcel('battle_equip_table'),
|
|
||||||
type=Dict[str, BattleEquipData]
|
|
||||||
)
|
|
||||||
return self.battle_equip_table_
|
return self.battle_equip_table_
|
||||||
|
|
||||||
|
async def building_data(self) -> None:
|
||||||
|
self.building_data_ = BuildingData.convert(
|
||||||
|
await store.get_excel("building_data")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def BUILDING_DATA(self) -> BuildingData:
|
def BUILDING_DATA(self) -> BuildingData:
|
||||||
if not self.building_data_:
|
|
||||||
self.building_data_ = BuildingData.convert(
|
|
||||||
CacheData.readExcel('building_data')
|
|
||||||
)
|
|
||||||
return self.building_data_
|
return self.building_data_
|
||||||
|
|
||||||
|
async def campaign_table(self) -> None:
|
||||||
|
self.campaign_table_ = CampaignTable.convert(
|
||||||
|
await store.get_excel("campaign_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CAMPAIGN_TABLE(self) -> CampaignTable:
|
def CAMPAIGN_TABLE(self) -> CampaignTable:
|
||||||
if not self.campaign_table_:
|
|
||||||
self.campaign_table_ = CampaignTable.convert(
|
|
||||||
CacheData.readExcel('campaign_table')
|
|
||||||
)
|
|
||||||
return self.campaign_table_
|
return self.campaign_table_
|
||||||
|
|
||||||
@property
|
async def chapter_table(self) -> None:
|
||||||
def CHAPTER_TABLE(self) -> Dict[str, ChapterData]:
|
self.chapter_table_ = ChapterTable.convert(
|
||||||
if not self.chapter_table_:
|
{"chapters": await store.get_excel("chapter_table")}
|
||||||
self.chapter_table_ = msgjson.decode(
|
)
|
||||||
CacheData.readBytesExcel('chapter_table'),
|
|
||||||
type=Dict[str, ChapterData]
|
|
||||||
)
|
|
||||||
return self.chapter_table_
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CHARATER_TABLE(self) -> Dict[str, CharacterData]:
|
def CHAPTER_TABLE(self) -> ChapterTable:
|
||||||
if not self.character_table_:
|
return self.chapter_table_
|
||||||
self.character_table_ = msgjson.decode(
|
|
||||||
CacheData.readBytesExcel('character_table'),
|
async def character_table(self) -> None:
|
||||||
type=Dict[str, CharacterData]
|
self.character_table_ = CharacterTable.convert(
|
||||||
)
|
{"chars": await store.get_excel("character_table")}
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def CHARATER_TABLE(self) -> CharacterTable:
|
||||||
return self.character_table_
|
return self.character_table_
|
||||||
|
|
||||||
|
async def char_meta_table(self) -> None:
|
||||||
|
self.char_meta_table_ = CharMetaTable.convert(
|
||||||
|
await store.get_excel("char_meta_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CHAR_META_TABLE(self) -> CharMetaTable:
|
def CHAR_META_TABLE(self) -> CharMetaTable:
|
||||||
if not self.char_meta_table_:
|
|
||||||
self.char_meta_table_ = CharMetaTable.convert(
|
|
||||||
CacheData.readExcel('char_meta_table')
|
|
||||||
)
|
|
||||||
return self.char_meta_table_
|
return self.char_meta_table_
|
||||||
|
|
||||||
|
async def charm_table(self) -> None:
|
||||||
|
self.charm_table_ = CharmTable.convert(
|
||||||
|
await store.get_excel("charm_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CHARM_TABLE(self) -> CharmTable:
|
def CHARM_TABLE(self) -> CharmTable:
|
||||||
if not self.charm_table_:
|
|
||||||
self.charm_table_ = CharmTable.convert(
|
|
||||||
CacheData.readExcel('charm_table')
|
|
||||||
)
|
|
||||||
return self.charm_table_
|
return self.charm_table_
|
||||||
|
|
||||||
|
async def char_patch_table(self) -> None:
|
||||||
|
self.char_patch_table_ = CharPatchTable.convert(
|
||||||
|
await store.get_excel("char_patch_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CHAR_PATH_TABLE(self) -> CharPatchTable:
|
def CHAR_PATH_TABLE(self) -> CharPatchTable:
|
||||||
if not self.char_patch_table_:
|
|
||||||
self.char_patch_table_ = CharPatchTable.convert(
|
|
||||||
CacheData.readExcel('char_patch_table')
|
|
||||||
)
|
|
||||||
return self.char_patch_table_
|
return self.char_patch_table_
|
||||||
|
|
||||||
|
async def charword_table(self) -> None:
|
||||||
|
self.charword_table_ = CharwordTable.convert(
|
||||||
|
await store.get_excel("charword_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CHARWORD_TABLE(self) -> CharwordTable:
|
def CHARWORD_TABLE(self) -> CharwordTable:
|
||||||
if not self.charword_table_:
|
|
||||||
self.charword_table_ = CharwordTable.convert(
|
|
||||||
CacheData.readExcel('charword_table')
|
|
||||||
)
|
|
||||||
return self.charword_table_
|
return self.charword_table_
|
||||||
|
|
||||||
|
async def checkin_table(self) -> None:
|
||||||
|
self.checkin_table_ = CheckinTable.convert(
|
||||||
|
await store.get_excel("checkin_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CHECKIN_TABLE(self) -> CheckinTable:
|
def CHECKIN_TABLE(self) -> CheckinTable:
|
||||||
if not self.checkin_table_:
|
|
||||||
self.checkin_table_ = CheckinTable.convert(
|
|
||||||
CacheData.readExcel('checkin_table')
|
|
||||||
)
|
|
||||||
return self.checkin_table_
|
return self.checkin_table_
|
||||||
|
|
||||||
|
async def climb_tower_table(self) -> None:
|
||||||
|
self.climb_tower_table_ = ClimbTowerTable.convert(
|
||||||
|
await store.get_excel("climb_tower_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CLIMB_TOWER_TABLE(self) -> ClimbTowerTable:
|
def CLIMB_TOWER_TABLE(self) -> ClimbTowerTable:
|
||||||
if not self.climb_tower_table_:
|
|
||||||
self.climb_tower_table_ = ClimbTowerTable.convert(
|
|
||||||
CacheData.readExcel('climb_tower_table')
|
|
||||||
)
|
|
||||||
return self.climb_tower_table_
|
return self.climb_tower_table_
|
||||||
|
|
||||||
|
async def clue_data(self) -> None:
|
||||||
|
self.clue_data_ = ClueData.convert(
|
||||||
|
await store.get_excel("clue_data")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CLUE_DATA(self) -> ClueData:
|
def CLUE_DATA(self) -> ClueData:
|
||||||
if not self.clue_data_:
|
|
||||||
self.clue_data_ = ClueData.convert(
|
|
||||||
CacheData.readExcel('clue_data')
|
|
||||||
)
|
|
||||||
return self.clue_data_
|
return self.clue_data_
|
||||||
|
|
||||||
|
async def crisis_table(self) -> None:
|
||||||
|
self.crisis_table_ = CrisisTable.convert(
|
||||||
|
await store.get_excel("crisis_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def CRISIS_TABLE(self) -> CrisisTable:
|
def CRISIS_TABLE(self) -> CrisisTable:
|
||||||
if not self.crisis_table_:
|
|
||||||
self.crisis_table_ = CrisisTable.convert(
|
|
||||||
CacheData.readExcel('crisis_table')
|
|
||||||
)
|
|
||||||
return self.crisis_table_
|
return self.crisis_table_
|
||||||
|
|
||||||
|
async def display_meta_table(self) -> None:
|
||||||
|
self.display_meta_table_ = DisplayMetaTable.convert(
|
||||||
|
await store.get_excel("display_meta_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def DISPLAY_META_TABLE(self) -> DisplayMetaTable:
|
def DISPLAY_META_TABLE(self) -> DisplayMetaTable:
|
||||||
if not self.display_meta_table_:
|
|
||||||
self.display_meta_table_ = DisplayMetaTable.convert(
|
|
||||||
CacheData.readExcel('display_meta_table')
|
|
||||||
)
|
|
||||||
return self.display_meta_table_
|
return self.display_meta_table_
|
||||||
|
|
||||||
|
async def enemy_handbook_table(self) -> None:
|
||||||
|
self.enemy_handbook_table_ = EnemyHandbookTable.convert(
|
||||||
|
await store.get_excel("enemy_handbook_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ENEMY_HANDBOOK_TABLE(self) -> EnemyHandbookTable:
|
def ENEMY_HANDBOOK_TABLE(self) -> EnemyHandbookTable:
|
||||||
if not self.enemy_handbook_table_:
|
|
||||||
self.enemy_handbook_table_ = EnemyHandbookTable.convert(
|
|
||||||
CacheData.readExcel('enemy_handbook_table')
|
|
||||||
)
|
|
||||||
return self.enemy_handbook_table_
|
return self.enemy_handbook_table_
|
||||||
|
|
||||||
|
async def favor_table(self) -> None:
|
||||||
|
self.favor_table_ = FavorTable.convert(
|
||||||
|
await store.get_excel("favor_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def FAVOR_TABLE(self) -> FavorTable:
|
def FAVOR_TABLE(self) -> FavorTable:
|
||||||
if not self.favor_table_:
|
|
||||||
self.favor_table_ = FavorTable.convert(
|
|
||||||
CacheData.readExcel('favor_table')
|
|
||||||
)
|
|
||||||
return self.favor_table_
|
return self.favor_table_
|
||||||
|
|
||||||
|
async def gacha_table(self) -> None:
|
||||||
|
self.gacha_table_ = GachaTable.convert(
|
||||||
|
await store.get_excel("gacha_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def GACHA_TABLE(self) -> GachaTable:
|
def GACHA_TABLE(self) -> GachaTable:
|
||||||
if not self.gacha_table_:
|
|
||||||
self.gacha_table_ = GachaTable.convert(
|
|
||||||
CacheData.readExcel('gacha_table')
|
|
||||||
)
|
|
||||||
return self.gacha_table_
|
return self.gacha_table_
|
||||||
|
|
||||||
|
async def gamedata_const(self) -> None:
|
||||||
|
self.gamedata_const_ = GamedataConst.convert(
|
||||||
|
await store.get_excel("gamedata_const")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def GAMEDATA_CONST(self) -> GamedataConst:
|
def GAMEDATA_CONST(self) -> GamedataConst:
|
||||||
if not self.gamedata_const_:
|
|
||||||
self.gamedata_const_ = GamedataConst.convert(
|
|
||||||
CacheData.readExcel('gamedata_const')
|
|
||||||
)
|
|
||||||
return self.gamedata_const_
|
return self.gamedata_const_
|
||||||
|
|
||||||
|
async def handbook_info_table(self) -> None:
|
||||||
|
self.handbook_info_table_ = HandbookInfoTable.convert(
|
||||||
|
await store.get_excel("handbook_info_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def HANDBOOK_INFO_TABLE(self) -> HandbookInfoTable:
|
def HANDBOOK_INFO_TABLE(self) -> HandbookInfoTable:
|
||||||
if not self.handbook_info_table_:
|
|
||||||
self.handbook_info_table_ = HandbookInfoTable.convert(
|
|
||||||
CacheData.readExcel('handbook_info_table')
|
|
||||||
)
|
|
||||||
return self.handbook_info_table_
|
return self.handbook_info_table_
|
||||||
|
|
||||||
|
async def handbook_table(self) -> None:
|
||||||
|
self.handbook_table_ = HandbookTable.convert(
|
||||||
|
await store.get_excel("handbook_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def HANDBOOK_TABLE(self) -> HandbookTable:
|
def HANDBOOK_TABLE(self) -> HandbookTable:
|
||||||
if not self.handbook_table_:
|
|
||||||
self.handbook_table_ = HandbookTable.convert(
|
|
||||||
CacheData.readExcel('handbook_table')
|
|
||||||
)
|
|
||||||
return self.handbook_table_
|
return self.handbook_table_
|
||||||
|
|
||||||
|
async def handbook_team_table(self) -> None:
|
||||||
|
self.handbook_team_table_ = HandbookTeamTable.convert(
|
||||||
|
{"team": await store.get_excel("handbook_team_table")}
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def HANDBOOK_TEAM_TABLE(self) -> Dict[str, HandbookTeam]:
|
def HANDBOOK_TEAM_TABLE(self) -> HandbookTeamTable:
|
||||||
if not self.handbook_team_table_:
|
|
||||||
self.handbook_team_table_ = msgjson.decode(
|
|
||||||
CacheData.readBytesExcel('handbook_team_table'),
|
|
||||||
type=Dict[str, HandbookTeam]
|
|
||||||
)
|
|
||||||
return self.handbook_team_table_
|
return self.handbook_team_table_
|
||||||
|
|
||||||
|
async def item_table(self) -> None:
|
||||||
|
self.item_table_ = ItemTable.convert(
|
||||||
|
await store.get_excel("item_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ITEM_TABLE(self) -> ItemTable:
|
def ITEM_TABLE(self) -> ItemTable:
|
||||||
if not self.item_table_:
|
|
||||||
self.item_table_ = ItemTable.convert(
|
|
||||||
CacheData.readExcel('item_table')
|
|
||||||
)
|
|
||||||
return self.item_table_
|
return self.item_table_
|
||||||
|
|
||||||
|
async def medal_table(self) -> None:
|
||||||
|
self.medal_table_ = MedalTable.convert(
|
||||||
|
await store.get_excel("medal_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def MEDAL_TABLE(self) -> MedalTable:
|
def MEDAL_TABLE(self) -> MedalTable:
|
||||||
if not self.medal_table_:
|
|
||||||
self.medal_table_ = MedalTable.convert(
|
|
||||||
CacheData.readExcel('medal_table')
|
|
||||||
)
|
|
||||||
return self.medal_table_
|
return self.medal_table_
|
||||||
|
|
||||||
|
async def mission_table(self) -> None:
|
||||||
|
self.mission_table_ = MissionTable.convert(
|
||||||
|
await store.get_excel("mission_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def MISSION_TABLE(self) -> MissionTable:
|
def MISSION_TABLE(self) -> MissionTable:
|
||||||
if not self.mission_table_:
|
|
||||||
self.mission_table_ = MissionTable.convert(
|
|
||||||
CacheData.readExcel('mission_table')
|
|
||||||
)
|
|
||||||
return self.mission_table_
|
return self.mission_table_
|
||||||
|
|
||||||
|
async def open_server_table(self) -> None:
|
||||||
|
self.open_server_table_ = OpenServerTable.convert(
|
||||||
|
await store.get_excel("open_server_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def OPEN_SERVER_TABLE(self) -> OpenServerTable:
|
def OPEN_SERVER_TABLE(self) -> OpenServerTable:
|
||||||
if not self.open_server_table_:
|
|
||||||
self.open_server_table_ = OpenServerTable.convert(
|
|
||||||
CacheData.readExcel('open_server_table')
|
|
||||||
)
|
|
||||||
return self.open_server_table_
|
return self.open_server_table_
|
||||||
|
|
||||||
|
async def player_avatar_table(self) -> None:
|
||||||
|
self.player_avatar_table_ = PlayerAvatarTable.convert(
|
||||||
|
await store.get_excel("player_avatar_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def PLAYER_AVATAR_TABLE(self) -> PlayerAvatarTable:
|
def PLAYER_AVATAR_TABLE(self) -> PlayerAvatarTable:
|
||||||
if not self.player_avatar_table_:
|
|
||||||
self.player_avatar_table_ = PlayerAvatarTable.convert(
|
|
||||||
CacheData.readExcel('player_avatar_table')
|
|
||||||
)
|
|
||||||
return self.player_avatar_table_
|
return self.player_avatar_table_
|
||||||
|
|
||||||
@property
|
async def range_table(self) -> None:
|
||||||
def RANGE_TABLE(self) -> Dict[str, Stage]:
|
self.range_table_ = RangeTable.convert(
|
||||||
if not self.range_table_:
|
{"range": await store.get_excel("range_table")}
|
||||||
self.range_table_ = msgjson.decode(
|
)
|
||||||
CacheData.readBytesExcel('range_table'),
|
|
||||||
type=Dict[str, Stage]
|
|
||||||
)
|
|
||||||
return self.range_table_
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def REPLICATE_TABLE(self) -> Dict[str, ReplicateList]:
|
def RANGE_TABLE(self) -> RangeTable:
|
||||||
if not self.replicate_table_:
|
return self.range_table_
|
||||||
self.replicate_table_ = msgjson.decode(
|
|
||||||
CacheData.readBytesExcel('replicate_table'),
|
async def replicate_table(self) -> None:
|
||||||
type=Dict[str, ReplicateList]
|
self.replicate_table_ = ReplicateTable.convert(
|
||||||
)
|
{"replicate": await store.get_excel("replicate_table")}
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def REPLICATE_TABLE(self) -> ReplicateTable:
|
||||||
return self.replicate_table_
|
return self.replicate_table_
|
||||||
|
|
||||||
|
async def retro_table(self) -> None:
|
||||||
|
self.retro_table_ = RetroTable.convert(
|
||||||
|
await store.get_excel("retro_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def RETRO_TABLE(self) -> RetroTable:
|
def RETRO_TABLE(self) -> RetroTable:
|
||||||
if not self.retro_table_:
|
|
||||||
self.retro_table_ = RetroTable.convert(
|
|
||||||
CacheData.readExcel('retro_table')
|
|
||||||
)
|
|
||||||
return self.retro_table_
|
return self.retro_table_
|
||||||
|
|
||||||
|
async def roguelike_table(self) -> None:
|
||||||
|
self.roguelike_table_ = RoguelikeTable.convert(
|
||||||
|
await store.get_excel("roguelike_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ROGUELIKE_TABLE(self) -> RoguelikeTable:
|
def ROGUELIKE_TABLE(self) -> RoguelikeTable:
|
||||||
if not self.roguelike_table_:
|
|
||||||
self.roguelike_table_ = RoguelikeTable.convert(
|
|
||||||
CacheData.readExcel('roguelike_table')
|
|
||||||
)
|
|
||||||
return self.roguelike_table_
|
return self.roguelike_table_
|
||||||
|
|
||||||
|
async def roguelike_topic_table(self) -> None:
|
||||||
|
self.roguelike_topic_table_ = RoguelikeTopicTable.convert(
|
||||||
|
await store.get_excel("roguelike_topic_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ROGUELIKE_TOPIC_TABLE(self) -> RoguelikeTopicTable:
|
def ROGUELIKE_TOPIC_TABLE(self) -> RoguelikeTopicTable:
|
||||||
if not self.roguelike_topic_table_:
|
|
||||||
self.roguelike_topic_table_ = RoguelikeTopicTable.convert(
|
|
||||||
CacheData.readExcel('roguelike_topic_table')
|
|
||||||
)
|
|
||||||
return self.roguelike_topic_table_
|
return self.roguelike_topic_table_
|
||||||
|
|
||||||
|
async def sandbox_table(self) -> None:
|
||||||
|
self.sandbox_table_ = SandboxTable.convert(
|
||||||
|
await store.get_excel("sandbox_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SANDBOX_TABLE(self) -> SandboxTable:
|
def SANDBOX_TABLE(self) -> SandboxTable:
|
||||||
if not self.sandbox_table_:
|
|
||||||
self.sandbox_table_ = SandboxTable.convert(
|
|
||||||
CacheData.readExcel('sandbox_table')
|
|
||||||
)
|
|
||||||
return self.sandbox_table_
|
return self.sandbox_table_
|
||||||
|
|
||||||
|
async def shop_client_table(self) -> None:
|
||||||
|
self.shop_client_table_ = ShopClientTable.convert(
|
||||||
|
await store.get_excel("shop_client_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SHOP_CLIENT_TABLE(self) -> ShopClientTable:
|
def SHOP_CLIENT_TABLE(self) -> ShopClientTable:
|
||||||
if not self.shop_client_table_:
|
|
||||||
self.shop_client_table_ = ShopClientTable.convert(
|
|
||||||
CacheData.readExcel('shop_client_table')
|
|
||||||
)
|
|
||||||
return self.shop_client_table_
|
return self.shop_client_table_
|
||||||
|
|
||||||
|
async def skill_table(self) -> None:
|
||||||
|
self.skill_table_ = SkillTable.convert(
|
||||||
|
{"skills": await store.get_excel("skill_table")}
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SKILL_TABLE(self) -> Dict[str, SkillDataBundle]:
|
def SKILL_TABLE(self) -> SkillTable:
|
||||||
if not self.skill_table_:
|
|
||||||
self.skill_table_ = msgjson.decode(
|
|
||||||
CacheData.readBytesExcel('skill_table'),
|
|
||||||
type=Dict[str, SkillDataBundle]
|
|
||||||
)
|
|
||||||
return self.skill_table_
|
return self.skill_table_
|
||||||
|
|
||||||
|
async def skin_table(self) -> None:
|
||||||
|
self.skin_table_ = SkinTable.convert(
|
||||||
|
await store.get_excel("skin_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def SKIN_TABLE(self) -> SkinTable:
|
def SKIN_TABLE(self) -> SkinTable:
|
||||||
if not self.skin_table_:
|
|
||||||
self.skin_table_ = SkinTable.convert(
|
|
||||||
CacheData.readExcel('skin_table')
|
|
||||||
)
|
|
||||||
return self.skin_table_
|
return self.skin_table_
|
||||||
|
|
||||||
|
async def stage_table(self) -> None:
|
||||||
|
self.stage_table_ = StageTable.convert(
|
||||||
|
await store.get_excel("stage_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def STAGE_TABLE(self) -> StageTable:
|
def STAGE_TABLE(self) -> StageTable:
|
||||||
if not self.stage_table_:
|
|
||||||
self.stage_table_ = StageTable.convert(
|
|
||||||
CacheData.readExcel('stage_table')
|
|
||||||
)
|
|
||||||
return self.stage_table_
|
return self.stage_table_
|
||||||
|
|
||||||
|
async def story_review_meta_table(self) -> None:
|
||||||
|
self.story_review_meta_table_ = StoryReviewMetaTable.convert(
|
||||||
|
await store.get_excel("story_review_meta_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def STORY_REVIEW_META_TABLE(self) -> StoryReviewMetaTable:
|
def STORY_REVIEW_META_TABLE(self) -> StoryReviewMetaTable:
|
||||||
if not self.story_review_meta_table_:
|
|
||||||
self.story_review_meta_table_ = StoryReviewMetaTable.convert(
|
|
||||||
CacheData.readExcel('story_review_meta_table')
|
|
||||||
)
|
|
||||||
return self.story_review_meta_table_
|
return self.story_review_meta_table_
|
||||||
|
|
||||||
@property
|
async def story_review_table(self) -> None:
|
||||||
def STORY_REVIEW_TABLE(self) -> Dict[str, StoryReviewGroupClientData]:
|
self.story_review_table_ = StoryReviewTable.convert(
|
||||||
if not self.story_review_table_:
|
{"storyreviewtable": await store.get_excel("story_review_table")}
|
||||||
self.story_review_table_ = msgjson.decode(
|
)
|
||||||
CacheData.readBytesExcel('story_review_table'),
|
|
||||||
type=Dict[str, StoryReviewGroupClientData]
|
|
||||||
)
|
|
||||||
return self.story_review_table_
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def STORY_TABLE(self) -> Dict[str, StoryData]:
|
def STORY_REVIEW_TABLE(self) -> StoryReviewTable:
|
||||||
if not self.story_table_:
|
return self.story_review_table_
|
||||||
self.story_table_ = msgjson.decode(
|
|
||||||
CacheData.readBytesExcel('story_table'),
|
async def story_table(self) -> None:
|
||||||
type=Dict[str, StoryData]
|
self.story_table_ = StoryTable.convert(
|
||||||
)
|
{"stories": await store.get_excel("story_table")}
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def STORY_TABLE(self) -> StoryTable:
|
||||||
return self.story_table_
|
return self.story_table_
|
||||||
|
|
||||||
|
async def tech_buff_table(self) -> None:
|
||||||
|
self.tech_buff_table_ = TechBuffTable.convert(
|
||||||
|
await store.get_excel("tech_buff_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def TECH_BUFF_TABLE(self) -> TechBuffTable:
|
def TECH_BUFF_TABLE(self) -> TechBuffTable:
|
||||||
if not self.tech_buff_table_:
|
|
||||||
self.tech_buff_table_ = TechBuffTable.convert(
|
|
||||||
CacheData.readExcel('tech_buff_table')
|
|
||||||
)
|
|
||||||
return self.tech_buff_table_
|
return self.tech_buff_table_
|
||||||
|
|
||||||
|
async def tip_table(self) -> None:
|
||||||
|
self.tip_table_ = TipTable.convert(
|
||||||
|
await store.get_excel("tip_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def TIP_TABLE(self) -> TipTable:
|
def TIP_TABLE(self) -> TipTable:
|
||||||
if not self.tip_table_:
|
|
||||||
self.tip_table_ = TipTable.convert(
|
|
||||||
CacheData.readExcel('tip_table')
|
|
||||||
)
|
|
||||||
return self.tip_table_
|
return self.tip_table_
|
||||||
|
|
||||||
|
async def token_table(self) -> None:
|
||||||
|
self.token_table_ = TokenTable.convert(
|
||||||
|
{"tokens": await store.get_excel("token_table")}
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def TOKEN_TABLE(self) -> Dict[str, TokenCharacterData]:
|
def TOKEN_TABLE(self) -> TokenTable:
|
||||||
if not self.token_table_:
|
|
||||||
self.token_table_ = msgjson.decode(
|
|
||||||
CacheData.readBytesExcel('token_table'),
|
|
||||||
type=Dict[str, TokenCharacterData]
|
|
||||||
)
|
|
||||||
return self.token_table_
|
return self.token_table_
|
||||||
|
|
||||||
|
async def uniequip_data(self) -> None:
|
||||||
|
self.uniequip_data_ = UniequipData.convert(
|
||||||
|
await store.get_excel("uniequip_data")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def UNIEQUIP_DATA(self) -> UniequipData:
|
def UNIEQUIP_DATA(self) -> UniequipData:
|
||||||
if not self.uniequip_data_:
|
|
||||||
self.uniequip_data_ = UniequipData.convert(
|
|
||||||
CacheData.readExcel('uniequip_data')
|
|
||||||
)
|
|
||||||
return self.uniequip_data_
|
return self.uniequip_data_
|
||||||
|
|
||||||
|
async def uniequip_table(self) -> None:
|
||||||
|
self.uniequip_table_ = UniEquipTable.convert(
|
||||||
|
await store.get_excel("uniequip_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def UNIEQUIP_TABLE(self) -> UniEquipTable:
|
def UNIEQUIP_TABLE(self) -> UniEquipTable:
|
||||||
if not self.uniequip_table_:
|
|
||||||
self.uniequip_table_ = UniEquipTable.convert(
|
|
||||||
CacheData.readExcel('uniequip_table')
|
|
||||||
)
|
|
||||||
return self.uniequip_table_
|
return self.uniequip_table_
|
||||||
|
|
||||||
|
async def zone_table(self) -> None:
|
||||||
|
self.zone_table_ = ZoneTable.convert(
|
||||||
|
await store.get_excel("zone_table")
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ZONE_TABLE(self) -> ZoneTable:
|
def ZONE_TABLE(self) -> ZoneTable:
|
||||||
if not self.zone_table_:
|
|
||||||
self.zone_table_ = ZoneTable.convert(
|
|
||||||
CacheData.readExcel('zone_table')
|
|
||||||
)
|
|
||||||
return self.zone_table_
|
return self.zone_table_
|
||||||
|
|
||||||
def preload_table(self) -> None:
|
async def preload_table(self) -> None:
|
||||||
for name, method in inspect.getmembers(self, predicate=inspect.ismethod):
|
tasks = []
|
||||||
if callable(method) and not name.startswith('__') \
|
for name, method in inspect.getmembers(self):
|
||||||
and name != 'preload_table':
|
if (
|
||||||
method()
|
inspect.iscoroutinefunction(method)
|
||||||
|
and not name.startswith("__")
|
||||||
|
and name != "preload_table"
|
||||||
|
):
|
||||||
|
await method()
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
|
||||||
Excel = ExcelTableManager()
|
Excel = ExcelTableManager()
|
||||||
|
179
ArknightsUID/arknightsuid_resource/memoryStore.py
Normal file
179
ArknightsUID/arknightsuid_resource/memoryStore.py
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
import json
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import shutil
|
||||||
|
from datetime import UTC, datetime, timedelta
|
||||||
|
from pathlib import Path
|
||||||
|
from tempfile import mkstemp
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import anyio
|
||||||
|
from anyio import Path as anyioPath
|
||||||
|
from anyio.to_thread import run_sync
|
||||||
|
from msgspec import Struct
|
||||||
|
|
||||||
|
from gsuid_core.logger import logger
|
||||||
|
|
||||||
|
|
||||||
|
def read_json(file_path: Path, **kwargs) -> dict:
|
||||||
|
"""
|
||||||
|
Read a JSON file and return its contents as a dictionary.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with Path.open(file_path, encoding="UTF-8", **kwargs) as file:
|
||||||
|
return json.load(file)
|
||||||
|
except (FileNotFoundError, json.JSONDecodeError) as e:
|
||||||
|
logger.error(f"Error reading JSON file: {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
class Store(ABC):
|
||||||
|
"""Thread and process safe asynchronous key/value store."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def set(self, key: str, value: str | bytes, expires_in: int | timedelta | None = None) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get(self, key: str, renew_for: int | timedelta | None = None) -> bytes | None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete(self, key: str) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete_all(self) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def exists(self, key: str) -> bool:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def expires_in(self, key: str) -> int | None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class StorageObject(Struct):
|
||||||
|
expires_at: datetime | None
|
||||||
|
data: Any
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def new(cls, data: Any, expires_in: int | timedelta | None) -> StorageObject:
|
||||||
|
if expires_in is not None and not isinstance(expires_in, timedelta):
|
||||||
|
expires_in = timedelta(seconds=expires_in)
|
||||||
|
return cls(
|
||||||
|
data=data,
|
||||||
|
expires_at=(datetime.now(tz=UTC) + expires_in) if expires_in else None,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def expired(self) -> bool:
|
||||||
|
return self.expires_at is not None and datetime.now(tz=UTC) >= self.expires_at
|
||||||
|
|
||||||
|
@property
|
||||||
|
def expires_in(self) -> int:
|
||||||
|
if self.expires_at:
|
||||||
|
return int(self.expires_at.timestamp() - datetime.now(tz=UTC).timestamp())
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
class StoreService(Store):
|
||||||
|
__slots__ = ("store", "lock", "path")
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.path: anyioPath = anyioPath('data')
|
||||||
|
self.store_: dict[str, StorageObject] = {}
|
||||||
|
self.lock: anyio.Lock = anyio.Lock()
|
||||||
|
self.last_cleared: datetime = datetime.utcnow()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def load_from_path(path: anyioPath) -> dict[str, StorageObject]:
|
||||||
|
try:
|
||||||
|
data = await path.read_bytes()
|
||||||
|
return pickle.loads(data)
|
||||||
|
except FileNotFoundError:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _write_sync(self, target_file: anyioPath) -> None:
|
||||||
|
try:
|
||||||
|
tmp_file_fd, tmp_file_name = mkstemp(dir=self.path, prefix=f"{target_file.name}.cache")
|
||||||
|
renamed = False
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
os.write(tmp_file_fd, pickle.dumps(self.store_))
|
||||||
|
finally:
|
||||||
|
os.close(tmp_file_fd)
|
||||||
|
shutil.move(tmp_file_name, target_file)
|
||||||
|
renamed = True
|
||||||
|
finally:
|
||||||
|
if not renamed:
|
||||||
|
Path.unlink(Path(tmp_file_name))
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def write(self, target_file: anyioPath) -> None:
|
||||||
|
await run_sync(self._write_sync, target_file)
|
||||||
|
|
||||||
|
async def set(self, key: str, value: Any, expires_in: int | timedelta | None = None) -> None:
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = value.encode("UTF-8")
|
||||||
|
async with self.lock:
|
||||||
|
self.store_[key] = StorageObject.new(data=value, expires_in=expires_in)
|
||||||
|
|
||||||
|
async def get(self, key: str, renew_for: int | timedelta | None = None, default: Any = None) -> Any:
|
||||||
|
async with self.lock:
|
||||||
|
storage_obj = self.store_.get(key)
|
||||||
|
if not storage_obj:
|
||||||
|
return default
|
||||||
|
if storage_obj.expired:
|
||||||
|
self.store_.pop(key)
|
||||||
|
return None
|
||||||
|
if renew_for and storage_obj.expires_at:
|
||||||
|
storage_obj = StorageObject.new(data=storage_obj.data, expires_in=renew_for)
|
||||||
|
self.store_[key] = storage_obj
|
||||||
|
return storage_obj.data
|
||||||
|
|
||||||
|
async def get_excel(self, table_name: str) -> Any:
|
||||||
|
return await self.get(table_name, default=None)
|
||||||
|
|
||||||
|
async def get_file(self, local_path: Path, expires_in: int | timedelta | None = None) -> Any:
|
||||||
|
if not await self.exists(local_path.stem):
|
||||||
|
await self.set(local_path.stem, read_json(local_path), expires_in)
|
||||||
|
return await self.get(local_path.stem)
|
||||||
|
|
||||||
|
async def delete(self, key: str) -> None:
|
||||||
|
async with self.lock:
|
||||||
|
self.store_.pop(key, None)
|
||||||
|
|
||||||
|
async def delete_all(self) -> None:
|
||||||
|
async with self.lock:
|
||||||
|
self.store_.clear()
|
||||||
|
|
||||||
|
async def delete_expired(self) -> None:
|
||||||
|
async with self.lock:
|
||||||
|
new_store = {}
|
||||||
|
for i, (key, storage_obj) in enumerate(self.store_.items()):
|
||||||
|
if not storage_obj.expired:
|
||||||
|
new_store[key] = storage_obj
|
||||||
|
if i % 1000 == 0:
|
||||||
|
await anyio.sleep(0)
|
||||||
|
self.store_ = new_store
|
||||||
|
|
||||||
|
async def exists(self, key: str) -> bool:
|
||||||
|
return key in self.store_
|
||||||
|
|
||||||
|
async def keys(self) -> list[str]:
|
||||||
|
return list(self.store_.keys())
|
||||||
|
|
||||||
|
async def expires_in(self, key: str) -> int | None:
|
||||||
|
if storage_obj := self.store_.get(key):
|
||||||
|
return storage_obj.expires_in
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
store = StoreService()
|
Loading…
x
Reference in New Issue
Block a user