Mindustry JS Mod:MultiCrafter多输入输出合成器教程
简介面向Mindustry 6.0模组开发者的MultiCrafter JavaScript脚本主要用于在mod中快速生成多输入、多配方的合成器方块适合需要扩展自定义合成逻辑的玩家和开发者。脚本封装了核心调用方式通过引入multi-crafter.js并执行newCrafter即可配置物品与液体混合、输入数量等参数省去手工编写复杂合成逻辑的麻烦。资源包体积很小共2个文件包含JS脚本和Markdown格式的README说明整体仅4KB方便直接移植到现有mod工程中。该资源已有166人学习浏览适合作为Mindustry模组开发的入门参考。借助脚本内提供的示例读者可以快速理解从加载插件、定义名称到写入配方的完整流程也能从中掌握provide、input等API的用法从而更高效地搭建属于自己的多产物合成器。 做Mindustry mod的人大多会走到这一步想做一个比熔炉更复杂的合成机器比如同时吃铜和铅、产出合金还排出废液。原版GenericCrafter能做但每个方块基本只能配置单一输入、单一输出想要实现这种需求要么堆一堆中间方块要么自己写大量重复逻辑。后来我在6.0的mod项目里接触到MultiCrafter这个库配合JS脚本几行代码就定义了一个多输入多输出的合成器。如果你也在用JS写Mindustry 6.0的mod想知道MultiCrafter怎么用、有哪些坑这篇就是我的实操记录。1. 原版合成器不够用MultiCrafter到底帮你省了多少事1.1 原版GenericCrafter的两个痛点Mindustry的合成方块比如熔炉、粉碎机、塑料钢厂底层逻辑都继承自GenericCrafter。这个类本身没问题问题出在原版机制对“一个方块能处理多少种配方”限制得太死。每个GenericCrafter子类在实例化时输入物品、输入液体、输出物品、输出液体都是写死的单一数组。比如熔炉就是铜铅进巨钢出塑料钢厂就是煤水进塑料出。这意味着什么如果你的mod需要一个“既能炼A合金又能炼B合金”的机器原版方式要么做成两个独立方块要么写一个自定义build覆盖配置逻辑再维护一套复杂的状态机。游戏里玩家还要手动点配置、切配方代码量蹭蹭往上涨。更痛苦的是如果这个机器还需要三种原料输入、两种物质输出原版几乎没法直接表达只能靠多个方块级联。1.2 MultiCrafter的设计思路MultiCrafter的核心理念是把“合成方块”抽象成一个通用容器一个机器类型挂多组配方每组配方定义自己的输入列表和输出列表。它有点像一个智能菜单式炉子——原料放进去机器自动匹配当前能做的那道菜做完出菜菜单还能随时换。对JS mod来说MultiCrafter最实在的价值有两个。第一你不必继承GenericCrafter然后在Java层写子类JS脚本就能直接用库提供的构造器创建完整的方块类型。第二配方表是数据驱动的这意味着你可以把几十种配方写成一个数组用循环批量注册维护成本低很多。社区里不少大型mod的“综合冶炼厂”“多用途化工厂”就是用这个思路做的。2. 先把JS mod骨架搭对目录结构、mod.json与调试姿势2.1 目录结构先摆好写MultiCrafter的mod之前先确认你的mod基础结构没问题。一个最简的Mindustry 6.0 JS mod是这种结构MyMod/ ├── mod.json ├── main.js └── content/ └── items/ └── my-item.json入口文件可以是根目录的main.js也可以放scripts/main.jsMindustry加载时会自动识别。我习惯放根目录路径短引用其他文件时心智负担小。如果只添加方块、不新增物品和液体连content/目录都可以先不建。2.2 mod.json里最容易写错的两个字段mod.json是整个mod的身份证明格式错一个逗号游戏里就直接报错。我见过最多的两个问题一是name字段写得和文件夹名不一致导致后续require别的东西时路径找不到二是minGameVersion写错游戏判定版本不兼容直接拒绝加载。下面是能用的最小示例{ name: my-multi-mod, displayName: My Multi Mod, author: yourname, version: 1.0.0, minGameVersion: 126, description: A demo mod using MultiCrafter }minGameVersion填126对应6.0正式版如果你用更高的build就填你本地的版本号。取值可以在游戏主菜单的版本信息里看别图省事乱填。2.3 加载MultiCrafter库的正确姿势MultiCrafter本身也是一个mod/库你要么把它作为依赖mod装进游戏要么把它的JS版源文件直接放进自己mod目录。我推荐后者因为少一层依赖分享给别人的时候不用额外提醒“先去创意工坊订阅XX”。一般做法是在mod根目录建一个libs/文件夹把multi-crafter.js放进去然后在main.js顶部用require引入const MultiCrafter require(libs/multi-crafter);注意不同仓库的导出方式可能不一样有的是module.exports MultiCrafter有的把多个类挂在一个对象上。以你拿到的库源码里最后几行导出语句为准多用print(Object.keys(MultiCrafter))打印一下就能看到导出了哪些对象。2.4 调试输出别用alert用LogJS mod运行在游戏进程里没有浏览器控制台alert这类东西想都不用想。Mindustry提供的是print和Log.info前者在调试界面显示后者走游戏日志。我的习惯是所有临时调试信息都用Log.info带上前缀比如Log.info([MyMod] recipe registered: recipeName);日志文件在本地游戏目录的log.txt里崩溃和报错也会写到这里是排查问题的一手信息。很多新手拿着报错截图到处问其实打开日志能看到完整堆栈。3. 手把手定义第一个MultiCrafter机器API核心玩法拆解3.1 从需求出发选择方块参数我先拿一个最常见的需求举例做一个“废料冶炼机”吃铜和铅产出巨钢同时排出少量水。用MultiCrafter的视角看这个方块需要确认的参数包括占地大小、生命值、容器容量、建造需求、科技树位置、合成耗时、输入输出物。下面是核心代码框架字段名以你下载的MultiCrafter版本为准但整体结构是一致的const multi require(libs/multi-crafter); const wasteSmelter new multi.MultiCrafter(GenericCrafter, waste-smelter, { size: 3, health: 360, itemCapacity: 40, liquidCapacity: 30, craftTime: 60, category: Category.crafting, requirements: [ Item.copper, 80, Item.lead, 50, Item.silicon, 30 ], research: Blocks.siliconSmelter, recipes: [ { name: copper-lead-alloy, craftTime: 60, inputItems: [ Item.copper, 3, Item.lead, 2 ], outputItems: [ Item.metaglass, 1 ], outputLiquids: [ Liquids.water, 0.05 ] } ] });这里有个容易被忽略的点research表示这个方块在科技树里从哪里解锁。直接填Blocks.siliconSmelter它就会出现在硅冶炼厂的下一级解锁链上不用额外写科技树JSON省事。3.2 每个关键参数背后的“为什么”size: 33x3占地。MultiCrafter机器一般涉及多输入输出太小的方块管线不好接3x3是通用选择。想做大工厂的可以4x4甚至5x5但要注意后续图片资源尺寸匹配。craftTime单位是tick游戏每秒60 tick60就是1秒一次合成。这个数值会显示在方块信息里调太大可能让玩家觉得机器很废物。inputItems和outputItems格式是“物品类型、数量”成对出现。所有物品都要用Item.xxx这种方式引用如果引用了不存在的物品ID游戏会在加载时静默跳过你只会看到一个没配方的空机器。outputLiquids可选项不排液体就不写。输出液体还可以配合liquidCapacity控制缓冲容量容量太小会堵住产出。3.3 图标和显示不设置会被粉紫块支配方块创建后默认会尝试读取一个叫waste-smelter的贴图。你需要在mod的sprites/blocks/目录下放对应的PNG文件命名要和方块ID完全一致。如果没放游戏里看到的就是粉紫色方块AI路径和管线链接都会表现异常。如果你想让方块显示更多信息MultiCrafter还允许配置比较细致的绘制模式比如用customRegion或region指定不同的运行状态图。基础模式下我建议先做一张静态图把输入口和输出口的位置画清楚够用就行。3.4 注册方块后别忘了buildType新创建的方块类型默认会用MultiCrafter自带的build逻辑但有些modder会想自定义行为比如“机器工作到一半断电时保存进度”或者“根据周围Buff改变配方”。这时候就需要给方块挂一个自定义实体类wasteSmelter.buildType () extendContent(GenericCrafter.GenericCrafterBuild, { // 自定义逻辑写这里 });MultiCrafter的实体类透传了原版GenericCrafterBuild的大多数方法所以常规的crafting、progress、items这些字段都能直接用。需要提醒的是自定义build时如果覆盖了updateTile记得调用父类方法否则配方进度不会正常推进。4. 多配方与液体混搭一个能吃多种原料的实战案例4.1 同一个机器多个配方MultiCrafter最能打的地方在“多配方”。设想一个场景你希望做一个“综合分离机”同一个方块既能处理煤水产出油又能处理生物质水产出煤甚至还能处理沙铅产出硅。不用MultiCrafter你得写三个独立方块用MultiCrafter只需要往recipes数组里多塞几组配置。const separator new multi.MultiCrafter(GenericCrafter, multi-separator, { size: 3, health: 300, craftTime: 45, category: Category.crafting, requirements: [ Item.copper, 60, Item.titanium, 40 ], research: Blocks.centrifuge, recipes: [ { name: coal-to-oil, craftTime: 50, inputItems: [Item.coal, 2], inputLiquids: [Liquids.water, 0.2], outputLiquids: [Liquids.oil, 0.3] }, { name: biomass-to-coal, craftTime: 60, inputItems: [Item.biomatter, 2], inputLiquids: [Liquids.water, 0.2], outputItems: [Item.coal, 1] }, { name: sand-lead-to-silicon, craftTime: 80, inputItems: [Item.sand, 2, Item.lead, 1], outputItems: [Item.silicon, 1] } ] });重点是多个配方不要互相冲突。冲突指的是两个配方在某一时刻都可能消耗同一种输入但产出完全不同机器会随机选一个玩家会懵。所以配方设计时要保证输入组合有明显区分度比如上面三个配方一个额外吃水、一个吃生物质、一个吃砂输入集合完全不同机器就能根据当前库存自动匹配唯一可执行的那个。4.2 配方优先级与手动切换如果确实存在多个配方都满足输入条件的情况MultiCrafter会优先选择数组里靠前的配方。这个特性可以在设计时利用起来。比如想让机器优先处理高收益配方就把高收益的配方写在数组前面。想给玩家手动切换配方的能力可以在机器配置界面处理。MultiCrafter的默认实现不强制提供手动切换UI但你可以覆盖build的buildConfiguration和configured方法配合Block的configurable true属性做一个简单的按钮切换当前配方索引。这个玩法接近原版的Configurable机制代码量可控。4.3 用JS函数批量生成配方表配方多了以后如果每个配方都手写一遍代码会非常啰嗦。我建议用JS的数组加map方法统一生成const recipeStore [ [copper-alloy, 60, [Item.copper, 3, Item.lead, 2], [Item.metaglass, 1], []], [titanium-alloy, 90, [Item.titanium, 3, Item.coal, 3], [Item.surgeAlloy, 1], []], [oil-heavy, 45, [Item.coal, 2], [], [Liquids.oil, 0.3]] ]; const recipes recipeStore.map(r ({ name: r[0], craftTime: r[1], inputItems: r[2], outputItems: r[3], outputLiquids: r[4] }));这样后面想加配方只需要在recipeStore里加一行代码结构一目了然。注意Mindustry的Rhino引擎对ES6的支持有限map这种数组方法是可以用的但箭头函数在个别构建版本可能有兼容问题保守起见可以用普通function写法。5. 我踩过的坑资源路径、Rhino兼容性与调试技巧5.1 require路径大小写和相对位置JS mod的require路径是相对mod根目录的而且区分大小写。我踩过最蠢的坑是把文件名写成Multi-Crafter.js路径里却写multi-crafter结果加载时直接报模块找不到。另一个坑是把库文件放在子目录后在main.js里用require(libs/multi-crafter)这个相对路径在游戏重载时偶尔会因为工作目录不同而失效。稳妥做法是永远在main.js顶部用统一路径别在别的JS文件里再require一次。5.2 Rhino引擎的JS语法红线Mindustry 6.0的JS mod跑在Rhino引擎上不是浏览器环境。它支持ES5的大部分特性但ES6的支持各版本参差不齐。let和const在大多数版本可用但类、模板字符串、解构赋值、扩展运算符这些新特性不一定稳。最头疼的是某些数组新方法比如Array.prototype.find和includes在旧版Rhino上是没有的直接报TypeError。我的做法是所有mod代码统一按ES5风格写只用var和普通function数组遍历用for循环而非forEach。虽然看起来老气但至少不会因为玩家游戏版本不同而崩机器。5.3 图片、JSON和本地化文件的坑方块贴图缺失会显示粉紫块。PNG文件命名必须和方块ID完全一致放的位置也必须对应sprites/blocks/。更隐蔽的坑是图片尺寸Mindustry不会自动缩放如果你做了一张500x500的图但方块实际是3x3游戏里会按像素硬怼看起来错位。制作时先确定size参数再按游戏基准比例出图。JSON方面的坑主要在两个地方一是JSON不支持注释很多人从网上复制示例把注释也带进去加载直接失败二是content/目录下每个item的JSON用字段太多容易手滑少写一个cost或者写错color格式游戏日志会报一个很隐晦的错误。MultiCrafter机器大部分配置都在JS里完成JSON只负责物品、液体这些基础资源所以保持JSON精简是明智的。5.4 调试技巧热重载与Print大法Mindustry支持mod热重载修改main.js后不需要重启游戏在mod列表里禁用再启用一次就能加载新代码。这个流程配合日志输出迭代效率很高。我推荐的调试路径是先在main.js里写一个最简单的方块和一条配方启用mod确认加载无报错确认游戏里能放置、能原料进、能产物出再逐步增加配方和逻辑。如果机器放置后无法工作先看原料是否进得去。我看过很多案例是itemCapacity设得太小输入一次需要5个铜4个铅容量却只有10实际还有水占空间机器就卡住了。用Log.info(items.total())打印当前物品列表或者点开方块面板看内部存储基本能定位问题。6. 结合个人经验的几个忠告如果你打算用MultiCrafter做一套完整的大mod我建议先想清楚方块定位再动手。它可以轻松创建多配方机器但不代表每个方块都应该做成一锅炖。合成线太杂玩家反而难以规划产线。社区里做得好的mod多配方机器往往有一两个“全能核心”其他方块仍然是单一配方的专用机这样既发挥MultiCrafter的效率又不至于让游戏失去规划感。另外一个非常有用的习惯是在代码里给每个配方都配上独立的name字段别留空。别小看这串名字报错时日志里输出的是这个字段如果你叫它“配方1”出了问题根本不知道是哪个机器。我通常用“方块ID-产物ID”的格式命名比如waste-smelter-metaglass。最后分享一个小技巧。测试新机器时我会在它旁边放一个无限原料的箱子mod或者干脆调低建造需求让测试成本降到最低。把配方逻辑跑通之后再去考虑平衡性数值。顺序反了的话你会发现花了大量时间调数字最后发现配方逻辑本身有bug白忙一场。MultiCrafter就是这样一个工具它不改变Mindustry的游戏本质只是把modder从无尽的重复代码里解放出来。上手之后你会发现原来写一个“什么都吃、什么都能炼”的工厂方块可以这么轻松。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →