跳至主要内容
SheetForge

常见问题与故障排查

按症状优先给出的解答。每一个导入错误也都会在控制台报告中附带自己的"在哪里/是什么/为什么/怎么办"语句——请先从那里入手。

设置与首次运行

"我在没有 Addressables 的情况下导入了本资源——它能编译吗?为什么导入被锁定了?"

本资源在没有 Addressables 的情况下也能编译:使用 Addressables 的代码被包裹在一个 SHEETFORGE_ADDRESSABLES 版本 define 之后。地址加载和 AssetRef@Group 类型确实需要 com.unity.addressables,因此整条管线(导入·导出·推送·写回)在你安装它之前会保持锁定。每个入口点都会显示一条安装提示并停止——不会有部分运行。

请通过 Package Manager 安装 com.unity.addressables。入门窗口的 Addressables 行带有一个打开 Package Manager按钮,并且这个窗口能正常运行,而不会被 Safe Mode 挡住,因为 Editor 在没有该包时也能编译。

如果安装之后仍然存在编译错误,那么它们来自项目中的其他代码——SheetForge 在有没有该包的情况下都能编译。

"我升级到了新版本,结果项目编译不过了。"

.unitypackage 导入只会新增和更新文件,绝不会删除文件,因此被本产品在后续版本中淘汰的文件可能会残留下来,继续引用一个已经不存在的 API。

编辑器加载时,无依赖的 SheetForge.Setup 引导程序会检测这些已知的淘汰路径,并提议删除它们,在触碰任何文件之前先列出每一条路径。确认对话框后,编译就会恢复正常。因为它存在于自己独立的程序集中,即便主程序集正在编译失败,它依然能正常工作。想彻底跳过这个提示,也可以在导入新包之前先删除 Assets/SheetForge 文件夹。

没有覆盖到的情形是:你自己的代码是针对一个后来被淘汰的契约编写的——这部分需要你借助源码仓库CHANGELOG.md升级说明表手动移植(发行包不附带这个文件),快速上手对其内容做了摘要。

"创建工作表只显示了内置模板——技能演示模板在哪里?/ 我该如何添加自己的模板?"

内置的创建工作表列表自带两种模板——物品示例(仅核心类型),以及用于排布一张 @enum 表的 Enum definitions——外加"从零开始"。

需要插件的领域模板(比如技能演示)由该插件自己来注册,因此只有在插件存在时它们才会出现。导入 Plugin Demo 包,它的技能演示模板就会出现。要发布你自己的模板,请实现 ISheetForgeTemplatePlugin——见插件开发 §4.6。

"我该从哪里开始?/ 打开编辑器时总有一个窗口自动弹出。"

那是入门窗口。它会在编辑器首次加载时自动打开,是推荐的入口——Addressables 状态、选择活动设置资源、导入示例,以及运行你的第一次导入,全都汇集在一处。

可以用底部的**"编辑器启动时显示此窗口"**开关关闭自动弹出,并随时通过 Tools ▸ SheetForge ▸ 入门 重新打开它。

"我导入了一个演示包,但什么都没发生——既没有设置资源,也没有 addressable 组。"

每个演示包都自带一个预先配置好的设置资源,导入该包会自动激活它——但仅当你还没有自己的活动设置时才会这样。如果你已经有了,入门窗口会打开来建议你切换,而不会静默改动你的设置。

然后在 Tools ▸ SheetForge ▸ Data Studio 中按下一次 ↓ Pull from source:这会自动创建 addressable 组和各标签页的地址。流程:导入包 →(设置自动激活)→ 执行导入 → Play

"演示场景只显示了一条文字信息,而不是演示内容。"

演示是按 Addressables 地址加载的,而这些地址只有在你的机器上执行过一次导入之后才会存在(组资源是一个不提交到版本库、可自我修复的缓存)。导入演示包(其设置会被自动激活),然后运行一次执行导入——见快速上手 §5。

(演示中已提交的类型使用默认的 SheetForge.Generated 命名空间,因此不需要设置 generatedNamespace——重新导入会原地重新生成它们。)

"插件演示的首次导入报错 UnknownAssetGroup 'Scripts'。"

插件演示中有一个类型为 List<AssetRef@Scripts>script 列,需要一个名为 Scripts 的 Addressables 组。Addressables 组是按机器区分的(不提交到版本库),因此刚导入的演示还没有这个组。

演示会在导入时自动配置该组(PluginDemoAddressableSetup,在域重载时以及你打开演示场景时触发),所以正常导入本身就能正常工作。如果你仍然看到这个错误,重新打开演示场景(Tools ▸ SheetForge ▸ Open Plugin Demo Scene)以触发该设置,然后重新导入。

这一点只适用于插件演示——你自己的 AssetRef@… 组需要你自行注册。

"如果我有不止一个设置资源,会用哪一个?"

活动的那一个。菜单、Data Studio 和导入操作都会使用活动设置资源。可以在入门窗口或 Data Studio 工具栏的下拉菜单中选择它(只有存在多个设置资源时才会显示)。

