RecipaediaEX 是一个面向 Survivalcraft 模组开发的配方与图鉴扩展框架,核心目标是把“配方定义”“配方加载”“图鉴展示”解耦,让你可以:
- 自定义任意
IRecipe类型,不再局限原版CraftingRecipe。 - 通过
IRecipesLoader读取任意来源的配方(文件、程序生成、混合方式)。 - 使用统一的
RecipaediaEXManager进行匹配查询。 - 在图鉴界面通过
RecipeDescriptor按配方类型渲染 UI。
- 当前项目版本:
2.0.0.0-preview8(以modinfo.json为准) - 目标框架:
net10.0 - 主要依赖:
SurvivalcraftAPI.EngineSurvivalcraftAPI.EntitySystemSurvivalcraftAPI.SurvivalcraftZLinq
RecipaediaEXLoader 在 OnLoadingFinished 阶段执行:
RecipesLoadManager.Initialize():扫描并实例化全部IRecipesLoader与IDynamicRecipeLoader(按Order排序)。RecipaediaEXManager.Initialize():调用各IRecipesLoader的Initialize()/GetRecipes(),建立静态配方总表。RecipesCrafterManager.Initialize():扫描方块上的ICrafter,建立“配方 -> 可用工作站”映射。- 注入图鉴页面:
RecipaediaRecipaediaDescriptionRecipaediaRecipes
之后在:
CraftingRecipesManagerInitialized钩子中执行RecipaediaEXManager.ResetRecipes()。BlocksInitalized钩子中执行RecipesCrafterManager.Initialize()。
实现 IRecipe,最少需要:
DisplayOrderMatchPriorityMatch(IRecipe actual)GetExtraValue/SetExtraValue
建议在配方里维护 ValuesDictionary,键名使用 RecipeExtraKeys(RecipesExtra/RecipeExtraKeys.cs),并至少写入:
RecipeExtraKeys.MatchedResultBlockValues(int[]),供图鉴方块产物匹配;- 按需
MatchedIngredientBlockValues。
实现 IRecipesLoader:
Initialize():做一次性的扫描、缓存、索引构建。GetRecipes():返回配方序列。Order:加载优先级(数值越大,排序越靠后)。
项目内可参考:
SurvivalcraftRecipesLoaderBlockProceduralRecipesLoaderCrXmlRecipesLoader
在你的组件中构造“实际配方”,再调用:
RecipaediaEXManager.FindMatchingRecipe(actual)— 仅在静态配方总表中查找。RecipaediaEXManager.FindMatchingRecipe<T>(actual)— 若actual含RecipeExtraKeys.Project,会先走动态配方(IDynamicRecipeLoader),再查静态表。RecipaediaEXManager.FindDynamicRecipe(actual, project)— 仅查动态配方,不查静态表。RecipaediaEXManager.FindMatchingRecipes(actual)
扩展工作台/熔炉在构造 actual 时会写入 RecipeExtraKeys.Project 等 Extra,因此 FindMatchingRecipe<T> 可自动解析原版 AdHoc 配方。自定义机器若需 AdHoc,请同样在 actual 上设置 Project。
实现 IDynamicRecipeLoader 以对接原版 Block.GetAdHocCraftingRecipe 等运行时生成逻辑。框架内置 AdHocRecipeLoader(Order = 0)。详见 API 使用文档 · 动态配方。
- 条目实现
IRecipaediaItem。 - 若要在配方页展示,实现
IRecipaediaRecipeItem。 - 若要在详情页展示,实现
IRecipaediaDescriptionItem。 - 分类提供器实现
IRecipaediaCategoryProvider(必须无参构造)。
继承 RecipeDescriptor 并加:
[RecipeDescriptor(new[] { typeof(YourRecipe) }, order: 0)]
RecipaediaEXRecipesScreen 会按 recipe.GetType() 映射到 Descriptor。若同一配方类型有多个 Descriptor,按:
order高者优先order相同则类名字典序后的覆盖前者
RecipaediaEX 提供 RecipaediaEX.Events.RecipaediaEventBus:按事件类型维护独立通道,无需修改 RX 源码即可订阅框架生命周期与工作台/熔炉行为。
using RecipaediaEX.Events;
// 内置事件:配方表重建后刷新本地缓存
RecipaediaEventBus.RecipesReset.Subscribe(e => RebuildMyRecipeIndex(e.RecipeCount));
// 自定义事件类型(跨模组约定载荷 struct/class 即可)
RecipaediaEventBus.GetPublisher<MyModEvent>().Publish(new MyModEvent(...));内置事件一览见 API 使用文档 · 事件总线。
版本号以 modinfo.json → Version 为准;构建前 tools/sync-version.ps1 自动同步到 csproj。
- 复制
tools/pack.config.example.json为tools/pack.config.json,填写ModsFolder(游戏 Mods 目录)。 - 在仓库根目录执行
dotnet build RecipaediaEX.csproj -c Release(或 Debug)。 - 构建结束后
tools/pack.ps1自动将输出目录打成RecipaediaEX.scmod(短名)并复制到ModsFolder。
若 monorepo 内与 IE2 同仓开发,脚本会优先使用 SCIENEW/tools/7z/7z.exe;独立克隆时回退为 PowerShell Compress-Archive。
跳过自动打包:-p:RecipaediaEXSkipPack=true。跳过版本同步:-p:RecipaediaEXSkipSyncVersion=true。
| 工作流 | 触发 | 产物 |
|---|---|---|
build.yml |
push main、PR | RecipaediaEX-ci.{sha7}.scmod |
release.yml |
推送 tag v* |
GitHub Release + 模组站 post 1739:RecipaediaEX-{Version}.scmod |
发版步骤见 docs/RELEASE.md。Release 还需在 GitHub 配置 Secret MOD_SITE_TOKEN(模组站 Bearer Token)。RecipaediaEX 无 SCIENEW 编译期依赖,CI 仅需 checkout 本仓库。
RecipeReaderAttribute/RecipeFileLoaderAttribute当前在框架核心流程中不是必需入口,主要作为扩展约定与兼容保留。- 若你在自定义生态中使用自己的 Reader 体系(例如在自定义 Loader 内按
Reader字段分发),这是推荐做法。