diff --git a/latest version/core/bundle.py b/latest version/core/bundle.py index 01a230c..985d93c 100644 --- a/latest version/core/bundle.py +++ b/latest version/core/bundle.py @@ -82,11 +82,15 @@ class BundleParser: version_tuple_bundles: 'dict[tuple[str, str], ContentBundle]' = {} def __init__(self) -> None: - self.parse() + if not self.bundles: + self.parse() def re_init(self) -> None: self.bundles.clear() self.max_bundle_version.clear() + self.next_versions.clear() + self.version_tuple_bundles.clear() + self.get_bundles.cache_clear() self.parse() def parse(self) -> None: diff --git a/latest version/core/constant.py b/latest version/core/constant.py index e98694b..f775f13 100644 --- a/latest version/core/constant.py +++ b/latest version/core/constant.py @@ -1,6 +1,6 @@ from .config_manager import Config -ARCAEA_SERVER_VERSION = 'v2.11.3.13' +ARCAEA_SERVER_VERSION = 'v2.11.3.14' ARCAEA_DATABASE_VERSION = 'v2.11.3.13' ARCAEA_LOG_DATBASE_VERSION = 'v1.1' diff --git a/latest version/core/init.py b/latest version/core/init.py index cf0b8c4..affa6f1 100644 --- a/latest version/core/init.py +++ b/latest version/core/init.py @@ -16,6 +16,7 @@ from core.sql import (Connect, DatabaseMigrator, LogDatabaseMigrator, MemoryDatabase) from core.user import UserRegister from core.util import try_rename +from core.world import MapParser class DatabaseInit: @@ -326,12 +327,11 @@ class FileChecker: def check_song_file(self) -> bool: '''检查song有关文件并初始化缓存''' f = self.check_folder(Config.SONG_FILE_FOLDER_PATH) - self.logger.info("Start to initialize song data...") + self.logger.info("Initialize song data...") try: DownloadList.initialize_cache() if not Config.SONG_FILE_HASH_PRE_CALCULATE: self.logger.info('Song file hash pre-calculate is disabled.') - self.logger.info('Song data initialization is complete!') except Exception as e: self.logger.error(format_exc()) self.logger.warning('Song data initialization error!') @@ -341,17 +341,28 @@ class FileChecker: def check_content_bundle(self) -> bool: '''检查 content bundle 有关文件并初始化缓存''' f = self.check_folder(Config.CONTENT_BUNDLE_FOLDER_PATH) - self.logger.info("Start to initialize content bundle data...") + self.logger.info("Initialize content bundle data...") try: BundleParser() - self.logger.info('Content bundle data initialization is complete!') except Exception as e: self.logger.error(format_exc()) self.logger.warning('Content bundle data initialization error!') f = False return f + def check_world_map(self) -> bool: + '''检查 world map 有关文件并初始化缓存''' + f = self.check_folder(Config.WORLD_MAP_FOLDER_PATH) + self.logger.info("Initialize world map data...") + try: + MapParser() + except Exception as e: + self.logger.error(format_exc()) + self.logger.warning('World map data initialization error!') + f = False + return f + def check_before_run(self) -> bool: '''运行前检查,返回布尔值''' MemoryDatabase() # 初始化内存数据库 - return self.check_song_file() and self.check_content_bundle() and self.check_update_database() + return self.check_song_file() and self.check_content_bundle() and self.check_update_database() and self.check_world_map() diff --git a/latest version/core/operation.py b/latest version/core/operation.py index 62b2143..7e4a834 100644 --- a/latest version/core/operation.py +++ b/latest version/core/operation.py @@ -6,6 +6,7 @@ from .save import SaveData from .score import Score from .sql import Connect, Sql from .user import User +from .world import MapParser class BaseOperation: @@ -88,6 +89,16 @@ class RefreshBundleCache(BaseOperation): BundleParser().re_init() +class RefreshWorldMapCache(BaseOperation): + ''' + 刷新 map 缓存 + ''' + _name = 'refresh_world_map_cache' + + def run(self): + MapParser().re_init() + + class SaveUpdateScore(BaseOperation): ''' 云存档更新成绩,是覆盖式更新 diff --git a/latest version/core/sql.py b/latest version/core/sql.py index a402088..96035bf 100644 --- a/latest version/core/sql.py +++ b/latest version/core/sql.py @@ -437,7 +437,7 @@ class DatabaseMigrator: def _version_2_11_3_11(self): ''' 2.11.3.11 版本特殊更新,调整 recent30 表结构 - recent30 表从 (user_id: int PK, song_id: text, rating: real, ...) \ + recent30 表从 (user_id: int PK, rating: real, song_id: text, ...) \ 更改为 (user_id: int PK, r_index: int PK, time_played: int, song_id: text, difficulty: int, score: int, sp, p, n, m, hp, mod, clear_type, rating: real) ''' diff --git a/latest version/core/world.py b/latest version/core/world.py index d3c6c46..a82b48e 100644 --- a/latest version/core/world.py +++ b/latest version/core/world.py @@ -10,34 +10,46 @@ from .error import InputError, MapLocked, NoData from .item import ItemFactory -@lru_cache(maxsize=128) -def get_world_name(file_dir: str = Constant.WORLD_MAP_FOLDER_PATH) -> list: - '''获取所有地图名称,返回列表''' - file_list = [] - for root, dirs, files in os.walk(file_dir): - for file in files: - if os.path.splitext(file)[1] == '.json': - file_list.append(os.path.splitext(file)[0]) - return file_list +class MapParser: + map_id_path: 'dict[str, str]' = {} -@lru_cache(maxsize=128) -def get_world_info(map_id: str) -> dict: - '''读取json文件内容,返回字典''' - world_info = {} - with open(os.path.join(Constant.WORLD_MAP_FOLDER_PATH, f'{map_id}.json'), 'rb') as f: - world_info = load(f) + def __init__(self) -> None: + if not self.map_id_path: + self.parse() - return world_info + def parse(self) -> None: + for root, dirs, files in os.walk(Constant.WORLD_MAP_FOLDER_PATH): + for file in files: + if not file.endswith('.json'): + continue + path = os.path.join(root, file) + self.map_id_path[file[:-5]] = path -def get_world_all(c, user) -> list: - ''' - 读取所有地图信息,返回列表 - parameter: `user` - `User`类或子类的实例 - ''' - worlds = get_world_name() - return [UserMap(c, map_id, user) for map_id in worlds] + def re_init(self) -> None: + self.map_id_path.clear() + self.get_world_info.cache_clear() + self.parse() + + @staticmethod + @lru_cache(maxsize=128) + def get_world_info(map_id: str) -> dict: + '''读取json文件内容,返回字典''' + world_info = {} + with open(MapParser.map_id_path[map_id], 'rb') as f: + world_info = load(f) + + return world_info + + @staticmethod + def get_world_all(c, user) -> list: + ''' + 读取所有地图信息,返回列表 + parameter: `user` - `User` 类或子类的实例 + `c` - 数据库连接 + ''' + return [UserMap(c, map_id, user) for map_id in MapParser.map_id_path.keys()] class Step: @@ -208,7 +220,7 @@ class Map: def select_map_info(self): '''获取地图信息''' - self.from_dict(get_world_info(self.map_id)) + self.from_dict(MapParser.get_world_info(self.map_id)) class UserMap(Map): diff --git a/latest version/server/world.py b/latest version/server/world.py index 8567ea0..4fb1edc 100644 --- a/latest version/server/world.py +++ b/latest version/server/world.py @@ -2,7 +2,7 @@ from flask import Blueprint, request from core.sql import Connect from core.user import UserOnline -from core.world import UserMap, get_world_all +from core.world import MapParser, UserMap from .auth import auth_required from .func import arc_try, success_return @@ -20,7 +20,7 @@ def world_all(user_id): return success_return({ "current_map": user.current_map.map_id, "user_id": user_id, - "maps": [x.to_dict(has_map_info=True, has_rewards=True) for x in get_world_all(c, user)] + "maps": [x.to_dict(has_map_info=True, has_rewards=True) for x in MapParser.get_world_all(c, user)] })