快速上手
环境要求
- Unity 6(在 6000.0.79f1、URP 模板上开发和测试)。
- Addressables 包(
com.unity.addressables)——必需依赖。 地址加载是运行时路径,AssetRef@Group类型也需要 Addressables。- 没有该包,本资源依然可以编译,因为所有使用 Addressables 的代码都被包裹在一个
SHEETFORGE_ADDRESSABLES版本 define 之后。 - 但管线——导入·导出·推送·创作写回——会保持锁定。每个入口点都会显示一条安装提示,入门窗口会引导你完成安装。
- 没有该包,本资源依然可以编译,因为所有使用 Addressables 的代码都被包裹在一个
安装 Addressables
- 主要路径:当你从 Asset Store 导入本资源时,"Package Manager Dependencies" 提示会在编译之前出现——选择 Install,Addressables 就会随之一起安装。
- 安全网:如果你点击了 Skip(或手动导入),管线会保持锁定状态,入门窗口会通过其中的 Addressables 状态行引导你完成安装。该窗口即便在没有 Addressables 时也能运行,因为 Editor 仍然可以编译。
- 无依赖的
SheetForge.Setup引导窗口也会在编辑器加载时检测缺失的包,并在每个会话中显示一次通知。因为它没有任何依赖,即便其他编译错误阻塞了主程序集,它依然能正常工作。
- 无依赖的
- 没有一键式程序化安装:Asset Store 的上架规则限制了以程序方式安装包,因此改由引导窗口来指引你完成安装。
- 该通知会反映真实的安装状态。它说明产品可以正常编译,但其功能会在安装该包之前保持锁定,并在之后引导你前往入门窗口。你可以随时通过 Tools ▸ SheetForge ▸ Addressables 设置 重新打开它(即便主程序集因其他原因编译失败,这个菜单依然可用)。
从旧版本升级
.unitypackage 导入只会新增和更新文件,绝不会删除文件。因此,被新版本淘汰的文件可能会残留在 Assets/SheetForge 中,继续引用一个已经不存在的 API。编译因此中断,看起来就像升级把你的项目搞坏了。有两道防线覆盖这个问题:
- 自动检测。 编辑器加载时,无依赖的
SheetForge.Setup引导程序会检查本产品已淘汰的路径。如果发现任何一个,就会提议删除它们——会先在对话框中列出每一个路径,在你确认之前不会触碰任何文件。它之所以存在于自己独立的程序集中,正是为了能在它本应修复的那些编译错误发生时依然存活。 - 清空重来。 若要确保升级绝对干净,先删除现有的
Assets/SheetForge文件夹,导入新包,然后执行一次执行导入,把删除时一并带走的东西重新建出来。设置资源和烘焙 SO(Assets/SheetForgeBaked)都在这个文件夹之外,不受影响;生成代码只要落在默认位置Assets/SheetForgeGenerated,同样不受影响。如果你的项目此前仍在旧的产品内部位置(Assets/SheetForge/Runtime/Generated)生成代码,删除该文件夹会连同那些代码一起清除,重新导入会转而把代码写到Assets/SheetForgeGenerated。这就是把现有项目迁移到新位置的官方支持做法。任何重新导入都无法找回的,只有你自己放进Assets/SheetForge里的东西(保存在那里的设置资源、你自己的插件脚本、工作表文件),所以只需要先把这些移出来。
有一条边界值得明确说明:这项自动清理只会删除 SheetForge 自身已淘汰的文件,绝不会删除你的文件。如果你自己的插件代码实现了一个后来被淘汰的契约,就需要手动移植。简而言之:
- 按标签页的图形构建器(
IGraphShapeBuilder/GraphSpecBuilder)变成了记录画布的增强器(IRecordCanvasAugmenter/CanvasAugmentBuilder)——它是在画布已经构建好的闭包上进行叠加,而不是构建整幅图; GraphMode已经消失,因为方向现在由画布自己掌控;StudioGraphContext.ShapeId/ModeId依然可以编译,但各自都只返回一个常量,因此任何针对它们的AppliesTo比较都应该直接删除;IAuthorableGraphShape.CreatableTabs没有变化。
每个被淘汰的契约具体变成了什么,完整对照表在源码仓库中 CHANGELOG.md 的升级说明一节(发行包不附带它)。已淘汰但仍可编译的成员会被标记为 [Obsolete] 而不是直接移除,因此升级会把它们显示为警告,而不是导致构建失败。
入门窗口(从这里开始)
安装好 Addressables 之后,入门窗口会每个编辑器会话自动打开一次——每次 Editor 启动都会打开,但域重载后不会再次打开。只要它的**"编辑器启动时显示此窗口"**开关处于开启状态(默认即为开启),它就会一直保持这样。
它是推荐的入口。你可以随时通过 Tools ▸ SheetForge ▸ 入门 重新打开它,并通过底部的这个开关关闭自动弹出(该选择按项目、按用户存储)。
它把整个首次运行流程汇集在一处:
- 状态仪表盘——三行红绿灯:Addressables 是否已安装、是否存在活动的导入设置资源、以及首次导入是否已完成。每一行都会显示 ✓ 或 ✗,仍需处理的项旁边会直接带一个操作按钮(新建设置资源,或执行导入)。
- 导入设置——列出每一个
SheetForgeSettings资源,并带有单选按钮用于选择活动资源,此外还有 新建设置资源 按钮和用于定位各资源的 显示 按钮。 - 示例——一键即可导入 Plugin Demo 或 Core Demo 包。
- 从模板开始——选择内置的两种模板之一,选择"从零开始"以自行定义字段,或使用一个插件注册的模板。点击 使用 会打开 Data Studio 的创建面板并预先填好这些内容。此功能需要一个带有可写来源的活动设置资源;如果你还没有,该要求会被明确展示出来(而不是被隐藏)。
- 内置的两种模板分别是物品示例(仅使用核心类型)和 Enum definitions(用于排布一张
@enum表)。 - 只有当存在提供模板的插件——例如 Plugin Demo——时,技能演示的标签页才会出现在这里。
- 内置的两种模板分别是物品示例(仅使用核心类型)和 Enum definitions(用于排布一张
- 运行——执行导入(使用活动设置)以及 打开 Data Studio。
- 打开完整指南——指向本文档站点的链接。
下面各节会详细说明每一步;你既可以完全在这个窗口内完成操作,也可以按下文所述通过菜单和 Project 窗口来完成。
更快的方式——拖放。 如果你已经有一个装着工作表文件的文件夹,打开 Data Studio,然后把该文件夹拖到窗口上——或单个 .tsv/.csv/.xlsx 文件。它会主动提出为你创建一个从该文件夹读取数据的导入设置资源,并将其设为活动,无需手动配置。
当它还没有活动设置时,Studio 会显示一个 "开始使用" 面板,其中带有同样的创建 / 导入演示 / 入门 按钮,而不是一张空表格。
健康检查。 在任何时候,打开 Data Studio,从工具栏中选择 ⋯ ▸ 健康检查 即可获得一次快速、无需联网的诊断。它会针对以下各项报告 ✓/✗,并为每一项附带建议的修复方法:
- 活动设置;
- 来源是否可达(本地文件夹是否存在,或 Google id + 密钥路径是否有效);
- 是否存在导入 baseline;
- 生成代码、烘焙 SO 和 addressables 是否为最新状态。
界面语言。 首次打开项目时,SheetForge 会根据你编辑器的系统语言来设置界面语言(九种语言有对应映射;其他语言则保持英文)。它绝不会覆盖你已经选定的语言;你可以随时在 Preferences ▸ SheetForge 中更改(参见本地化)。
1. 选择导入设置资源
可以通过入门窗口的 新建设置资源 按钮创建一个,也可以在 Project 窗口中右键 → Create ▸ SheetForge ▸ 导入设置(菜单标签会跟随你的语言设置——参见本地化)。
你可以保留多个设置资源(例如每个数据源一个),并选择其中哪一个是活动的。菜单、Data Studio 和导入操作都会使用这个活动资源。这个选择是按项目、按用户存储的(一个 EditorPrefs 指针——不会产生版本控制噪音,每位队友各自独立),如果活动资源被删除,该指针会自我修复。
如果只有一个设置资源,你的首次导入会自动选中它;无需显式选择。当存在多个设置资源时,可以在入门窗口中选择活动资源,也可以通过 Data Studio 工具栏中出现的下拉菜单来选择。
配置 SheetForgeSettings 资源:
| 字段 | 含义 |
|---|---|
| Source(下拉菜单) | 内置的 LocalFile(.tsv/.csv/.xlsx 文件所在的文件夹)或 GoogleSheet——两者都是完整的生产级路径。已注册的自定义插件来源(DB/REST 等)也会出现在这里。存储在 sourceProviderId 中;为空时默认使用内置的 LocalFile 提供方。 |
localFolderPath | LocalFile 模式:存放工作表文件的文件夹。只扫描该文件夹的直接子项。 |
spreadsheetId | GoogleSheet 模式:目标表格的 ID(SheetsApi 模式需要服务账号认证)。 |
bakeOutputFolder | 烘焙后的 Database SO 的存放位置。默认值为 Assets/SheetForgeBaked。 |
generatedCodeFolder | 生成的 .cs 文件的存放位置。默认值为 Assets/SheetForgeGenerated,特意放在 Assets/SheetForge 之外,这样重新安装或移动本产品都不会删除你的生成代码。如果项目仍在旧的产品内部位置(Assets/SheetForge/Runtime/Generated)生成代码,会一直保留在那个位置,直到它被清空为止;迁移方法见从旧版本升级。任何文件夹都可以。如果生成的代码引用了该文件夹所在程序集看不到的插件类型,导入会自动在那里生成一个配套的 .asmdef 来接通引用(核心运行时程序集本身保持干净)。请注意,这只是新标签页的默认落脚点。如果某个标签页生成的类型已经存在于别处(例如某个插件包已提交的 Generated 目录),它会原地在其已有位置重新生成,过期的重复文件会被自动清理并输出控制台日志。 |
generatedNamespace | 生成类型所用的命名空间。为空 = SheetForge.Generated。设置一个独有的命名空间(例如 MyGame.Data),可以将你生成的类型与其他包以及内置示例区分开。 |
exportFolderPath / exportFormat | 导出目标位置与格式(Tsv / Csv / Xlsx / MatchSource)。 |
设置面板只显示与当前来源模式相关的字段——Local 模式会隐藏 Google 相关的输入项;gidMap 只在 Google ExportUrl 模式下出现。
2. 服务账号密钥安全性(Google 来源)
使用的是 LocalFile 来源?可以跳过本节。
在 SheetsApi 模式下使用 Google表格需要一个服务账号 JSON 密钥。如果你从未创建过密钥,Google表格设置 会手把手带你走完整个流程。请将该密钥放在 Assets/ 目录之外、也放在你的代码仓库之外——切勿将其提交到版本库。
- 推荐做法:将环境变量
SHEETFORGE_SHEETS_KEY设置为你密钥文件的绝对路径。它的优先级高于设置资源中的密钥路径字段,这样每位开发者都可以注入自己本地的密钥,而不会在仓库中留下任何路径信息。 - 如果你必须在设置字段中填写路径,请指向仓库之外的位置(例如
C:/keys/service-account.json)。放在Assets/下的密钥文件会被泄漏进构建产物和提交记录中。
3. 执行首次导入
Tools ▸ SheetForge ▸ Data Studio,然后在工具栏中按下 ↓ Pull from source。
- 该管线会依次执行:获取 → 验证 →(成功后)生成代码 → 烘焙。诊断信息会以你所选语言、人类友好的报告形式打印到控制台。
- 首次导入会自动分两个内部阶段完成。当架构是新建或已更改时,导入会先写入生成的代码,从而触发一次编译/域重载。重载完成后,会自动继续完成烘焙。用户只需操作一次,无需手动再次触发。如果编译失败,自动继续会安全中止(尝试次数上限为 3 次),并在控制台留下一条可执行的提示语句。
- 验证会在导入时收集所有诊断信息(它从不会在第一个错误处就停止)。哪怕只存在一个错误,也不会产生任何输出(不会有部分组装的结果)。
- 导入会将每个标签页的 Database SO 自动注册到 Addressables 组
SheetForge下,地址为"SheetForge/{tab}"——你的游戏就通过这个稳定地址来加载(参见核心概念)。
4. 在游戏中加载数据
using SheetForge.Runtime;
using UnityEngine.ResourceManagement.AsyncOperations;
AsyncOperationHandle<DefinitionDatabase> handle = SheetForgeDatabases.LoadAsync("Items");
await handle.Task; // or coroutine yield / handle.WaitForCompletion()
if (handle.Status == AsyncOperationStatus.Succeeded)
{
DefinitionDatabase db = handle.Result;
// For strong typing: SheetForgeDatabases.LoadAsync<ItemsDatabase>("Items")
}
SheetForgeDatabases.Release(handle); // Addressables is ref-counted — release what you loadSheetForge.Runtime 程序集是 autoReferenced 的,因此游戏代码无需 asmdef 引用即可使用它。
切勿从场景中直接引用烘焙出的 SO。 烘焙出的 SO 是不提交到版本库、按机器区分的缓存——它们的 GUID 会因机器不同、每次重新烘焙而不同,因此直接的场景引用会在队友的机器上变成 Missing。按地址加载正是为了从设计上吸收这一问题。
5. 尝试演示场景
两个示例以可选导入包的形式提供。插件示例 SheetForge.PluginDemo(自定义类型、enum、验证器、边)和一个不含插件的 SheetForge.CoreDemo(仅使用核心内置类型),二者都各自包含一个"打开即可 Play"的演示场景。
演示导入统一集中在一个地方——入门窗口的示例分区——因此没有对应的菜单项。
- 插件演示:在入门窗口中按下 导入 Plugin Demo,或双击
Assets/SheetForge/Examples/SheetForgePluginDemo.unitypackage。两种方式都会将其还原到Assets/SheetForge.PluginDemo/…下。场景:Demo/PluginDemo.unity(菜单 Tools ▸ SheetForge ▸ Open Plugin Demo Scene,由示例包自身添加)。它会按地址加载示例数据库,并展示一个由工作表数据组装而成的技能(火球总伤害 = Damage 10 + DamageOverTime 3×3 = 19)。 - 仅核心演示:在入门窗口中按下 导入 Core Demo,或双击
Assets/SheetForge/Examples/SheetForgeCoreDemo.unitypackage。该操作会将其还原到Assets/SheetForge.CoreDemo/…下。场景:Demo/CoreDemo.unity(菜单 Tools ▸ SheetForge ▸ Open Core Demo Scene)。它展示了仅使用核心内置类型、由物品引用组装而成的装备配置。该演示还包含一个本地化表(ExampleStrings),物品通过LocRef单元格引用其中的键——参见本地化表。
(这些示例菜单的叶子标签是英文的,因为它们位于核心本地化菜单管线之外。)
每个演示包都自带一个预先配置好的设置资源。 当你导入一个演示包时,如果你还没有自己的活动设置,SheetForge 会自动激活该内置的设置资源。如果你已经有一个,它会打开入门窗口来建议切换,而不是静默覆盖你的选择。因此演示流程很简单:导入包 →(设置自动激活)→ 执行导入 → Play——无需手动创建设置。
演示只有在你的机器上运行过一次导入之后才能工作——它所加载的 Addressables 地址,只有在导入运行过一次之后才会存在(Addressables 组资源是一个不提交到版本库、可自我修复的缓存)。在此之前,演示场景会显示一条引导信息,而不是失败。
要完成一次演示(在按上文导入示例包之后):
- 确认该演示自带的设置资源已被激活(入门窗口会显示它,或者导入过程已自动激活它)。它使用来源 = LocalFile,本地文件夹 = 该示例的
DemoSheets文件夹,命名空间为默认的SheetForge.Generated,因此重新导入会原地重新生成已提交的类型。 - 插件演示的脚本引用无需任何操作。
ExampleEffects标签页包含一个AssetRef@Scripts示例。示例包会自行、幂等地将DemoScripts/special_effect.lua.txt以地址special_effect注册到一个ScriptsAddressables 组中,因此首次导入就能通过引用验证。只有当它记录了一条无法完成该操作的警告时(例如资源缺失)才需要你手动添加该条目——如果你不想要这个 Addressables 示例,也可以直接删除那一行。 - 在 Tools ▸ SheetForge ▸ Data Studio 中按一次 ↓ Pull from source(或入门窗口中的 执行导入 按钮),然后打开演示场景并按下 Play。
6. 团队工作流程摘要
- 烘焙出的 SO(
Assets/SheetForgeBaked)是按机器区分的缓存。请把它加入 gitignore;克隆仓库后,每位团队成员只需运行一次执行导入。 - 生成代码(
Assets/SheetForgeGenerated)是你项目自己的源码,推荐将其提交。这样一来,新克隆的仓库在任何人运行导入之前就能编译,架构上的变更也会直接体现在代码评审里。它是确定性(deterministic)输出,因此队友的导入会产生完全相同的字节,不会带来多余的差异噪声。改用 gitignore 忽略它同样可行——这种情况下,克隆后的执行导入就是恢复编译的手段。 - 构建前的新鲜度检查钩子会针对每个已提交的生成 Database 类型检查:(i) 烘焙的 SO 是否存在,(ii) 架构指纹是否与 baseline 匹配,(iii) Addressables 注册是否存在。只要有一项失败,构建就会中止并给出可执行的提示语句,因此克隆出来的或 CI 用的机器绝不会悄无声息地打出一个空缓存的构建。