<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://mdtwiki.top/index.php?action=history&amp;feed=atom&amp;title=JSON%E6%A8%A1%E7%BB%84%E6%95%99%E7%A8%8B-Java%E8%AF%AD%E6%B3%95%E5%88%9D%E6%AD%A5%E4%B8%8EContentParser%E8%A7%A3%E6%9E%90</id>
	<title>JSON模组教程-Java语法初步与ContentParser解析 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://mdtwiki.top/index.php?action=history&amp;feed=atom&amp;title=JSON%E6%A8%A1%E7%BB%84%E6%95%99%E7%A8%8B-Java%E8%AF%AD%E6%B3%95%E5%88%9D%E6%AD%A5%E4%B8%8EContentParser%E8%A7%A3%E6%9E%90"/>
	<link rel="alternate" type="text/html" href="https://mdtwiki.top/index.php?title=JSON%E6%A8%A1%E7%BB%84%E6%95%99%E7%A8%8B-Java%E8%AF%AD%E6%B3%95%E5%88%9D%E6%AD%A5%E4%B8%8EContentParser%E8%A7%A3%E6%9E%90&amp;action=history"/>
	<updated>2026-05-16T06:06:41Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://mdtwiki.top/index.php?title=JSON%E6%A8%A1%E7%BB%84%E6%95%99%E7%A8%8B-Java%E8%AF%AD%E6%B3%95%E5%88%9D%E6%AD%A5%E4%B8%8EContentParser%E8%A7%A3%E6%9E%90&amp;diff=2589&amp;oldid=prev</id>
		<title>硫缺铅：​创建页面，内容为“&lt;span id=&quot;java-语法初步与-contentparser-解析&quot;&gt;&lt;/span&gt; = Java 语法初步与 ContentParser 解析 =  这一节不是让你“学会 Java”，而是让你看懂源码，并理解 JSON 是如何被解析成游戏内容的。只要你能读懂类、字段与方法，就能推断出 JSON 该怎么写。  &lt;span id=&quot;java-语法速通只讲必要部分&quot;&gt;&lt;/span&gt; == Java 语法速通（只讲必要部分） ==  Java 里的“内容定义”通常是一个类，…”</title>
		<link rel="alternate" type="text/html" href="https://mdtwiki.top/index.php?title=JSON%E6%A8%A1%E7%BB%84%E6%95%99%E7%A8%8B-Java%E8%AF%AD%E6%B3%95%E5%88%9D%E6%AD%A5%E4%B8%8EContentParser%E8%A7%A3%E6%9E%90&amp;diff=2589&amp;oldid=prev"/>
		<updated>2026-02-01T13:34:56Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“&amp;lt;span id=&amp;quot;java-语法初步与-contentparser-解析&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; = Java 语法初步与 ContentParser 解析 =  这一节不是让你“学会 Java”，而是让你看懂源码，并理解 JSON 是如何被解析成游戏内容的。只要你能读懂类、字段与方法，就能推断出 JSON 该怎么写。  &amp;lt;span id=&amp;quot;java-语法速通只讲必要部分&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; == Java 语法速通（只讲必要部分） ==  Java 里的“内容定义”通常是一个类，…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;span id=&amp;quot;java-语法初步与-contentparser-解析&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Java 语法初步与 ContentParser 解析 =&lt;br /&gt;