如果只有一个设置资源,首次导入会自动选中它。这个选择按项目、按用户存储(一个 EditorPrefs 指针——不会产生版本控制噪音),如果活动资源被删除,会自我修复。

"我已经有一个装着工作表的文件夹了——最快该怎么让 SheetForge 指向它?"

打开 Data Studio,然后把该文件夹(或单个 .tsv/.csv/.xlsx 文件)拖到窗口上。

它会主动提出为你创建一个从该文件夹读取数据的导入设置资源,并将其设为活动,无需手动填写字段。如果你已经有活动设置,对话框会说明这一点,并提供切换的选项。

"怎么检查我的项目是否配置正确 / 为什么导入运行不了?"

在 Data Studio 工具栏中选择 ⋯ ▸ 健康检查。它会报告 ✓/✗ 及建议的修复方法,检查项包括:

  • 活动设置;
  • 来源可达性——本地文件夹是否存在,或 Google id + 服务账号密钥路径——不发起网络请求
  • 导入 baseline;
  • 生成代码/烘焙/addressable 的新鲜度。

结果会输出到控制台,并附带一个汇总对话框。

"菜单和界面用了一种我没有选择过的语言打开。"

项目首次打开时,SheetForge 会根据你编辑器的系统语言来设置界面语言(九种语言有对应映射,其他语言则用英文)。它绝不会覆盖你自己设置过的语言。你可以随时在 Preferences ▸ SheetForge 中更改——参见本地化

(更改语言会触发一次简短的重新编译,因为菜单标签需要重新生成。)

"我克隆了仓库,场景里对烘焙 SO 的引用都变成了 Missing。"

这是预期行为:烘焙出的 SO 是按机器区分的缓存,带有按机器区分的 GUID。绝不要从场景中直接引用它们——请按地址加载(SheetForgeDatabases.LoadAsync("Tab"))。运行一次导入即可重建你本地的缓存。

"我的构建被一条 SheetForge 消息中止了。"

那是构建前的新鲜度检查钩子在保护你,防止你打出一个空的/过期的缓存。请按提示语句所说的去做——在 Tools ▸ SheetForge ▸ Data Studio 中按下 ↓ Pull from source——然后再次构建。

导入与验证

"导入运行了,发现了错误,然后什么都没产出。"

这是设计使然:一个错误 ⇒ 没有输出(不会有部分组装的结果)。报告会列出所有问题,并附带坐标和建议的修复方法——一次性修复它们,然后重新导入。你不会因此丢失任何工作成果;工作表本身不会被触碰。

"我能直接跳转到错误所在的单元格吗?"

可以。人类可读的控制台报告中,每个错误旁边都有一个可点击的**"在 Data Studio 中打开"**链接;点击它会打开 Data Studio、切换到对应标签页并高亮该单元格(文件/标签页级别的错误只会聚焦到标签页)。机器可读的坐标行保持不变,因此不会影响 CI/日志抓取。

"导入写入了代码,重新编译了……完成了吗?"

是的——当架构是新建/已更改时,导入内部会分两个阶段(代码生成 → 编译/重载 → 烘焙),并且烘焙会在重载之后自动继续。请留意控制台中的最终报告。

如果你的游戏代码因此无法再编译了(例如在一次列重命名之后),链条会安全中止,并给出一条可执行的提示语句;修好你的代码,再次导入即可。

"空单元格报错了,但我希望这个单元格是可选的。"

没有标记的类型是必填的(这是一项静默污染防护)。要让一个单元格变为可选,可以:

  • 声明为 float?——类型默认值;
  • 声明为 int=1——显式默认值;
  • 或者使用 List<T>,此时空单元格 = 空列表。

表格语法

"1.5 导入正常,但 1,5 报错了。"

这是刻意为之的:数字与语言环境无关——小数点始终使用 .。逗号小数、NaNInfinity 都会在入口处被拦截。

"导入突然变得非常慢。"

导入耗时与你的数据规模呈线性关系(50k 行 × 20 列,编辑器内 ≈ 628 ms),即便同时有大量引用破坏,也依然保持线性——最接近匹配的搜索按字段设有预算,并经过长度预筛选(4,000 条损坏引用时 ≈ 45 ms,无头模式)。

如果某次导入耗时突然远超这个水平,该关注的是工作表的大小,而不是错误的数量。

"出现未知标记 / 未知类型错误,并带有'你是不是想输入'的提示。"

@marker 名称、类型名称或 enum 成员中的拼写错误都是错误,并带有最接近的匹配建议——采纳该建议即可。带 @ 的未注册类型名同样是一个错误(这是为 RecordId@Tab 这类引用提供的拼写错误安全保障)。

Google表格

"Google 导入报错 PERMISSION_DENIED(403)。"

该表格没有与服务账号的 client_email 地址共享——仅凭密钥本身不会授予任何权限。打开 JSON 密钥文件,复制 client_email,然后把该表格共享给这个地址(导入用 Viewer,推送用 Editor)。完整流程见Google表格设置

"推送提示需要 SheetsApi。"

