配方与配置 DSL
基本信息
| 属性 | 值 |
|---|---|
| 解析器 | net.bdew.lib.recipes.RecipeParser |
| 执行器 | net.bdew.lib.recipes.RecipeLoader |
| 语法 AST | ast-statements-cfg.scala / ast-statements-recipe.scala / ast-conditions.scala / ast-stackref.scala |
| 入口方法 | RecipesHelper.loadConfigs(modName, listResource, configDir, resBaseName, loader) |
recipes/ Scala 文件数 |
15(含 gencfg/、lootlist/ 子目录) |
功能
BD lib 内置了一套自定义文本 DSL,用于同时定义「机器调校参数」与「合成配方」。同一套解析器被复用于两处:本模组自己的网络白名单配置,以及下游模组的机器调校文件。
语句分类
AST 分为两个顶层分类(ast-statements-cfg.scala):
| 基类 | 用途 | 子类 |
|---|---|---|
ConfigStatement |
配置作用域语句 | CsRecipeBlock、CsConditionalConfig、CsClearRecipes |
RecipeStatement |
配方作用域语句 | RsCharAssign、RsClassMacro、RsRecipes、RsConditional、RsRecipeShaped、RsRecipeShapeless 等 |
命名约定写在源码注释中:配置语句以 Cs 开头、配方语句以 Rs 开头、条件以 Cnd 开头(ast-conditions.scala:12-15)。
关键语法
| 语法 | 含义 | AST 类型 |
|---|---|---|
{char} = {ref} |
字符映射,把配方图案中的一个字母绑定到物品引用 | RsCharAssign |
def {id} = {name} |
类宏,$id 可在类名处展开 |
RsClassMacro |
recipes { {statements} } |
配方块,用于分组与隔离 | RsRecipes / CsRecipeBlock |
clearRecipes: {spec} |
清除此前为某产物定义的所有配方 | CsClearRecipes |
XXX XXX => {result} [* {count}] |
3×3 有序配方 | RsRecipeShaped |
XX XX => {result} [* {count}] |
2×2 有序配方 | RsRecipeShaped |
shapeless: {characters} => {result} [* {count}] |
无序配方 | RsRecipeShapeless |
* {count} 后缀用于指定产出数量,默认 1。
条件表达式
ast-conditions.scala 定义了 6 种条件,全部以 Cnd 前缀命名:
| 语法 | 含义 | AST 类型 |
|---|---|---|
HaveMod {string} |
该 modid 存在时为真 | CndHaveMod |
HaveAPI {string} |
该 API 存在时为真 | CndHaveAPI |
HaveOD {string} |
该矿物字典条目存在时为真 | CndHaveOD |
! {condition} |
取反 | CndNOT |
({c} && {c}) |
与 | CndAND |
({c} || {c}) |
或 | CndOR |
条件可同时用于两个作用域:配置作用域用 if {cond} << {statements} >> [else << {statements} >>](CsConditionalConfig),配方作用域用 if {cond} recipes { {statements} }(RsConditional)。
解析器的可扩展性
RecipeLoader.newParser()(RecipeLoader.scala:33)是一个可被子类覆写的方法,注释明确写明「override in subclasses to use an extended parser」——BD lib 自身的 NetworkSecurityLoader 就用 GenericConfigLoader / GenericConfigParser 混入了这套机制。
数值
| 数值名 | 值 |
|---|---|
ConfigStatement 子类数 |
3 |
RecipeStatement 子类数 |
6 个具体类(RsCharAssign、RsClassMacro、RsRecipes、RsConditional、RsRecipeShaped、RsRecipeShapeless)+ 1 个抽象基类 CraftingStatement |
Condition 子类数 |
6 |
| 条件求值实现 | RecipeLoader.scala:327-336(resolveCondition) |
| 支持的有序配方尺寸 | 2 种(2×2、3×3) |
| 无序配方种类 | 1 |
| 条件原语种类 | 3(HaveMod / HaveAPI / HaveOD) |
| 布尔运算符 | 2(&&、||)+ 取反 ! |
交互
DSL 本身没有玩家交互。它是给模组作者和服务器管理员在 .cfg 文件里使用的编辑接口:
| 触发 | 行为 |
|---|---|
| 服务器启动、预初始化阶段 | 加载器按顺序解析配置文件并执行全部语句 |
配方语句 RsRecipeShaped |
调用 Misc.addRecipe → GameRegistry.addRecipe 注册有序配方 |
| 配方语句(使用矿物字典时) | 调用 GameRegistry.addShapelessRecipe / ShapelessOreRecipe 注册无序或矿物字典配方 |
clearRecipes: {spec} |
移除先前注册的、产物匹配的配方 |
| 条件为假 | 对应块内的语句整体跳过 |
| 配置解析出错 | 抛出 StatementError,由 RecipesHelper.tryLoadConfig 捕获后经 FMLCommonHandler.raiseException 中止游戏 |