&lt;br /&gt;
这一节不是让你“学会 Java”，而是让你看懂源码，并理解 JSON 是如何被解析成游戏内容的。只要你能读懂类、字段与方法，就能推断出 JSON 该怎么写。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;java-语法速通只讲必要部分&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Java 语法速通（只讲必要部分） ==&lt;br /&gt;
&lt;br /&gt;
Java 里的“内容定义”通常是一个类，字段就是配置项。比如：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public class Drill extends Block{&lt;br /&gt;
    public int tier = 1;&lt;br /&gt;
    public float drillTime = 300f;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;public&amp;lt;/code&amp;gt; 表示公开字段，&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt; 是类型，右侧是默认值。JSON 里只要写同名字段即可覆盖默认值。注意 Java 的 &amp;lt;code&amp;gt;float&amp;lt;/code&amp;gt; 常带 &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; 后缀，表示这是浮点数而不是整数。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;extends&amp;lt;/code&amp;gt; 表示继承。&amp;lt;code&amp;gt;Drill extends Block&amp;lt;/code&amp;gt; 的意思是“钻头拥有 Block 的所有字段”，所以你在 JSON 里看到的很多字段其实来自父类，比如 &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;health&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;requirements&amp;lt;/code&amp;gt;。&amp;lt;code&amp;gt;super(name)&amp;lt;/code&amp;gt; 是调用父类构造器，确保父类先完成初始化。源码里出现 &amp;lt;code&amp;gt;@Override&amp;lt;/code&amp;gt; 时，代表子类重写了父类方法；&amp;lt;code&amp;gt;abstract&amp;lt;/code&amp;gt; 表示抽象类不能直接实例化，必须用具体子类。&lt;br /&gt;
&lt;br /&gt;
方法是类里的“行为”，例如：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public void updateTile(){&lt;br /&gt;
    //每帧逻辑&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
构造器名字与类名相同，常用于创建时设定基础值：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;public Drill(String name){&lt;br /&gt;
    super(name);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
你在 &amp;lt;code&amp;gt;core/src/mindustry/content/*.java&amp;lt;/code&amp;gt; 里看到的写法，经常是“匿名内部类”初始化：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;new GenericCrafter(&amp;quot;x&amp;quot;){ {&lt;br /&gt;
    craftTime = 60f;&lt;br /&gt;
}}&amp;lt;/pre&amp;gt;&lt;br /&gt;
这一对大括号的含义就是“创建对象后马上设置字段”。JSON 本质上就是在做这件事。&lt;br /&gt;
&lt;br /&gt;
源码里还会出现大量“箭头函数”写法，例如 &amp;lt;code&amp;gt;u -&amp;amp;gt; true&amp;lt;/code&amp;gt; 或 &amp;lt;code&amp;gt;() -&amp;amp;gt; {}&amp;lt;/code&amp;gt;。这是 Java 的 Lambda 表达式，表示“把一段逻辑当作参数传入”。当你看到这些写法时，就应该意识到这是函数类型字段，JSON 通常无法配置，只能用 JS/Java 处理。&lt;br /&gt;
&lt;br /&gt;
数组与列表也经常出现。Java 里 &amp;lt;code&amp;gt;ItemStack[]&amp;lt;/code&amp;gt; 是数组，&amp;lt;code&amp;gt;Seq&amp;amp;lt;ItemStack&amp;amp;gt;&amp;lt;/code&amp;gt; 是列表。JSON 里通常用数组表示，比如 &amp;lt;code&amp;gt;&amp;amp;quot;requirements&amp;amp;quot;: [&amp;amp;quot;copper/10&amp;amp;quot;, &amp;amp;quot;lead/10&amp;amp;quot;]&amp;lt;/code&amp;gt;。&amp;lt;code&amp;gt;ObjectMap&amp;lt;/code&amp;gt; 一类的映射通常写成“键值对对象”。&lt;br /&gt;
&lt;br /&gt;
你还会看到 &amp;lt;code&amp;gt;@Nullable&amp;lt;/code&amp;gt; 注解或字段默认值为 &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt;。这类字段通常是“可选项”，JSON 可以不写；但一旦写，就必须符合类型。例如 &amp;lt;code&amp;gt;Effect&amp;lt;/code&amp;gt; 字段允许写原版名称字符串或自定义对象，如果字段为 &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt;，游戏就会走默认行为。理解“可选项”能减少不必要的配置，也能避免写错类型导致报错。&lt;br /&gt;
&lt;br /&gt;
源码里常见的“容器构造”也值得一看，例如：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;requirements = ItemStack.with(Items.copper, 50, Items.lead, 30);&lt;br /&gt;
consumes.add(new ConsumeItems(new ItemStack(Items.graphite, 2)));&amp;lt;/pre&amp;gt;&lt;br /&gt;
它们在 JSON 中对应 &amp;lt;code&amp;gt;&amp;amp;quot;requirements&amp;amp;quot;: [&amp;amp;quot;copper/50&amp;amp;quot;, &amp;amp;quot;lead/30&amp;amp;quot;]&amp;lt;/code&amp;gt; 或 &amp;lt;code&amp;gt;consumes.items&amp;lt;/code&amp;gt; 的写法。看到这些语句时，你就能反推 JSON 的结构。&lt;br /&gt;
&lt;br /&gt;
如果你看到 &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;final&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;private&amp;lt;/code&amp;gt; 这些关键字，可以简单理解为“静态”“不可变”“私有”，它们通常不需要也不应该在 JSON 里配置。你只需要关注公开字段与构造器里对字段的默认赋值。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;this&amp;lt;/code&amp;gt; 指向当前对象，&amp;lt;code&amp;gt;this.field&amp;lt;/code&amp;gt; 只是更明确地引用字段；&amp;lt;code&amp;gt;super.field&amp;lt;/code&amp;gt; 或 &amp;lt;code&amp;gt;super.method()&amp;lt;/code&amp;gt; 则是访问父类成员。读源码时不必被这些写法吓到，它们只是告诉你“值来自当前类还是父类”。JSON 里不需要写这些关键字，只需要写字段本身。&lt;br /&gt;
&lt;br /&gt;
把 Java 写法翻译成 JSON 是最实用的练习。例如 Java 中常见的写法：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;new GenericCrafter(&amp;quot;silicon-smelter&amp;quot;){{&lt;br /&gt;
    craftTime = 60f;&lt;br /&gt;
    outputItem = new ItemStack(Items.silicon, 1);&lt;br /&gt;
    consumes.power(0.5f);&lt;br /&gt;
}}&amp;lt;/pre&amp;gt;&lt;br /&gt;
对应的 JSON 大致是：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;{&lt;br /&gt;
    &amp;quot;type&amp;quot;: &amp;quot;GenericCrafter&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;silicon-smelter&amp;quot;,&lt;br /&gt;
    &amp;quot;craftTime&amp;quot;: 60,&lt;br /&gt;
    &amp;quot;outputItem&amp;quot;: &amp;quot;silicon/1&amp;quot;,&lt;br /&gt;
    &amp;quot;consumes&amp;quot;: {&lt;br /&gt;
        &amp;quot;power&amp;quot;: 0.5&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
只要你能把“匿名内部类里的字段赋值”翻译成 JSON 键值对，就已经掌握了 70% 的阅读技巧。&lt;br /&gt;
&lt;br /&gt;
再注意 Java 里常见的 &amp;lt;code&amp;gt;Items.copper&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;Liquids.water&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;Blocks.mechanicalDrill&amp;lt;/code&amp;gt; 这类写法，它们都是静态字段引用。换到 JSON，你要写的是内部名 &amp;lt;code&amp;gt;copper&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;water&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;mechanical-drill&amp;lt;/code&amp;gt;。这一点是“源码到 JSON”最常见的转换。&lt;br /&gt;
&lt;br /&gt;
同理，单位武器的写法也可以直接翻译：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;weapons.add(new Weapon(){{&lt;br /&gt;
    x = 4f; y = 1f;&lt;br /&gt;
    reload = 30f;&lt;br /&gt;
    bullet = new BasicBulletType(3f, 12);&lt;br /&gt;
}});&amp;lt;/pre&amp;gt;&lt;br /&gt;
对应 JSON 的结构就是：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;{&lt;br /&gt;
    &amp;quot;weapons&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;x&amp;quot;: 4,&lt;br /&gt;
            &amp;quot;y&amp;quot;: 1,&lt;br /&gt;
            &amp;quot;reload&amp;quot;: 30,&lt;br /&gt;
            &amp;quot;bullet&amp;quot;: {&lt;br /&gt;
                &amp;quot;type&amp;quot;: &amp;quot;BasicBulletType&amp;quot;,&lt;br /&gt;
                &amp;quot;speed&amp;quot;: 3,&lt;br /&gt;
                &amp;quot;damage&amp;quot;: 12&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    ]&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
这类“从 Java 还原 JSON”的练习做多了，就会形成直觉。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;contentparser-在做什么&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== ContentParser 在做什么 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ContentParser&amp;lt;/code&amp;gt; 是 JSON 解析器，它把 JSON 字段逐个写进 Java 对象。它遵循“字段同名映射”的基本规则：JSON 的键名必须和 Java 字段名一致，类型也要对应。如果类型不一致，游戏会直接报错。&lt;br /&gt;
&lt;br /&gt;
解析器还会根据文件夹推断内容类型：&amp;lt;code&amp;gt;content/blocks&amp;lt;/code&amp;gt; 会被当成方块，&amp;lt;code&amp;gt;content/units&amp;lt;/code&amp;gt; 会被当成单位。文件名就是内部名，所以文件夹与文件名写错，经常会导致“找不到内容”或“类型不匹配”的报错。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 是最关键的字段之一。方块的 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 决定 Java 类（如 &amp;lt;code&amp;gt;GenericCrafter&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;Drill&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;PowerNode&amp;lt;/code&amp;gt;），单位的 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 决定构造器（如 &amp;lt;code&amp;gt;flying/mech/legs/naval/payload/missile/tank/hover/tether/crawl&amp;lt;/code&amp;gt;），而子类对象（子弹、能力、特效等）也依赖 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 指定具体子类。你可以把它理解成“告诉解析器该用哪个类来建对象”。&lt;br /&gt;
&lt;br /&gt;
从源码角度看，解析器的大致流程类似这样（伪代码）：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;var type = json.getString(&amp;quot;type&amp;quot;, defaultType);&lt;br /&gt;
var block = makeBlock(type, name);&lt;br /&gt;
readFields(block, json);&amp;lt;/pre&amp;gt;&lt;br /&gt;
因此当你写错 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;，解析器甚至无法创建对象，后续字段都会失效。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 的作用不仅体现在方块与单位上，&amp;lt;code&amp;gt;drawer&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;parts&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;BulletType&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;Ability&amp;lt;/code&amp;gt; 等复杂对象也依赖它来决定具体子类。比如 &amp;lt;code&amp;gt;DrawTurret&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;DrawMulti&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;RegionPart&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;HaloPart&amp;lt;/code&amp;gt; 都是靠 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 识别的。如果你忘了写 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 或写错大小写，解析器就会回退到默认类型，表现与预期完全不同。&lt;br /&gt;
&lt;br /&gt;
解析顺序也很重要。以方块为例，解析器会先读取 &amp;lt;code&amp;gt;bundle&amp;lt;/code&amp;gt; 文案，然后解析 &amp;lt;code&amp;gt;consumes&amp;lt;/code&amp;gt;（因为它是特殊语法），接着再把剩余字段逐个写入对象。单位则会先处理 &amp;lt;code&amp;gt;requirements&amp;lt;/code&amp;gt;（用于挂载工厂与重构厂），再处理 AI 与控制器字段，最后写入剩余字段。理解这个顺序可以帮助你避免“字段被覆盖”或“写了不生效”的情况。&lt;br /&gt;
&lt;br /&gt;
解析完成后，类的 &amp;lt;code&amp;gt;init()&amp;lt;/code&amp;gt; 与 &amp;lt;code&amp;gt;load()&amp;lt;/code&amp;gt; 会在后续流程中执行，这一步可能继续改字段或加载贴图。比如某些方块在 &amp;lt;code&amp;gt;init()&amp;lt;/code&amp;gt; 里会根据 &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt; 自动计算 &amp;lt;code&amp;gt;itemCapacity&amp;lt;/code&amp;gt;，这意味着你在 JSON 里写的值可能被逻辑覆盖。看懂这些“后置逻辑”，才能解释“写了却不生效”的现象。&lt;br /&gt;
&lt;br /&gt;
如果 JSON 没有写某个字段，解析器就会保留 Java 默认值。这也是为什么“极简 JSON”能跑起来：默认值已经把大部分东西填好了。但当你使用 &amp;lt;code&amp;gt;template&amp;lt;/code&amp;gt; 或覆盖原版时，默认值可能来自模板而不是原版，所以在关键字段上最好显式写出，避免被继承值影响。&lt;br /&gt;
&lt;br /&gt;
解析器使用反射写字段，这意味着父类的 &amp;lt;code&amp;gt;public&amp;lt;/code&amp;gt; 字段同样可写。比如 &amp;lt;code&amp;gt;Block&amp;lt;/code&amp;gt; 里定义的 &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;health&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;requirements&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;category&amp;lt;/code&amp;gt; 都可以直接写在任意方块的 JSON 里。只要字段是 &amp;lt;code&amp;gt;public&amp;lt;/code&amp;gt; 并且类型可解析，就能被写入。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;常见的-json-简写&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== 常见的 JSON 简写 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ContentParser&amp;lt;/code&amp;gt; 内置了多种简写语法。例如 &amp;lt;code&amp;gt;&amp;amp;quot;copper/10&amp;amp;quot;&amp;lt;/code&amp;gt; 会被解析为 &amp;lt;code&amp;gt;ItemStack&amp;lt;/code&amp;gt;，&amp;lt;code&amp;gt;&amp;amp;quot;water/0.1&amp;amp;quot;&amp;lt;/code&amp;gt; 会被解析为 &amp;lt;code&amp;gt;LiquidStack&amp;lt;/code&amp;gt;，载荷堆栈则可以用 &amp;lt;code&amp;gt;&amp;amp;quot;block-or-unit/amount&amp;amp;quot;&amp;lt;/code&amp;gt; 的形式表示。简写很方便，但只能表达“名称 + 数量”，一旦需要额外参数（例如 &amp;lt;code&amp;gt;booster&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;optional&amp;lt;/code&amp;gt;），就必须改用对象形式。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Effect&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;BulletType&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;DrawPart&amp;lt;/code&amp;gt; 等复杂对象也有简写规则。例如 &amp;lt;code&amp;gt;Effect&amp;lt;/code&amp;gt; 可以直接写原版 &amp;lt;code&amp;gt;Fx&amp;lt;/code&amp;gt; 名字，或者写一个对象并用 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 指定子类。&amp;lt;code&amp;gt;BulletType&amp;lt;/code&amp;gt; 可以写字符串引用原版子弹，也可以写对象并指定 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 创建自定义子弹。理解这些规则后，你会发现 JSON 其实比模板更灵活。&lt;br /&gt;
&lt;br /&gt;
颜色与向量也有常见写法。颜色可以写成十六进制字符串（如 &amp;lt;code&amp;gt;ffffff&amp;lt;/code&amp;gt; 或 &amp;lt;code&amp;gt;25C9AB80&amp;lt;/code&amp;gt;），解析器会自动识别透明度；向量类字段往往支持数组或对象形式，例如 &amp;lt;code&amp;gt;x/y&amp;lt;/code&amp;gt; 或 &amp;lt;code&amp;gt;[x, y]&amp;lt;/code&amp;gt;。这些细节虽然不影响逻辑，但能显著影响表现，尤其是子弹与特效参数。&lt;br /&gt;
&lt;br /&gt;
读源码时还要注意“时间单位”。Java 里很多逻辑都是以“刻”为单位（&amp;lt;code&amp;gt;Time.delta&amp;lt;/code&amp;gt; 是每帧增量），所以你在源码里看到的 &amp;lt;code&amp;gt;reload = 60f&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;craftTime = 120f&amp;lt;/code&amp;gt; 实际对应 1 秒和 2 秒。把这个换算带回 JSON，有助于你把数值写得更直观。&lt;br /&gt;
&lt;br /&gt;
容器类型也有对应关系：&amp;lt;code&amp;gt;Seq&amp;lt;/code&amp;gt; 与数组一一对应，&amp;lt;code&amp;gt;ObjectSet&amp;lt;/code&amp;gt; 通常对应“去重数组”，&amp;lt;code&amp;gt;ObjectMap&amp;lt;/code&amp;gt; 则对应 JSON 对象的键值结构。看到这类类型时先想“它在 JSON 里长什么样”，再决定是否用数组或对象写法。&lt;br /&gt;
&lt;br /&gt;
另外，一些字段本质上是整数（例如 &amp;lt;code&amp;gt;size&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;tier&amp;lt;/code&amp;gt;），虽然 JSON 支持小数，但写成整数更稳妥，避免因为隐式转换造成困惑。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;consumes-不是普通字段&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== consumes 不是普通字段 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;consumes&amp;lt;/code&amp;gt; 是特殊语法，它不会直接写进字段，而是被解析成“消耗器”。常见的键包括 &amp;lt;code&amp;gt;items&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;liquids&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;power&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;itemFlammable&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;itemExplosive&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;coolant&amp;lt;/code&amp;gt; 等。你在 JSON 里写的消耗器最终会变成 &amp;lt;code&amp;gt;Consume*&amp;lt;/code&amp;gt; 对象，决定方块的效率与输入逻辑。也就是说，&amp;lt;code&amp;gt;consumes&amp;lt;/code&amp;gt; 更像“配方逻辑”，而不是单纯的“字段赋值”。&lt;br /&gt;
&lt;br /&gt;
不同消耗器还有不同的写法限制。&amp;lt;code&amp;gt;items&amp;lt;/code&amp;gt; 与 &amp;lt;code&amp;gt;liquids&amp;lt;/code&amp;gt; 支持数组或对象形式，&amp;lt;code&amp;gt;coolant&amp;lt;/code&amp;gt; 与 &amp;lt;code&amp;gt;liquid&amp;lt;/code&amp;gt; 如果需要 &amp;lt;code&amp;gt;optional&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;booster&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt; 之类参数，就必须写对象；&amp;lt;code&amp;gt;power&amp;lt;/code&amp;gt; 与 &amp;lt;code&amp;gt;powerBuffered&amp;lt;/code&amp;gt; 则决定是持续耗电还是从缓冲中抽取。理解这些差异，可以避免“写了不生效”的常见坑。&lt;br /&gt;
&lt;br /&gt;
类似的“特殊解析”还有 &amp;lt;code&amp;gt;requirements&amp;lt;/code&amp;gt; 与 &amp;lt;code&amp;gt;research&amp;lt;/code&amp;gt;。&amp;lt;code&amp;gt;requirements&amp;lt;/code&amp;gt; 本质是 &amp;lt;code&amp;gt;ItemStack[]&amp;lt;/code&amp;gt;，解析器允许 &amp;lt;code&amp;gt;&amp;amp;quot;copper/10&amp;amp;quot;&amp;lt;/code&amp;gt; 这种简写，也允许对象写法；&amp;lt;code&amp;gt;research&amp;lt;/code&amp;gt; 则是一个带 &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt; 和 &amp;lt;code&amp;gt;objectives&amp;lt;/code&amp;gt; 的对象，里面会出现 &amp;lt;code&amp;gt;SectorComplete&amp;lt;/code&amp;gt;、&amp;lt;code&amp;gt;OnSector&amp;lt;/code&amp;gt; 等目标类型。只要目标复杂，就应该回到源码或 Java 教程核对字段名。&lt;br /&gt;
&lt;br /&gt;
现实中的写法可以直接参考成熟模组。“饱和火力 3.3.0”的“离子钻头”在 &amp;lt;code&amp;gt;consumes.liquid&amp;lt;/code&amp;gt; 里同时使用 &amp;lt;code&amp;gt;optional&amp;lt;/code&amp;gt; 与 &amp;lt;code&amp;gt;booster&amp;lt;/code&amp;gt;，这类对象写法是 &amp;lt;code&amp;gt;ContentParser&amp;lt;/code&amp;gt; 明确支持的。看到类似配置时，你就能反推出“为什么需要对象而不是简写”。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;requirements&amp;lt;/code&amp;gt; 是“建造成本”，&amp;lt;code&amp;gt;consumes&amp;lt;/code&amp;gt; 是“运行成本”，两者用途完全不同。很多新人会把运行消耗写进 &amp;lt;code&amp;gt;requirements&amp;lt;/code&amp;gt;，导致方块只在建造时消耗一次，运行时不耗料。理解这条分界线，会让你的配方更符合玩家预期。&lt;br /&gt;
&lt;br /&gt;
== 覆盖与模板 ==&lt;br /&gt;
&lt;br /&gt;
如果 JSON 文件名与原版内容内部名相同，且不写 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt;，解析器会认为你是在“覆盖原版”。单位还有一个 &amp;lt;code&amp;gt;template&amp;lt;/code&amp;gt; 字段，可以用现成单位作为模板，再覆盖少量字段。这些机制能减少重复配置，但也更容易出错，建议熟悉后再使用。&lt;br /&gt;
&lt;br /&gt;
模板继承的另一个常见陷阱是“忘记重写关键字段”。比如你用模板继承了某个单位，但忘了改 &amp;lt;code&amp;gt;weapons&amp;lt;/code&amp;gt; 或 &amp;lt;code&amp;gt;abilities&amp;lt;/code&amp;gt;，就会得到一个“外形改了但行为没变”的单位。&amp;lt;code&amp;gt;research&amp;lt;/code&amp;gt; 字段也是类似：它本质上是一个对象，里面包含 &amp;lt;code&amp;gt;parent&amp;lt;/code&amp;gt; 与 &amp;lt;code&amp;gt;objectives&amp;lt;/code&amp;gt;，后者往往涉及 &amp;lt;code&amp;gt;SectorComplete&amp;lt;/code&amp;gt; 等复杂目标，这些结构在 JSON 里能写，但写错一个键就会整个解锁链失效。&lt;br /&gt;
&lt;br /&gt;
== 常见报错的读法 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;No content found with name &amp;#039;xxx&amp;#039;&amp;lt;/code&amp;gt; 通常是内部名拼写错误或内容解析失败；&amp;lt;code&amp;gt;Unknown consumption type&amp;lt;/code&amp;gt; 表示 &amp;lt;code&amp;gt;consumes&amp;lt;/code&amp;gt; 里写了不支持的键；&amp;lt;code&amp;gt;Invalid unit type&amp;lt;/code&amp;gt; 说明单位 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 拼写有误；&amp;lt;code&amp;gt;Class not found&amp;lt;/code&amp;gt; 则意味着 &amp;lt;code&amp;gt;type&amp;lt;/code&amp;gt; 指向了不存在的类或类名不完整。遇到这些报错时，先检查拼写，再检查解析器支持的类型，再看原版有没有对应内容。&lt;br /&gt;
&lt;br /&gt;
还有一些更“类型相关”的报错，比如 &amp;lt;code&amp;gt;Expected object&amp;lt;/code&amp;gt; 或 &amp;lt;code&amp;gt;Cannot parse&amp;lt;/code&amp;gt;，通常意味着你把对象写成了字符串，或把数组写成了对象。遇到这类问题时，回到类定义看字段类型是最直接的解决方案。另外，报错通常会带文件名和行号，建议先定位那一行，而不是盲目翻全文件。&lt;br /&gt;
&lt;br /&gt;
字段名大小写也会导致报错。JSON 的键名必须和 Java 字段名完全一致，&amp;lt;code&amp;gt;reloadTime&amp;lt;/code&amp;gt; 与 &amp;lt;code&amp;gt;reloadtime&amp;lt;/code&amp;gt; 就会被当成两个不同字段。内容内部名同样区分大小写，连字符也不能漏掉。遇到 &amp;lt;code&amp;gt;No content found&amp;lt;/code&amp;gt; 这类问题时，优先检查拼写。&lt;br /&gt;
&lt;br /&gt;
还有一种“不会报错但看起来不对”的情况：你写了字段，但 UI 没有对应显示。这通常是因为 &amp;lt;code&amp;gt;setStats()&amp;lt;/code&amp;gt; 或 &amp;lt;code&amp;gt;setBars()&amp;lt;/code&amp;gt; 没有为该字段添加展示，或者展示逻辑基于其他条件。遇到这种问题时，应该回到类定义看 UI 逻辑，而不是继续调数值。&lt;br /&gt;
&lt;br /&gt;
== 小结 ==&lt;br /&gt;
&lt;br /&gt;
只要能看懂 Java 类与字段，就能写对 JSON。&amp;lt;code&amp;gt;ContentParser&amp;lt;/code&amp;gt; 决定了“哪些写法被允许”，遇到问题时先看报错，再查解析器，效率会比盲猜高得多。建议多做“源码到 JSON”的逆向练习，熟悉之后写配置会非常顺手。把源码当成说明书，就不会被旧教程误导，学习曲线也会更平滑，后续进阶到 JS/Java 也会更轻松。等你形成自己的“字段词典”，写 JSON 会像在写一份更短的 Java，这时你已经具备独立读源码的能力，也更容易快速定位问题，改数值会更快，整体效率会更高也更稳定、更省心、更顺畅。&lt;/div&gt;</summary>
		<author><name>硫缺铅</name></author>
	</entry>
</feed>