你目前处于 ExportUrl 模式,该模式是只读的(无需认证)。任何写回操作都需要带有服务账号密钥的 SheetsApi 模式。见数据源、导出与推送。创建服务账号与密钥的完整步骤见Google表格设置

"ExportUrl 导入失败,提示需要 gid 映射表。"

这是必需的:没有 gid 的导出 URL 会静默地只返回第一个标签页,因此该映射表(标签页名称 → #gid=)是强制要求的。或者改用 SheetsApi 模式,它不需要映射表。

"推送报告说有单元格被跳过了。"

发送前的实时重新获取发现了冲突(队友编辑了某个单元格、某一行发生了移动/消失、出现了重复的键)。被跳过的单元格是一种保护,而不是失败——报告会显示已应用/已跳过的计数。先重新导入以进行协调,然后再次推送。

"我在本地删除了一些行,但推送之后它们仍然在 Google 工作表里。"

行删除操作永远不会被推送(针对一个实时工作表进行按位置的删除是不安全的)——你只会收到一条通知。请在工作表中删除这些行,然后重新导入。

创作

"Ctrl+Z 撤销不了我暂存的更改。"

有两个边界:

  • 一个获得焦点的文本框会优先消费 Ctrl+Z——先点击别处,再撤销;
  • 在"反映到工作表"成功之后,暂存历史会被清空,因此撤销只在反映前的这段会话内有效。

反映之后,请编辑工作表本身(它才具有权威性)。

"我的一些暂存编辑显示了'隔离'徽标,没有被反映。"

工作表在暂存和反映之间发生了外部更改,破坏了那些编辑的逻辑地址(行的键在外部被重命名 / 行被删除 / 键冲突)。它们被排除在外——不是被静默丢失,也不会阻塞其余部分。请逐条丢弃它们,并针对新的 baseline 重新暂存。

"我重命名了一个列/标签页,现在我的游戏代码编译不过了。"

这是预期行为,并且确认对话框中已经说明过:重命名会改变生成的字段名/类名。请更新你的游戏代码;导入链会在下一次运行时完成。该列的数据取值被完整保留了。

"我可以在一个批次里互换两个标签页的名称(A↔B),或者按循环重命名标签页吗?"

可以——互换与循环重命名(A→B→C→A)都可以在单个批次内暂存并反映,UI 只会拒绝真正的冲突:两个重命名指向了同一个名称。引用会跟随数据走,并被原子化地重写。

在 Google 上还遗留一处边界情况:两个互换的标签页如果互相引用,则不会被重新指向(本地路径是完全正确的)。请让这个相互引用改为经由第三个标签页中转,或者通过一个中间名称来反映。见Data Studio功能与限制

"我的键重命名没有更新我在同一批次里刚输入的一处引用。"

传播只会重写 baseline 中的单元格——绝不会重写你刚刚输入的文本(不会静默重写刚输入的内容)。预检会标记出这个悬空引用;请自己修复它。

"反映因为一个 xlsx 标签页而被拒绝了。"

有两种已知情形:

  • xlsx 来源的标签页无法重命名(工作簿保护);
  • 会触及 xlsx 标签页的键重命名传播会阻塞整个批次(不允许部分反映)。

请直接编辑该工作簿,然后重新导入。

"我在面板里编辑了一个烘焙的 SO,结果被重新导入清空了。"

这是设计使然——工作表才是唯一真实来源,SO 只是一个缓存。面板中的"测试编辑"开关被明确设计为临时性的。真正的更改请通过工作表或 Data Studio 来进行。

导出及其他

"导出因为架构不匹配而失败了。"

你的烘焙结果相对于一次架构变更来说是过期的(ExportSchemaMismatch——指纹校验)。请先运行一次导入以完成代码生成 + 烘焙,然后再导出/推送。

"我导出的浮点数显示为 1,但工作表里原本是 1.0。"

这是语义化往返:数值被精确保留;记法会归一化为最短的可往返形式。结构(标记、列顺序、注释、你写的文本)会被 100% 保留。

"xlsx 导入拒绝了一些单元格。"

内置的 OOXML 读取器刻意保持精简。有三样东西是不支持的:

  • 没有缓存值的公式单元格;
  • 错误单元格;
  • 单元格内的制表符/换行符。

请将公式具化为值;用 ; 表示列表。

"我现在没法更改编辑器语言。"

在导入/导出/推送运行期间,语言更改会被锁定(更改语言会触发一次菜单文件再生成 + 简短的重新编译)。请等管线运行完毕。

"即便我的语言是韩语/日语/……,我的错误报告有些部分仍然是英文的。"

报告骨架以及"为什么"/"怎么办"语句是本地化的;运行时插值的细节内容(出问题的值、建议)以及底层日志则是内嵌英文——这是标准的本地化边界。

"克隆之后,Tools ▸ SheetForge ▸ … 菜单项去哪儿了?"

本地化的菜单文件是生成出来的(已被 Git 忽略)——它会在编辑器加载时自我修复。如果标签显示的语言不对,它们会在下一次语言更改或编辑器启动时重新生成。

相关页面