diff --git a/App/Program.cs b/App/Program.cs index ee4de0ca..1c4ecaeb 100644 --- a/App/Program.cs +++ b/App/Program.cs @@ -19,7 +19,8 @@ internal static class Program var options = AppOptions.FromArgs(args); var baseDirectory = AppPaths.BaseDirectory; - var moduleStore = new ModuleStore(ModuleStore.ResolveModuleDirectory(baseDirectory)); + var moduleStore = new ModuleStore(ModuleStore.ResolveModuleDirectory()); + ShowModuleMigrationHint(baseDirectory, moduleStore); var triggerKeyState = new WindowsTriggerKeyState(); var processLocator = new WowProcessLocator(baseDirectory); var runtimeFactory = new ShigureRuntimeFactory(baseDirectory, moduleStore, triggerKeyState, processLocator); @@ -33,4 +34,37 @@ internal static class Program processLocator, runtimeSession)); } + + // 模块目录迁移提示:旧目录(baseDirectory/module)存在且有内容、且新目录(用户配置目录)尚无模块文件时, + // 弹一次纯文案提示,引导用户手动移动模块;条件不满足或检测异常时静默,不影响启动。 + private static void ShowModuleMigrationHint(string baseDirectory, ModuleStore moduleStore) + { + try + { + var oldDirectory = Path.Combine(baseDirectory, "module"); + if (!Directory.Exists(oldDirectory) + || !Directory.EnumerateFileSystemEntries(oldDirectory).Any()) + { + return; + } + + // 新目录以是否存在模块文件(.json)判空,避免保存崩溃残留的 .tmp 原子写文件阻断提示。 + if (Directory.EnumerateFiles(moduleStore.ModuleDirectory, "*.json", SearchOption.AllDirectories).Any()) + { + return; + } + + MessageBox.Show( + $"模块目录已迁移到用户配置目录。\n\n" + + $"新的模块目录:\n{moduleStore.ModuleDirectory}\n\n" + + $"请将旧目录 {oldDirectory} 中的模块文件手动移动到新目录。", + "Shigure", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + catch + { + // 检测或提示异常时静默跳过,避免影响启动。 + } + } } diff --git a/CLAUDE.md b/CLAUDE.md index b372245a..ae8f5dc3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -20,7 +20,7 @@ dotnet run --project .\Shigure.csproj -- --toggle XBUTTON2 --mode switch --logic - **没有测试项目**:验证 = 能编译 + 实际运行点开「设置」走查。`dotnet build` 干净通过(0 警告 0 错误)是基线要求。 - 启动参数见 [README.md](README.md#运行)(`--toggle/--mode/--logic-ms/--render-ms`),解析在 [App/AppOptions.cs](App/AppOptions.cs)。目标进程名来自 `wow_process.txt`。 -程序直接从当前 EXE 所在目录运行;`AppPaths.BaseDirectory` 即 `AppContext.BaseDirectory`,配置、按键映射、模块和插件源码均从该目录读取。 +程序直接从当前 EXE 所在目录运行;`AppPaths.BaseDirectory` 即 `AppContext.BaseDirectory`,配置、按键映射和插件源码均从该目录读取;模块从用户配置目录读取(`ModuleStore.ResolveModuleDirectory()`,见下)。 ## 架构与数据流 @@ -53,13 +53,14 @@ Input/ keymap 读取、按键发送、Win32 API Infrastructure/ 配置读取(ConfigService)、JSON 辅助、UI 缓存、路径、Fuyutsui 插件文件读写 UI/ WinForms 界面、编辑器、主题 Fuyutsui/ 内置插件权威源;构建/发布时完整复制,运行时部署到游戏 AddOns -config/ keymap/ module/ 运行时 JSON 数据(构建时复制到输出, 见 .csproj 的 None+CopyToOutputDirectory) +config/ keymap/ 运行时 JSON 数据(构建时复制到输出, 见 .csproj 的 None+CopyToOutputDirectory) +module 运行时模块数据位于用户配置目录 ~/.config/Shigure/module(启动时自动创建, 不随构建复制) wow_process.txt 目标游戏进程名列表;构建时复制,运行期间每次定位都会重新读取 ``` ## 模块解析(改逻辑前必读) -- 模块以 `module/模块名.json` 平铺保存,**文件名取自模块名,故模块名不可重复**;加载递归扫描子目录。模型在 [Modules/ModuleStore.cs](Modules/ModuleStore.cs)(`ModuleDefinition`/`ModuleMatch`/`ModuleRule`/`ModuleUnit`/`ModuleCountField`/`ModuleValueAdjustment`)。`RecommendedTalent` 是 `ModuleDefinition` 上的纯展示字段,不参与匹配(`ModuleMatch.Specificity` 不计入)。 +- 模块以 `~/.config/Shigure/module/模块名.json` 平铺保存(`ModuleStore.ResolveModuleDirectory()` 返回用户配置目录,`{UserProfile}/.config/{程序集名}/module`),**文件名取自模块名,故模块名不可重复**;加载递归扫描子目录。模型在 [Modules/ModuleStore.cs](Modules/ModuleStore.cs)(`ModuleDefinition`/`ModuleMatch`/`ModuleRule`/`ModuleUnit`/`ModuleCountField`/`ModuleValueAdjustment`)。`RecommendedTalent` 是 `ModuleDefinition` 上的纯展示字段,不参与匹配(`ModuleMatch.Specificity` 不计入)。 - `ModuleStore` 的 `Reload`/`Save`/`Delete` 会在同一个门锁内串行完整文件事务与内存快照更新;`Save` 通过同目录临时文件提交,重命名失败会回滚新文件。编辑器写入不要绕过它,避免运行时读到半次操作。运行时工厂不再自行 `Reload`:启动和模块刷新先由 `ModuleDependencyService` 导入依赖、拒绝宏容量超限模块,再把已验证的内存快照交给运行时。 - 职业/专精明确的模块保存时会写入 `Dependencies` 快照。`ModuleDependencyService` 以本地为优先追加缺失的 ClassBlocks/spellsList/ClassMacros,按动态宏 30 槽、其它宏 1 槽检查所有受影响专精;任一专精超过 keymap 容量就拒绝整个模块且不写 Lua。依赖提交失败会恢复配置和宏原文。 - 选择优先级:`ModuleStore.FindSelectedOrBestMatch` —— 先用 UI/参数选定的 `ModuleId`;否则取 `Match` 命中字段最多者(`ModuleMatch.Specificity` 越大越优先),并列按名称。`Match` 字段留空 = 任意。`PartyType` 数字会归一化为 `"1-40"`。 diff --git a/Infrastructure/AppInfo.cs b/Infrastructure/AppInfo.cs index 1b2a45d7..5a21abbd 100644 --- a/Infrastructure/AppInfo.cs +++ b/Infrastructure/AppInfo.cs @@ -3,11 +3,14 @@ using System.Reflection; namespace Shigure; /// -/// 应用版本信息的单一来源。优先取 csproj 的 <Version>(AssemblyInformationalVersion), -/// 退化到 AssemblyVersion。 +/// 应用名称与版本信息的单一来源:AppName 取自程序集名, +/// Version 优先取 csproj 的 <Version>(AssemblyInformationalVersion),退化到 AssemblyVersion。 /// internal static class AppInfo { + // 取自程序集名(重命名程序集时自动跟随),与 Version 从程序集读取的惯例一致。 + public static string AppName { get; } = Assembly.GetExecutingAssembly().GetName().Name ?? "Shigure"; + public static string Version { get; } = ResolveVersion(); private static string ResolveVersion() diff --git a/Modules/ModuleStore.cs b/Modules/ModuleStore.cs index 9fd52f42..aa8a4be2 100644 --- a/Modules/ModuleStore.cs +++ b/Modules/ModuleStore.cs @@ -289,15 +289,13 @@ public sealed class ModuleStore public string ModuleDirectory { get; } - public static string ResolveModuleDirectory(string baseDirectory) + public static string ResolveModuleDirectory() { - var currentModuleDirectory = Path.Combine(baseDirectory, "module"); - if (Directory.Exists(currentModuleDirectory) || File.Exists(Path.Combine(baseDirectory, "Shigure.csproj"))) - { - return currentModuleDirectory; - } - - return Path.Combine(baseDirectory, "module"); + return Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".config", + AppInfo.AppName, + "module"); } public IReadOnlyList GetModules() diff --git a/Obsidian/30-Shigure/00-Shigure-MOC.md b/Obsidian/30-Shigure/00-Shigure-MOC.md index 13a1e35e..60a4732f 100644 --- a/Obsidian/30-Shigure/00-Shigure-MOC.md +++ b/Obsidian/30-Shigure/00-Shigure-MOC.md @@ -89,7 +89,7 @@ Program.Main | 状态步骤映射 | ClassBlocks Lua,经转换器生成 | `ConfigService` / `StateBuilder` | `config/*.json` | | 法术宏到键位 | ClassMacros Lua,经转换器生成 | `KeymapService` | `keymap/*.json` | | 游戏插件副本 | 项目内置 `Fuyutsui/` | WoW AddOn 加载器 | `Interface/AddOns/Fuyutsui` | -| 行为规则 | 模块编辑器或手工 JSON | `ModuleStore` / `ModuleLogic` | `module/*.json` | +| 行为规则 | 模块编辑器或手工 JSON | `ModuleStore` / `ModuleLogic` | `~/.config/Shigure/module` | | UI 缓存与偏好 | WinForms 界面 | WinForms 界面 | `cache/` | | 运行状态 | `ShigureRuntime` 单循环 | `StatusForm` | `RenderSnapshot`,不持久化 | diff --git a/Obsidian/30-Shigure/01-Shigure-启动随机副本与会话协调.md b/Obsidian/30-Shigure/01-Shigure-启动随机副本与会话协调.md index f3f6edf5..7caf5562 100644 --- a/Obsidian/30-Shigure/01-Shigure-启动随机副本与会话协调.md +++ b/Obsidian/30-Shigure/01-Shigure-启动随机副本与会话协调.md @@ -73,7 +73,7 @@ verified_at: 2026-08-10 ## 核心数据与不变量 -- 随机子进程**不复制业务数据目录**;`config`、`keymap`、`module`、`cache` 仍由原始根目录提供。 +- 随机子进程**不复制业务数据目录**;`config`、`keymap`、`cache` 仍由原始根目录提供,模块由用户配置目录 `~/.config/Shigure/module` 提供。 - `SHIGURE_RANDOMIZED_PROCESS=1` 是防递归开关。外部若伪造相关环境变量,也会改变启动和路径行为。 - 清理范围是按源 EXE 路径哈希隔离的专属临时根目录;清理会递归删除其所有子项并吞掉 IO/权限异常。 - 每次会话构造新的 `ConfigService`、`KeymapService`、`PixelScanner`、`StateBuilder`、`KeySender` 和 `LogicRegistry`;`ModuleStore` 与触发键读取器跨会话共享。 diff --git a/Obsidian/30-Shigure/10-Shigure-UI功能地图与数据所有权.md b/Obsidian/30-Shigure/10-Shigure-UI功能地图与数据所有权.md index 2c22d397..8f4d0b92 100644 --- a/Obsidian/30-Shigure/10-Shigure-UI功能地图与数据所有权.md +++ b/Obsidian/30-Shigure/10-Shigure-UI功能地图与数据所有权.md @@ -56,7 +56,7 @@ verified_at: 2026-08-10 | `MainForm` 浮条 | 启停、打开设置/状态、关闭、拖动 | 会话状态、UI 缓存 | `SetEnabled`、重启/停止、窗口偏好 | | 通用设置 | 触发键、模式、模块选择、配置生成与插件部署 | `AppOptions`、模块目录、项目 Fuyutsui | 缓存/设置、会话重启、同步队列 | | `StatusForm` | 九个状态/诊断页 | `RenderSnapshot`、日志 | 不拥有运行状态 | -| 模块编辑器 | 匹配、规则、动态单位、数量、调整/公式、排序 | 模块快照 | `module/*.json` | +| 模块编辑器 | 匹配、规则、动态单位、数量、调整/公式、排序 | 模块快照 | `~/.config/Shigure/module` | | ClassBlocks 编辑器 | 职业/专精状态块编辑 | `Fuyutsui/class/*.lua` 项目源 | ClassBlocks table、config、当前 Lua 游戏部署 | | ClassMacros 编辑器 | common/spec/static/special 宏编辑 | `Fuyutsui/core/classmacros.lua` 项目源 | ClassMacros table、keymap、当前 Lua 游戏部署 | | 条件/单位对话框 | 构造受限条件和动态定义 | 当前草稿 | 返回编辑器内存模型 | diff --git a/Obsidian/30-Shigure/11-Shigure-本地数据路径构建与验证.md b/Obsidian/30-Shigure/11-Shigure-本地数据路径构建与验证.md index 0f49d4ff..48458957 100644 --- a/Obsidian/30-Shigure/11-Shigure-本地数据路径构建与验证.md +++ b/Obsidian/30-Shigure/11-Shigure-本地数据路径构建与验证.md @@ -41,7 +41,7 @@ verified_at: 2026-08-10 # Shigure 本地数据、路径、构建与验证 > [!abstract] AI 快速摘要 -> Shigure 的业务根目录通常是正式 EXE 所在目录;随机副本子进程通过环境变量仍指回该目录。程序从这里读取内置 `Fuyutsui/`、`config`、`keymap`、`module`、`cache` 和 `wow_process.txt`。项目插件是权威源,目标游戏中的 Fuyutsui 只是由部署服务维护的运行副本。项目是无第三方 NuGet 引用的 `net10.0-windows` WinForms WinExe,仓库没有测试项目。 +> Shigure 的业务根目录通常是正式 EXE 所在目录;随机副本子进程通过环境变量仍指回该目录。程序从这里读取内置 `Fuyutsui/`、`config`、`keymap`、`cache` 和 `wow_process.txt`;模块从用户配置目录 `~/.config/Shigure/module` 读取。项目插件是权威源,目标游戏中的 Fuyutsui 只是由部署服务维护的运行副本。项目是无第三方 NuGet 引用的 `net10.0-windows` WinForms WinExe,仓库没有测试项目。 ## 图谱位置 @@ -65,7 +65,7 @@ verified_at: 2026-08-10 AppContext.BaseDirectory = 随机临时目录(仅运行依赖) ``` -这使随机 EXE 可以加载临时目录 DLL,同时配置和用户数据仍落在正式安装目录。环境变量属于信任边界:若外部预先设置/篡改,可能改变业务数据根目录。 +这使随机 EXE 可以加载临时目录 DLL,同时配置、Keymap 和缓存等数据仍落在正式安装目录;模块则在用户配置目录(子进程与父进程同属一个 Windows 用户,解析结果一致)。环境变量属于信任边界:若外部预先设置/篡改,可能改变业务数据根目录。 ## 本地数据地图 @@ -74,7 +74,7 @@ verified_at: 2026-08-10 | `config/common.json` | 协议固定字段 | `ConfigService` | 打包内容/人工维护 | | `config/.json` | 13 职业和专精步骤映射、法术元数据 | `ConfigService`, `StateBuilder` | `FuyutsuiConfigConverter` | | `keymap/*.json` | unit/spell/macroCondition→hotkey | `KeymapService`, `KeymapCatalog` | `FuyutsuiKeymapConverter` | -| `module/**/*.json` | 匹配、规则、动态值和公式 | `ModuleStore` | 模块编辑器/人工 | +| `~/.config/Shigure/module/**/*.json` | 匹配、规则、动态值和公式 | `ModuleStore` | 模块编辑器/人工 | | `cache/` | 窗口和 UI 偏好 | UI 基础设施 | MainForm/各 UI | | `Fuyutsui/class/*.lua` | 内置 ClassBlocks 权威源 | ClassBlocks Store/转换器 | ClassBlocks 编辑器/人工 | | `Fuyutsui/core/classmacros.lua` | 内置宏权威源 | ClassMacros Store/转换器 | 宏编辑器/人工 | @@ -99,7 +99,7 @@ verified_at: 2026-08-10 - 开启 nullable 与 implicit usings。 - 应用版本在项目文件中为 1.2.1,并被模块编辑器保存到模块元数据。 - 项目没有 `PackageReference`;核心只依赖 .NET/WinForms/System.Drawing 和 Win32 P/Invoke。 -- 项目文件声明嵌入 UI assets,并把 `Fuyutsui/**`、配置、Keymap、模块和 `wow_process.txt` 按规则复制到输出;Fuyutsui 同时明确复制到 publish。 +- 项目文件声明嵌入 UI assets,并把 `Fuyutsui/**`、配置、Keymap 和 `wow_process.txt` 按规则复制到输出;Fuyutsui 同时明确复制到 publish。模块不随构建/发布复制,由用户配置目录 `~/.config/Shigure/module` 提供。 - 实际打包策略还应对照 `打包说明.md`;随机启动器只复制正式输出目录**顶层**运行依赖到临时目录。 ## 当前验证能力 diff --git a/README.md b/README.md index 05b7a5c8..b3a92b3c 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Shigure 是一个 Windows WinForms 桌面程序。它从目标窗口读取 Fuyut - `日志`:记录启动、停止、职业识别、模块匹配、逻辑状态、施放步骤、配置同步和异常。 - `关于`:显示产品、公司、版本、模块目录和配置目录。 -触发键、发送模式、模块选择、模块保存以及配置同步都会按需重启运行循环。窗口位置、大小、模块选择和表格列宽等 UI 状态保存在 `cache/window-state.json`。`module/` 与 `cache/` 都是本地数据,默认不提交到 Git。 +触发键、发送模式、模块选择、模块保存以及配置同步都会按需重启运行循环。窗口位置、大小、模块选择和表格列宽等 UI 状态保存在 `cache/window-state.json`;模块保存在用户配置目录 `~/.config/Shigure/module`。`cache/` 与模块数据都是本地数据,默认不提交到 Git。 ## 环境要求 @@ -87,7 +87,7 @@ dotnet run --project .\Shigure.csproj -- --toggle XBUTTON2 --mode switch --logic - `click`:每次按下只执行一轮逻辑。 - `hold`:按住时运行,松开后停止。 -程序会直接从当前 EXE 所在目录运行,并从该目录读取 `Fuyutsui/`、`config/`、`keymap/`、`module/` 和 `wow_process.txt`。 +程序会直接从当前 EXE 所在目录运行,并从该目录读取 `Fuyutsui/`、`config/`、`keymap/` 和 `wow_process.txt`;模块从用户配置目录 `~/.config/Shigure/module` 读取。 ## 构建 @@ -95,7 +95,7 @@ dotnet run --project .\Shigure.csproj -- --toggle XBUTTON2 --mode switch --logic dotnet build .\Shigure.csproj ``` -应用图标为 `Assets\arasaka-icon.ico`。项目会把 `Fuyutsui/**`、`config/*.json`、`keymap/*.json`、本地 `module/**/*.json` 和 `wow_process.txt` 复制到输出/发布目录;图标、职业图和专精图作为嵌入资源打包。 +应用图标为 `Assets\arasaka-icon.ico`。项目会把 `Fuyutsui/**`、`config/*.json`、`keymap/*.json` 和 `wow_process.txt` 复制到输出/发布目录;图标、职业图和专精图作为嵌入资源打包。 ## 项目结构 @@ -111,7 +111,7 @@ Assets\ 应用图标、品牌资源、职业图和专精图 Fuyutsui\ 权威插件源码、配置/宏编辑源及游戏部署源 config\ 由 Fuyutsui 职业配置生成的扫描映射 keymap\ 由 Fuyutsui 职业宏生成的按键映射 -module\ 本地模块(运行后或在 UI 中保存时创建) +module\ 模块示例模板(运行时模块保存在用户配置目录 `~/.config/Shigure/module`) Tools\ 辅助脚本 ``` @@ -159,9 +159,9 @@ Tools\ 辅助脚本 ## 模块系统 -模块以 `模块名.json` 保存在 `module/`。名称不能重复;加载时会递归扫描子目录,以兼容旧版布局。模块页保存时会写入当前 Shigure 版本。职业和专精均已指定时,模块还会携带该专精的 `ClassBlocks`、职业 `spellsList`,以及该职业的通用/专精动态宏、静态宏和特殊宏;旧模块没有这些依赖信息时仍可正常使用。 +模块以 `模块名.json` 保存在用户配置目录 `~/.config/Shigure/module`。名称不能重复;加载时会递归扫描子目录,以兼容旧版布局。模块页保存时会写入当前 Shigure 版本。职业和专精均已指定时,模块还会携带该专精的 `ClassBlocks`、职业 `spellsList`,以及该职业的通用/专精动态宏、静态宏和特殊宏;旧模块没有这些依赖信息时仍可正常使用。 -启动和“刷新模块”会把模块携带而本地缺少的配置与宏追加到项目 `Fuyutsui/`,不会覆盖或删除本地已有条目。发生新增后会自动重建 `config/keymap`、同步游戏插件并按需重启运行。导入前会按每项动态宏 30 个槽位、静态/特殊宏各 1 个槽位检查该职业所有受影响专精;合并结果超过 273 个槽位时,整个模块不会进入模块列表或运行时,本地 Lua 也不会被修改。模块文件仍保留在 `module/`,清理宏后可刷新重试。 +启动和“刷新模块”会把模块携带而本地缺少的配置与宏追加到项目 `Fuyutsui/`,不会覆盖或删除本地已有条目。发生新增后会自动重建 `config/keymap`、同步游戏插件并按需重启运行。导入前会按每项动态宏 30 个槽位、静态/特殊宏各 1 个槽位检查该职业所有受影响专精;合并结果超过 273 个槽位时,整个模块不会进入模块列表或运行时,本地 Lua 也不会被修改。模块文件仍保留在模块目录,清理宏后可刷新重试。 模块匹配字段: diff --git a/Shigure.csproj b/Shigure.csproj index d4376026..03f16b4e 100644 --- a/Shigure.csproj +++ b/Shigure.csproj @@ -30,7 +30,6 @@ - diff --git a/UI/ModuleEditorControl.cs b/UI/ModuleEditorControl.cs index 6b569665..09951cca 100644 --- a/UI/ModuleEditorControl.cs +++ b/UI/ModuleEditorControl.cs @@ -3031,7 +3031,7 @@ public sealed class ModuleEditorControl : UserControl private void OpenModuleFolder() { - var moduleDirectory = ModuleStore.ResolveModuleDirectory(_baseDirectory); + var moduleDirectory = ModuleStore.ResolveModuleDirectory(); var filePath = _selectedModule?.FilePath; try { diff --git a/UI/StatusForm.cs b/UI/StatusForm.cs index eea9a6ff..6225f962 100644 --- a/UI/StatusForm.cs +++ b/UI/StatusForm.cs @@ -737,7 +737,7 @@ public sealed class StatusForm : Form AddAboutRow(details, "类型", "冲锋枪"); AddAboutRow(details, "介绍", "它一分钟打出去的子弹比荒坂偷的税还要多。"); AddAboutRow(details, "用途", "有时人们只想把子弹全打出去,在硝烟过后品味眼前的一片狼藉。"); - var modulePath = ModuleStore.ResolveModuleDirectory(AppPaths.BaseDirectory); + var modulePath = ModuleStore.ResolveModuleDirectory(); var configPath = ConfigService.ResolveConfigPath(AppPaths.BaseDirectory); AddAboutRow(details, "模块目录", FormatAboutPath(modulePath), modulePath); AddAboutRow(details, "配置目录", FormatAboutPath(configPath), configPath); @@ -862,6 +862,13 @@ public sealed class StatusForm : Form var baseDirectory = Path.GetFullPath(AppPaths.BaseDirectory); var fullPath = Path.GetFullPath(path); var relativePath = Path.GetRelativePath(baseDirectory, fullPath); + // 路径位于 exe 目录之外时直接显示完整路径,避免冗长的 ..\..\ 相对路径文本。 + if (relativePath == ".." + || relativePath.StartsWith(".." + Path.DirectorySeparatorChar, StringComparison.Ordinal)) + { + return fullPath; + } + return string.IsNullOrWhiteSpace(relativePath) ? "." : relativePath; } catch diff --git a/打包说明.md b/打包说明.md index d06e9cc4..352bbed7 100644 --- a/打包说明.md +++ b/打包说明.md @@ -138,12 +138,13 @@ artifacts\publish\win-x64 Fuyutsui config keymap -module wow_process.txt ``` 其中插件目录是插件权威源,程序会在启动或“更新配置”时把它部署到已运行游戏的 `Interface\AddOns\插件名称`;`Assets` 中的图标和职业/专精图片已作为资源嵌入程序,不要求单独分发。上述运行数据会在发布时复制到输出目录,最稳妥的方式仍是把 `win-x64` 整个文件夹压缩成 zip 再发送。 +模块不随发布包分发:模块保存在用户配置目录 `~/.config/Shigure/module`(首次运行自动创建),全新用户首次启动模块列表为空。使用改名脚本打包时该目录随程序名变化,例如改名为 `MyShigure` 后为 `~/.config/MyShigure/module`。 + 不要只发送单个 exe,也不要删除发布目录中的插件目录。如果缺少内置插件目录,配置/宏编辑和游戏插件部署都会失败。 ## 7. 常见问题