SFS 资源管理器是一款专为游戏 Spaceflight Simulator(太空飞行模拟器,简称 SFS)设计的桌面端启动器和资源管理工具。基于 PySide6(Qt for Python)构建,提供游戏启动管理、多类型资源分类浏览、导入导出、插件扩展、主题切换等完整功能。
- 游戏启动管理:支持多游戏版本/整合包的启动、关闭、卸载,进程监控与优雅退出
- 资源分类管理:覆盖 9 种资源类型——蓝图、模组、存档、星系、贴图、游戏、整合包、插件、主题
- 多版本资源存储:每种资源支持多版本共存,目录结构为
资源名/版本号/内容,附版本兼容性测试数据 - 智能索引系统:自动扫描文件系统构建索引,支持关键词搜索、分页浏览、分类筛选
- 多种导入导出格式:支持
.sfs私有格式、通用.zip、社区压缩包格式(自动识别)、整合包导出 - 插件系统:基于钩子(Hook)的微内核架构,支持类继承和函数导出两种开发模式
- 主题切换:支持 light、dark、star lines 三套主题,通过
.ui文件 + QSS 实现 - 资源目录监测:游戏运行时后台自动检测玩家自创资源,迁移到存储并创建符号链接
- UID 权限系统:基于用户唯一标识的编辑权限控制
| 层面 | 技术 |
|---|---|
| 语言 | Python 3.8+ |
| UI 框架 | PySide6 (Qt 6 for Python) |
| UI 设计 | Qt Designer (.ui 文件) + QUiLoader 动态加载 |
| 样式 | QSS (Qt Style Sheets) + QPalette |
| 数据存储 | JSON 文件(简介、索引、哈希表、配置) |
| 压缩处理 | zipfile (Python 内置) + 7-Zip 外部调用(.rar/.7z) |
| 进程管理 | subprocess + Windows API (ctypes) |
| 符号链接 | Windows Junction (mklink /J) |
| 日志 | 自定义日志系统(logging 模块封装) |
| 插件架构 | 钩子注册/触发模式 + 观察者模式 |
┌──────────────────────────────────────────────────────┐
│ UI 层 (UI/) │
│ SFS_launcher.py ui_loader.py popup_dialogs.py │
│ resource_browser.py settings_page.py │
│ res_sel_page.py detail_test_ui.py │
├──────────────────────────────────────────────────────┤
│ 插件层 (plugins/) │
│ 7个简介编辑器 mod_info_extractor page_jump │
│ _plugin_template (开发模板) │
├──────────────────────────────────────────────────────┤
│ 插件框架层 │
│ plugin_api.py plugin_base.py plugin_manager.py │
│ context_menu_manager.py │
├──────────────────────────────────────────────────────┤
│ 业务逻辑层 │
│ resource_operations/ (资源磁盘操作) │
│ resource_loader/ (资源索引构建) │
│ resource_monitor.py (游戏内资源监测) │
│ game_manager.py (游戏进程管理) │
│ index_update_manager.py (索引自动更新) │
├──────────────────────────────────────────────────────┤
│ 数据共享层 │
│ share_data.py resource_data_manager.py │
│ resource_metadata.py resource_type_manager.py │
├──────────────────────────────────────────────────────┤
│ 基础设施层 │
│ files_operator.py config_manager.py logger.py │
│ user_profile.py app_settings.py │
├──────────────────────────────────────────────────────┤
│ 数据存储层 (files/) │
│ Blueprints/ Mods/ Worlds/ Solar_Systems/ │
│ Texture_Packs/ games/ Mod_Pack/ │
│ configs/ exports/ logs/ │
└──────────────────────────────────────────────────────┘
-
单例模式(Singleton):
RESOURCEREACTOR、PluginAPI、PluginManager、ConfigManager、AppSettings、UserProfile、ContextMenuRegistry等核心组件均采用单例模式,全局唯一访问点。 -
观察者模式(Observer):
ResourceManagerShareData维护ObservedEvent类型的事件订阅表。UI 组件(SFSMainWindow、ResourceBrowser)继承ProjectObserver并订阅事件,数据变更时自动刷新界面。 -
元数据驱动(Metadata-Driven):
resource_metadata.py是所有资源类型定义的唯一来源。ResourceLoader、ResourceDataManager、ResourceOperations、ResourceImportScanner等模块均通过type_id查表获取行为参数,彻底消除了按类型硬编码分支。 -
钩子模式(Hook):插件通过
api.register_hook(hook_name, callback)注册生命周期钩子,框架在特定时机触发。支持on_app_start、on_ui_ready、on_data_loaded、on_context_menu_show、on_resource_imported、on_resource_deleted、on_font_changed等钩子。
sfs_start_pyside/
│
├── main.py # 程序入口:初始化各组件、加载数据、创建主窗口
├── share_data.py # 全局数据共享单例 (RESOURCEREACTOR)
├── plugin_api.py # 插件开发 API 单例 (PluginAPI)
├── plugin_base.py # 插件基类 (PluginBase / DataPluginBase / UIPluginBase)
├── plugin_manager.py # 插件管理器:发现、加载、卸载、启停插件
├── files_operator.py # 文件系统操作工具集 (读/写/复制/移动/删除/哈希)
├── config_manager.py # 配置管理器单例:JSON 配置读写与缓存
├── game_manager.py # 游戏进程管理器:启动/关闭/卸载/进程检测
├── resource_monitor.py # 资源目录后台监测线程
├── resource_metadata.py # 资源类型元数据中心 (METADATA 唯一真相来源)
├── resource_data_manager.py # 通用资源数据管理器 (替代 6 个重复 Mixin)
├── resource_type_manager.py # 资源类型 OOP 封装 (ResourceType / ResourceManager)
├── user_profile.py # 用户档案:用户名/UID/编辑权限
├── app_settings.py # 应用设置单例:主题/游戏/显示/自启动等
├── logger.py # 日志系统:按模块创建独立日志文件
├── index_update_manager.py # 索引自动更新管理器 (定时/手动)
├── context_menu_manager.py # 右键菜单系统:身份匹配 + 插件注入
│
├── UI/ # ═══ 用户界面层 ═══
│ ├── SFS_launcher.py # 主窗口:导航、游戏控制、首页展示
│ ├── ui_loader.py # 主题加载器:加载 .ui 文件 + QSS 样式
│ ├── resource_browser.py # 资源浏览页:分类/搜索/分页
│ ├── settings_page.py # 设置页:主题/游戏/显示/字体等
│ ├── res_sel_page.py # 资源选择页:导出/导入/添加到游戏
│ ├── popup_dialogs.py # 弹窗合集:详情/提示/确认/进度/输入
│ ├── window_manager.py # 统一窗口管理器:加载/配置/样式/窗口按钮
│ ├── detail_test_ui.py # 兼容性测试动态 UI 构建
│ ├── Blueprints_detail.py # 蓝图详情(委托 popup_dialogs)
│ ├── Mods_detail.py # 模组详情
│ ├── Galaxies_detail.py # 星系详情
│ ├── Worlds_detail.py # 存档详情
│ ├── Textures_detail.py # 贴图详情
│ ├── Games_detail.py # 游戏详情
│ ├── setting.json # 应用配置文件
│ ├── SFS-Launcher-UI.pro # Qt Designer 项目文件
│ ├── light/ # 亮色主题 UI 文件
│ ├── dark/ # 暗色主题 UI 文件
│ └── Nebula Purple/ # 星云紫主题 UI 文件 (默认主题)
│
├── resource_loader/ # ═══ 资源加载器层 ═══
│ ├── __init__.py # 统一入口 start_load() + 全局 Loader 实例
│ ├── resource_loader.py # 通用资源加载器 (索引/哈希表构建)
│ └── ui_utils.py # UI 工具:QUiLoader/字体缩放/QSS 应用
│
├── resource_operations/ # ═══ 资源操作层 ═══
│ ├── __init__.py # 统一入口 + ResourceOperations 类 + 导出函数
│ ├── resource_importer.py # 资源导入扫描器 (多格式检测)
│ ├── intro_generator.py # 简介.json 自动生成
│ ├── game_ops.py # 游戏专用操作 (导入/导出/链接/转换)
│ ├── compatibility_checker.py # 版本兼容性批量检查与切换
│ └── community_format_detector.py # 社区压缩包格式自动识别
│
├── plugins/ # ═══ 插件目录 ═══
│ ├── _plugin_template/ # 插件开发标准模板
│ ├── blueprint_intro_editor/ # 蓝图简介编辑器
│ ├── mod_intro_editor/ # 模组简介编辑器
│ ├── solar_system_intro_editor/ # 星系简介编辑器
│ ├── texture_pack_intro_editor/ # 贴图简介编辑器
│ ├── world_intro_editor/ # 存档简介编辑器
│ ├── exten_intro_editor/ # 拓展(插件/主题)简介编辑器
│ ├── modpack_intro_editor/ # 整合包简介编辑器
│ ├── mod_info_extractor/ # 模组 DLL 元数据提取器
│ └── page_jump/ # 页码跳转增强
│
├── files/ # ═══ 数据存储层 ═══
│ ├── Blueprints/ # 蓝图资源 (含 index.json + hash_table.json)
│ ├── Mods/ # 模组资源
│ ├── Solar_Systems/ # 星系资源
│ ├── Texture_Packs/ # 贴图资源
│ ├── Worlds/ # 存档资源
│ ├── games/ # 游戏安装目录 (含 my_games/)
│ ├── Mod_Pack/ # 整合包资源
│ ├── configs/ # 配置文件 (plugin_states.json 等)
│ ├── exports/ # 默认导出目录
│ └── logs/ # 日志文件
│
├── intro_templates/ # ═══ 简介模板 ═══
│ ├── Blueprints/简介.json # 蓝图简介标准模板
│ ├── Mods/简介.json # 模组简介标准模板
│ ├── Solar_Systems/简介.json # 星系简介标准模板
│ ├── Texture_Packs/简介.json # 贴图简介标准模板
│ ├── Worlds/简介.json # 存档简介标准模板
│ ├── games/简介.json # 游戏简介标准模板
│ └── Mod_Pack/简介.json # 整合包简介标准模板
│
├── docs/ # 文档
│ └── 资源类型管理系统.md # 资源类型管理设计文档
│
├── .vscode/ # VS Code 配置
├── .claude/ # Claude Code 配置
└── README.md # 本文件
- 初始化
QApplication,设置高 DPI 缩放属性 - 按序初始化:
UserProfile→AppSettings→PluginAPI→ConfigManager→PluginManager - 调用
resource_loader.start_load()加载所有资源索引 - 创建
SFSMainWindow主窗口并显示 - 支持
--startup参数(开机自启动场景) - 处理首次运行的用户名输入和 UUID 迁移
- 退出时触发
on_app_exit钩子,关闭所有插件
ResourceManagerShareData 是全局单例(RESOURCEREACTOR),管理所有运行时数据:
_managers:{type_id: ResourceDataManager}— 每类资源一个数据管理器_paths:{type_id: str}— 每类资源的磁盘目录selected_resources:当前被右键选中的资源{type_id, name, widget}pending_imports:待导入的资源列表
观察者事件类型 (ObservedEvent):
| 事件 | 触发时机 | 订阅者 |
|---|---|---|
INDEX_CHANGED |
资源索引数据变更 | ResourceBrowser 自动刷新 |
PATHS_CHANGED |
资源目录路径变更 | UI 更新路径显示 |
FONT_CHANGED |
字体大小变更 | 所有需要字体缩放的控件 |
HOME_PAGE_CHANGED |
首页数据需要刷新 | SFSMainWindow 刷新首页 |
SELECTION_CHANGED |
当前选中资源变更 | 右键菜单相关 |
PENDING_IMPORTS_CHANGED |
待导入列表变更 | 导入相关 UI |
METADATA 字典定义了全部 9 种资源类型的元信息,是系统中所有资源类型判断的唯一来源。每个条目包含:
| 字段 | 说明 | 示例(blueprint) |
|---|---|---|
type_id |
内部标识 | 'blueprint' |
cn_name |
中文名称 | '蓝图' |
folder_name |
磁盘文件夹名 | 'Blueprints' |
name_field |
简介中名称字段 | '蓝图名称' |
author_field |
简介中作者字段 | '蓝图作者' |
uid_field |
简介中 UID 字段 | 'UID' |
intro_field |
简介中介绍字段 | '蓝图简介' |
version_field |
简介中版本列表字段 | '蓝图版本' |
test_field |
兼容性测试字段 | '兼容版本' |
search_fields |
可搜索字段列表 | ['蓝图名称', '蓝图版本', '蓝图作者'] |
my_category |
我的XX分类名 | '我的蓝图' |
detail_ui |
详情 UI 文件名 | 'Blueprints_detail.ui' |
同时派生多个便捷映射:ID_TO_FOLDER、FOLDER_TO_ID、ID_TO_CN、CN_TO_ID、CN_TO_RESOURCE_META、NAME_FIELD_TO_ID、ID_TO_VERSION_FIELD、ID_TO_TEST_FIELD 等。
9 种资源类型中,前 5 种(blueprint/mod/solar_system/texture_pack/world)是可多版本资源,game 和 modpack 是含资源目录的特殊类型,plugin 和 theme 是拓展类型(无"我的XX")。
ResourceDataManager 是通用参数化数据管理器,通过 type_id 初始化后提供统一的数据访问接口:
set_index(data)/set_hash_table(data)— 写入数据并通知观察者get_info(name)— 按名称查找资源(支持Category/Name格式)get_intro_path(name)— 查找资源的简介.json磁盘路径load_intro_data(name)— 加载完整简介内容get_categories()— 获取所有分类("我的XX"优先,其他收尾)get_paginated(page, page_size)/get_by_category_paginated(...)— 分页查询search(keyword)— 跨分类关键词搜索get_now_playing_game()/set_now_playing_game()— 当前游戏(仅 game 类型)
纯函数式模块,所有函数统一返回 (success: bool, data_or_error: str):
| 函数 | 功能 |
|---|---|
read_json(path) |
读取 JSON 文件 |
write_json(path, data) |
写入 JSON 文件(自动创建目录) |
read_txt(path) / write_txt(path, content) |
文本文件读写 |
copy_dir(src, dst) |
递归复制目录 |
delete_dir(path) |
递归删除目录 |
move_file(src, dst, overwrite) |
移动文件/目录(支持覆盖) |
rename_file(src, dst) |
重命名 |
generate_folder_hash(path, exclude_files) |
递归计算文件夹哈希(SHA256) |
get_all_dirs(path) / get_all_files(path) |
列出子目录/文件 |
sort_files(paths, key) |
文件排序(名称/修改时间) |
open_folder_in_explorer(path) |
在资源管理器中打开 |
check_file_exists(path) / get_file_size(path) / get_file_modify_time(path) |
文件信息 |
ResourceLoader(type_id) 负责从磁盘构建资源索引:
load_all()→_load_or_build_index()+_load_or_build_hash_table()- 若
index.json存在则直接加载,否则扫描目录构建 rebuild_index_and_hash_table()支持用户手动触发全量重建check_duplicate_import(hash_value)基于哈希表检测重复导入- 子类:
ModpackLoader(跳过哈希表,文件过大)、GameLoader(游戏专用索引结构 + 图标提取)
ResourceOperations(type_id) — 通用资源磁盘操作:
install_to_game(game_intro, res_intro, force)— 安装资源到游戏目录:找兼容版本 → 复制内容 → 生成版本.json。整合包同时记录到追踪文件link_to_game(game_intro, res_intro)— 通过 Junction 软链接安装(用于"我的XX"资源)export_as_archive(res_intro, version, export_dir)— 导出单版本为 zipdelete_resource(res_intro)— 删除整个资源目录并清理索引/哈希表get_versions(name_or_intro)— 获取资源所有版本号
ResourceImportScanner — 多格式导入扫描器:
.sfs— 期望内部files/<Folder>/<Category>/<Name>/结构- 标准 zip — 期望顶层
<ResourceName>/简介.json - 社区格式 — 自动通过
community_format_detector识别并生成简介
community_format_detector.py — 社区压缩包格式识别(基于文件特征签名):
| 资源类型 | 识别特征 |
|---|---|
| 蓝图 | Blueprint.txt(JSON 含 parts 键) |
| 星系 | Import_Settings.txt + Planet Data/ 或 Heightmap Data/ |
| 贴图 | pack_info.txt + Textures/ 或 Color Textures/ |
| 存档 | WorldSettings.txt 或 Solar System.txt + Persistent/ |
| 模组 | .dll 文件 或 .pack (Unity AssetBundle) |
game_ops.py — 游戏专用操作:
_create_symlink(target, link)— Windows Junction 创建(mklink /J)import_resource()— 导入游戏时自动分离资源到"我的XX"并创建符号链接export_resource()/export_as_modpack()— 游戏/整合包导出
compatibility_checker.py — 版本兼容性批量检查:
- 检查所有"我的XX"资源与目标游戏版本的兼容性
- 返回
{compatible, need_switch, incompatible}分类 - 支持一键切换资源版本
GameManager(QObject) — 管理游戏进程生命周期:
- 启动:读取简介 → 定位 exe →
subprocess.Popen启动 → 启动资源监测线程 - 关闭:优雅关闭(
WM_CLOSE,最多等待 3 秒)→ 强制关闭(taskkill /F /T) - 运行检测:
is_game_running()先检查 Popen handle,再通过tasklist搜索进程名 - 卸载:删除游戏目录 → 清理配置 → 通知观察者刷新 UI
- 信号:
game_started、game_stopped、game_deleted、game_error
ResourceMonitor(threading.Thread) — 后台守护线程:
- 游戏运行时每 1 秒轮询资源目录,检测新增文件夹
- 游戏模式:所有新增文件夹均为玩家自创,直接迁移
- 整合包模式:先检查是否为依赖声明或追踪文件中的已知资源,跳过已知,处理新增
- 处理流程:移动内容 → 生成简介 → 计算哈希 → 创建
版本.json→ 创建 Junction → 更新索引 - 重名处理:基于文件夹内容 SHA256 计算唯一标识
update_tracking_file()供外部调用,记录用户导入的资源
- 定时器驱动,按配置的间隔(分钟)自动刷新资源索引
- 也支持手动触发全量重建
- 间隔从
AppSettings读取
【存储层】files/<Folder>/<Category>/<ResourceName>/
├── 简介.json # 多版本元数据(所有版本列表 + 公共信息)
├── 版本.json # 当前活跃版本号
├── 1.0/ # 版本内容目录
│ └── <content>
└── 2.0/
└── <content>
【我的XX层】files/<Folder>/<我的XX>/<ResourceName>/
├── 简介.json # 从存储层复制(多版本)
├── 版本.json # 当前链接到游戏的版本
├── 1.0/ → (Junction) # 符号链接指向存储层版本
└── ...
【游戏内层】<GameDir>/<ResourceDir>/<ResourceName>/
├── 简介.json # 单版本(整合包)或多版本(游戏)
├── 版本.json # 当前版本号
└── <content> # 实际文件内容
右键菜单等上下文场景使用 domain:res_type:identifier 格式:
resource:blueprint:我的蓝图/飞行器V2— 资源域,蓝图类型,分类/名称resource:mod:模组名— 直呼名称(无分类前缀时匹配所有分类)
基于**钩子(Hook)**模式的微内核架构:
PluginManager → 发现、加载、管理插件生命周期
PluginAPI → 向插件暴露核心能力(data / config / logger / ui / hooks)
PluginBase → 插件基类,封装生命周期方法
ContextMenuRegistry → 右键菜单注册与分发
plugins/插件名/
├── config.json # 插件元数据(必须)
├── __init__.py # 入口文件(必须)
├── dialog.ui # Qt Designer UI 文件
├── my_module.py # 自定义模块
└── resources/ # 图标等资源文件
模式一:类继承(推荐)
from plugin_base import PluginBase
class MyPlugin(PluginBase):
def on_initialize(self) -> bool:
self.api.register_hook('on_ui_ready', self._on_ui_ready)
return True
def _on_ui_ready(self, main_window):
self.log("主窗口已就绪")
def on_shutdown(self):
pass
PLUGIN_CLASS = MyPlugin模式二:函数导出(兼容旧方式)
def initialize(api):
api.register_hook('on_ui_ready', _on_ui_ready)
def shutdown():
pass| 钩子名 | 参数 | 触发时机 |
|---|---|---|
on_app_start |
无 | 应用启动完成后 |
on_ui_ready |
main_window: SFSMainWindow |
主窗口 UI 就绪 |
on_app_exit |
无 | 应用退出前 |
on_data_loaded |
share_data |
资源数据加载完成 |
on_context_menu_show |
widget, identity, items |
右键菜单弹出前(可注入菜单项) |
on_resource_imported |
type_id, name, success |
资源导入完成后 |
on_resource_deleted |
type_id, name |
资源删除完成后 |
on_font_changed |
new_font_size: int |
全局字体大小变更 |
api.data # 数据访问:资源 CRUD、选中管理、简介加载/保存
api.config # 配置读写:JSON 配置文件读写
api.logger # 日志模块:创建插件的独立日志文件
api.plugin_dir # 当前插件目录路径
api.ui # UI 操作:上下文菜单注入、主窗口访问、对话框创建
api.hooks # 钩子系统:注册/触发钩子、暴露函数供其他插件调用from context_menu_manager import ContextMenuRegistry
registry = ContextMenuRegistry.get_instance()
registry.register_pattern("resource:*:*", [
("自定义菜单项", on_custom_action, True), # (文本, 回调, 是否启用)
])插件可以通过 api.expose_function(name, func) 向全局暴露函数,其他插件通过 api.get_exposed_function(name) 调用。例如 mod_info_extractor 暴露了 extract_mod_info、extract_mod_info_batch、merge_info_to_intro、enhance_mod_intro 四个函数。
UIThemeLoader 单例负责:
- 从
UI/<theme_name>/theme.json读取主题配置 - 加载
GlobalStyle.ui提取 QSS 样式表 - 若主题类型为
palette,额外应用 QPalette 颜色方案 - 主题切换时触发
on_font_changed钩子通知所有插件
| 主题 | 目录 | 类型 |
|---|---|---|
| Nebula Purple | UI/Nebula Purple/ |
qss(默认主题,星云紫) |
| dark | UI/dark/ |
qss(暗色主题) |
| light | UI/light/ |
qss(亮色主题) |
所有 .ui 文件通过 PySide6.QtUiTools.QUiLoader 在运行时动态加载,不使用 pyside6-uic 预编译。这意味着修改 .ui 文件后无需重新编译即可生效。
main.py
├── UserProfile() # 加载用户身份
├── AppSettings() # 加载应用配置
├── PluginAPI.get_instance() # 初始化插件 API
├── PluginManager.load_all() # 发现并加载所有插件
├── resource_loader.start_load() # 构建所有资源索引
│ └── ResourceLoader.load_all()
│ ├── _load_or_build_index() → index.json
│ └── _load_or_build_hash_table() → hash_table.json
├── SFSMainWindow() # 创建主窗口
└── app.exec() # 进入事件循环
用户选择文件
→ ResourceImportScanner.scan_archive()
├── .sfs 格式 → 验证内部结构 → 复制到存储
├── 标准 zip → 检测简介.json → 复制到存储
└── 社区格式 → community_format_detector → 生成简介 → 复制到存储
→ ResourceLoader.rebuild_index_and_hash_table()
→ RESOURCEREACTOR.notify(INDEX_CHANGED)
→ UI 自动刷新
用户点击启动
→ GameManager.start_game()
├── 读取游戏简介 → 定位 exe 路径
├── subprocess.Popen 启动进程
├── game_started 信号 → UI 更新状态
└── ResourceMonitor.start() → 后台监测资源目录
- 数据存储在
C:\ProgramData\SFS_Launcher\user_profile.json(软件卸载后仍保留) - 首次运行时自动生成 UUID 作为唯一用户标识
can_edit(intro_uid)方法:比对简介中的 UID 与当前用户 UID,决定编辑权限master_edit_override标志允许超级用户绕过 UID 检查
编辑任何资源的 简介.json 前,系统会检查:
- 简介中记录的
UID字段 - 若 UID 为空(未设置),允许编辑
- 若 UID 与当前用户匹配,允许编辑
- 否则弹出"无编辑权限"警告
{
"theme": {"current": "star lines"},
"game": {"now_playing_games": "games/my_games/..."},
"display": {
"page_size": 10,
"font_size": 12,
"auto_remember": true,
"info_pop": true
},
"app": {
"version": "1.0.0",
"log_dir": "files/logs",
"export_dir": "files/exports",
"auto_start": false,
"index_update_frequency": 30
},
"user": {"username": "", "uuid": ""}
}discover_themes()— 扫描UI/目录下的主题子目录register_auto_start()/unregister_auto_start()— 通过 Windows 注册表管理开机自启get_intro_path(root_path)— 从now_playing_games推导出游戏简介路径get_game_root_dir(root_path)— 从now_playing_games推导出游戏根目录
logger.py 提供 setup_logger(log_dir_path, log_filename) 函数:
- 创建独立的命名 logger,同时输出到控制台和文件
- 基于
(dir, filename)缓存复用,避免重复创建 handler - 日志文件按月轮转
主要日志文件:
| 日志文件 | 对应模块 |
|---|---|
main.log |
主程序 |
game_manager.log |
游戏进程管理 |
resource_monitor.log |
资源目录监测 |
resource_ops.log |
资源磁盘操作 |
blueprint_loader.log 等 |
各资源加载器 |
项目使用 QUiLoader 在运行时动态加载 .ui 文件。这使得:
- 修改
.ui文件后无需重新编译即可生效 - 主题切换时只需加载不同目录下的同名
.ui文件 - 插件可以自带
.ui文件,无需编译步骤
"我的XX"中的资源通过 Windows Junction(目录符号链接)连接到游戏目录,而非复制文件。优点:
- 存储中的资源保持唯一,节省磁盘空间
- 游戏内修改直接反映到存储中
- 卸载游戏时只需删除链接,不丢失资源数据
每种资源类型有两个层级的版本概念:
- 多版本存储:
简介.json中的版本列表记录所有历史版本及兼容性测试数据 - 活跃版本:
版本.json记录当前在游戏中使用(链接)的版本号
整合包有三类资源来源,系统通过不同机制区分:
- 自带资源(依赖声明)→
简介.json中的整合包依赖字段 - 用户导入资源 →
.sfs_tracked_imports.json追踪文件 - 玩家自创资源 →
ResourceMonitor自动检测并迁移
# 安装依赖
pip install PySide6 Pillow
# 可选:7-Zip 支持 .rar/.7z 解压
# 下载安装 7-Zip 并确保 7z.exe 在 PATH 中
# 运行
python main.py- 在
resource_metadata.py的METADATA中添加新条目 - 在
intro_templates/<Folder>/中放置标准简介.json模板 - 若需要专门的处理逻辑,在
resource_loader/或resource_operations/中添加子类 - 在
UI/各主题目录下添加对应的详情 UI 文件
- 在
UI/下创建新目录 - 编写
theme.json(指定类型:qss或palette) - 放置需要的 UI 文件
- 主题会自动被
discover_themes()发现
参考 plugins/_plugin_template/ 中的完整模板,或阅读现有 7 个简介编辑器插件的实现。
# 使用 PyInstaller
pip install pyinstaller
pyinstaller --onefile --windowed --name "SFS-Launcher" main.py本项目仅供学习和研究使用。
srcEcho