zh_cn:tutorial:trees
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
zh_cn:tutorial:trees [2021/07/14 16:55] – [Creating a TreeDecorator] breakice | zh_cn:tutorial:trees [2022/08/18 03:40] – [添加树木 [1.17](高级)] solidblock | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | FIXME 本文有一段时间没有更新了,可能对未来版本不起作用。请参考[[tutorial: | ||
+ | |||
===== 添加树木 [1.17](高级) ===== | ===== 添加树木 [1.17](高级) ===== | ||
阅读本文之前,建议先学习如何创建一个特征地形。\\ | 阅读本文之前,建议先学习如何创建一个特征地形。\\ | ||
- | 参见[[zh_cn: | + | 参见 [[zh_cn: |
- | 树木是在你的mod中拓展原版世界生成的一个好方法。\\ | + | 树木是在你的 mod 中拓展原版世界生成的一个好方法。\\ |
注意本话题较为高级,因此开始之前,最好要有关于修改世界生成的丰富经验。 | 注意本话题较为高级,因此开始之前,最好要有关于修改世界生成的丰富经验。 | ||
- | |||
- | ==== 关于API ==== | ||
- | 有个API可以让你非常方便的添加树木,但是他还在开发中,< | ||
- | |||
- | PR[[https:// | ||
===== 创建简单的树木 ===== | ===== 创建简单的树木 ===== | ||
Line 25: | Line 22: | ||
如果想让树木长得不那么像是原版的树木,可以选择创建自定义的实现。但是实际上原版的实现通常足够模组的开发了。 | 如果想让树木长得不那么像是原版的树木,可以选择创建自定义的实现。但是实际上原版的实现通常足够模组的开发了。 | ||
- | ==== 创建ConfiguredFeature ==== | + | ==== 创建 ConfiguredFeature ==== |
- | 不需要创建新的'' | + | 不需要创建新的 '' |
- | 把这个添加到你的'' | + | 把这个添加到你的 '' |
<code java> | <code java> | ||
Line 45: | Line 42: | ||
</ | </ | ||
- | 现在只需要像往常那样向游戏注册'' | + | 现在只需要像往常那样向游戏注册 '' |
<code java> | <code java> | ||
Line 54: | Line 51: | ||
Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, | Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, | ||
- | // 应该为树木使用VEGETAL_DECORATION生成步骤 | + | // 应该为树木使用 VEGETAL_DECORATION 生成步骤 |
BiomeModifications.addFeature(BiomeSelectors.foundInOverworld(), | BiomeModifications.addFeature(BiomeSelectors.foundInOverworld(), | ||
} | } | ||
Line 60: | Line 57: | ||
==== 创建树苗 ==== | ==== 创建树苗 ==== | ||
- | 树苗是生长树木的一类特殊方块,需要'' | + | 树苗是生长树木的一类特殊方块,需要 '' |
- | === 创建SaplingGenerator === | + | === 创建 SaplingGenerator === |
- | 简单的生成器接收树木的'' | + | 简单的生成器接收树木的 '' |
<code java> | <code java> | ||
Line 83: | Line 80: | ||
后面会展示高级的'' | 后面会展示高级的'' | ||
- | === 创建SaplingBlock === | + | === 创建 SaplingBlock === |
- | 创建方块本身需要继承'' | + | 创建方块本身需要继承'' |
<code java> | <code java> | ||
Line 95: | Line 92: | ||
=== 注册SaplingBlock === | === 注册SaplingBlock === | ||
- | 要注册树苗,按照注册方块的以下步骤(参见[[zh_cn: | + | 要注册树苗,按照注册方块的以下步骤(参见[[zh_cn: |
把这个放在用于你的树苗方块的类中: | 把这个放在用于你的树苗方块的类中: | ||
Line 109: | Line 106: | ||
</ | </ | ||
- | ===== 创建TrunkPlacer ===== | + | ===== 创建 TrunkPlacer ===== |
- | '' | + | '' |
- | ==== 原版TrunkPlacers ==== | + | ==== 原版 TrunkPlacers ==== |
- | 在创建'' | + | 在创建 '' |
* '' | * '' | ||
Line 121: | Line 118: | ||
==== 创建TrunkPlacerType ==== | ==== 创建TrunkPlacerType ==== | ||
- | 往游戏注册'' | + | 往游戏注册 '' |
- | 可惜Fabric API目前没有用于创建和注册'' | + | 可惜 |
- | 我们准备创建一个调用器(见[[https:// | + | 我们准备创建一个调用器(invoker)(见[[https:// |
- | 以下是我们的mixin,不要忘记加到mixin配置中: | + | 以下是我们的 mixin ,不要忘记加到 mixin 配置中: |
<code java> | <code java> | ||
Line 140: | Line 137: | ||
</ | </ | ||
- | ==== 创建TrunkPlacer ==== | + | ==== 创建 TrunkPlacer ==== |
- | '' | + | '' |
- | * 用于序列化的编码解码器。编码解码器(codec)是其自己的话题,这里我们只需要使用'' | + | * 用于序列化的编码解码器。编码解码器(codec)是其自己的话题(topic),这里我们只需要使用 '' |
- | * 获取器(getter),返回'' | + | * 获取器(getter),返回 '' |
- | * '' | + | * '' |
- | '' | + | '' |
<code java> | <code java> | ||
Line 169: | Line 166: | ||
this.setToDirt(world, | this.setToDirt(world, | ||
| | ||
- | // 迭代到树干高度限制,并使用TrunkPlacer中的getAndSetState方法放置两个方块 | + | // 迭代到树干高度限制,并使用 TrunkPlacer 中的 getAndSetState 方法放置两个方块 |
for (int i = 0; i < height; i++) { | for (int i = 0; i < height; i++) { | ||
this.getAndSetState(world, | this.getAndSetState(world, | ||
Line 176: | Line 173: | ||
// 创建两个树木节点——一个用于第一个树干,另一个用于第二个 | // 创建两个树木节点——一个用于第一个树干,另一个用于第二个 | ||
- | // 将树干中最高的方块设为中心坐标给FoliagePlacer使用 | + | // 将树干中最高的方块设为中心坐标给 FoliagePlacer 使用 |
return ImmutableList.of(new FoliagePlacer.TreeNode(startPos.up(height), | return ImmutableList.of(new FoliagePlacer.TreeNode(startPos.up(height), | ||
new FoliagePlacer.TreeNode(startPos.east().north().up(height), | new FoliagePlacer.TreeNode(startPos.east().north().up(height), | ||
Line 184: | Line 181: | ||
==== 注册并使用TrunkPlacer ==== | ==== 注册并使用TrunkPlacer ==== | ||
- | 使用你的调用器,为你的'' | + | 使用你的调用器,为你的 '' |
<code java> | <code java> | ||
Line 190: | Line 187: | ||
</ | </ | ||
- | 现在将你的'' | + | 现在将你的 '' |
<code java> | <code java> | ||
[...] | [...] | ||
Line 198: | Line 195: | ||
===== 创建FoliagePlacer ===== | ===== 创建FoliagePlacer ===== | ||
- | '' | + | '' |
==== 原版FoliagePlacer ==== | ==== 原版FoliagePlacer ==== | ||
- | 创建'' | + | 创建 '' |
* '' | * '' | ||
Line 207: | Line 204: | ||
* '' | * '' | ||
- | ==== 创建FoliagePlacerType ==== | + | ==== 创建 FoliagePlacerType ==== |
- | 往游戏中注册'' | + | 往游戏中注册 '' |
- | 和'' | + | 和 '' |
<code java> | <code java> | ||
Line 222: | Line 219: | ||
</ | </ | ||
- | ==== 创建FoliagePlacer ==== | + | ==== 创建 FoliagePlacer ==== |
- | '' | + | '' |
- | * 用于序列化的编码解码器。在此例中我们展示了如何往编码解码器中添加一个额外的IntProvider。 | + | * 用于序列化的编码解码器。在此例中我们展示了如何往编码解码器中添加一个额外的 IntProvider。 |
- | * 用于获取'' | + | * 用于获取 '' |
- | * '' | + | * '' |
- | * '' | + | * '' |
- | * '' | + | * '' |
- | 我们的'' | + | 我们的 '' |
<code java> | <code java> | ||
public class RichFoliagePlacer extends FoliagePlacer { | public class RichFoliagePlacer extends FoliagePlacer { | ||
- | // 对于foliageHeight我们使用由IntProvider.createValidatingCodec生成的编码解码器 | + | // 对于foliageHeight我们使用由 IntProvider.createValidatingCodec 生成的编码解码器 |
- | // 方法参数,我们传入IntProvider的最小值和最大值 | + | // 方法参数,我们传入 IntProvider 的最小值和最大值 |
- | // 往你的TrunkPlacer/ | + | // 为了向你的 TrunkPlacer/ |
// | // | ||
- | // 对于创建我们自己的编码解码器类型的例子,可以参考IntProvider.createValidatingCodec方法的源代码。 | + | // 如果想创建属于我们自己的编码解码器类型,可以参考 IntProvider.createValidatingCodec 方法的源代码。 |
public static final Codec< | public static final Codec< | ||
fillFoliagePlacerFields(instance) | fillFoliagePlacerFields(instance) | ||
Line 268: | Line 265: | ||
for ( | for ( | ||
- | // 从X开始:中心 - 半径 | + | // 从 X 开始:中心 - 半径 |
Vec3i vec = center.subtract(new Vec3i(radius, | Vec3i vec = center.subtract(new Vec3i(radius, | ||
- | // 在X结束:中心 + 半径 | + | // 在 X 结束:中心 + 半径 |
vec.compareTo(center.add(new Vec3i(radius, | vec.compareTo(center.add(new Vec3i(radius, | ||
// 每次移动1 | // 每次移动1 | ||
Line 284: | Line 281: | ||
@Override | @Override | ||
public int getRandomHeight(Random random, int trunkHeight, | public int getRandomHeight(Random random, int trunkHeight, | ||
- | // 使用IntProvider挑选随机高度 | + | // 使用 IntProvider 挑选随机高度 |
return foliageHeight.get(random); | return foliageHeight.get(random); | ||
} | } | ||
Line 290: | Line 287: | ||
@Override | @Override | ||
protected boolean isInvalidForLeaves(Random random, int dx, int y, int dz, int radius, boolean giantTrunk) { | protected boolean isInvalidForLeaves(Random random, int dx, int y, int dz, int radius, boolean giantTrunk) { | ||
- | // 我们的FoliagePlacer不为树叶设置限制 | + | // 我们的 FoliagePlacer 不为树叶设置限制 |
return false; | return false; | ||
} | } | ||
Line 296: | Line 293: | ||
</ | </ | ||
- | ==== 注册并使用你的FoliagePlacer ==== | + | ==== 注册并使用你的 FoliagePlacer ==== |
- | 该过程几乎相同,只需要使用你的调用器创建并注册'' | + | 该过程几乎相同,只需要使用你的调用器(invoker)创建并注册 '' |
<code java> | <code java> | ||
Line 303: | Line 300: | ||
</ | </ | ||
- | 并将旧的'' | + | 并将旧的 '' |
<code java> | <code java> | ||
Line 311: | Line 308: | ||
</ | </ | ||
- | ===== 创建一个TreeDecorator ===== | + | ===== 创建一个 TreeDecorator ===== |
- | A '' | + | '' |
- | If you have a game development background, it's essentially a post-processor, but for trees. | + | |
- | ==== Vanilla | + | ==== 原版的 |
- | Almost none vanilla | + | 原版的 |
- | and '' | + | 和 '' |
- | For anything non-trivial, | + | 虽然这是一件非常繁琐的事情,但是你还是需要创建你自己的 |
- | ==== Creating a TreeDecoratorType ==== | + | ==== 创建一个 |
- | A '' | + | 一个 |
- | Fabric API doesn' | + | FabricAPI 没有提供任何工具用于创建 |
- | Our mixin will look almost exactly the same, don't forget to add it to your mixin config: | + | 我们的 |
<code java> | <code java> | ||
Line 338: | Line 334: | ||
</ | </ | ||
- | ==== Creating the TreeDecorator ==== | + | ==== 创建 |
- | A '' | + | '' |
- | * A codec for serialization, | + | * 一个可用于序列化的编码解码器。但默认情况下为空,因为构造函数是没有参数的。如果需要,你可以随时扩展(expand)它。 |
- | * A getter for your '' | + | * 你的 |
- | * The '' | + | * 为修饰树而存在的 |
- | Our '' | + | 我们的 |
<code java> | <code java> | ||
public class RichTreeDecorator extends TreeDecorator { | public class RichTreeDecorator extends TreeDecorator { | ||
public static final RichTreeDecorator INSTANCE = new RichTreeDecorator(); | public static final RichTreeDecorator INSTANCE = new RichTreeDecorator(); | ||
- | // Our constructor doesn' | + | // 我们的构造函数没有任何参数,所以我们创建一个单元编解码器,让他返回一个单例对象。 |
public static final Codec< | public static final Codec< | ||
Line 360: | Line 356: | ||
@Override | @Override | ||
public void generate(TestableWorld world, BiConsumer< | public void generate(TestableWorld world, BiConsumer< | ||
- | // Iterate through block positions | + | // 遍历方块位置 |
for (BlockPos logPosition : logPositions) { | for (BlockPos logPosition : logPositions) { | ||
- | // Pick a value from 0 (inclusive) to 4 (exclusive) and if it' | + | // 选择一个从 |
- | // This is the chance for spawning the gold block | + | // 这是一个让树生成金块从而让我们走向富裕的机会,太爽了。 |
if (random.nextInt(4) == 0) { | if (random.nextInt(4) == 0) { | ||
- | // Pick a random value from 0 to 4 and determine the side where the gold block will be placed using it | + | // 选择一个从 |
int sideRaw = random.nextInt(4); | int sideRaw = random.nextInt(4); | ||
Direction side = switch (sideRaw) { | Direction side = switch (sideRaw) { | ||
Line 375: | Line 371: | ||
}; | }; | ||
- | // Offset the log position by the resulting side | + | // 通过结果边偏移树木位置 |
BlockPos targetPosition = logPosition.offset(side, | BlockPos targetPosition = logPosition.offset(side, | ||
- | // Place the gold block using the replacer | + | // 使用 |
- | // This is the standard way of placing blocks in TrunkPlacers, FoliagePlacers | + | // 这是在 |
replacer.accept(targetPosition, | replacer.accept(targetPosition, | ||
} | } | ||
Line 387: | Line 383: | ||
</ | </ | ||
- | ==== Registering and using your TreeDecorator ==== | + | ==== 注册和使用你的 |
- | First, create your '' | + | 首先,使用调用器(invoker)创建你的 |
<code java> | <code java> | ||
Line 394: | Line 390: | ||
</ | </ | ||
- | Then, between the creation of your '' | + | 然后,在创建你的 |
<code java> | <code java> | ||
Line 402: | Line 398: | ||
</ | </ | ||
- | ===== Creating an advanced | + | ===== 创建一个高级的 |
- | So, remember how I told you that '' | + | 所以,还记得我告诉过你 |
- | Here's an example of that - we create several vanilla trees instead of the actual trees depending on the chance: | + | 这是一个例子 |
<code java> | <code java> | ||
Line 419: | Line 415: | ||
int chance = random.nextInt(100); | int chance = random.nextInt(100); | ||
| | ||
- | // Each tree has a 10% chance | + | // 每棵树都有 |
if (chance < 10) { | if (chance < 10) { | ||
return ConfiguredFeatures.OAK; | return ConfiguredFeatures.OAK; | ||
Line 436: | Line 432: | ||
} | } | ||
| | ||
- | // If none of that happened (the random value was between | + | // 如果这些都没有发生(随机值在 |
return feature; | return feature; | ||
} | } | ||
Line 442: | Line 438: | ||
</ | </ | ||
- | This isn't a very practical, but it shows what you can achieve using '' | + | 其实这没啥练手的,但是他给你展示了 |
- | ===== Extra settings for your tree ===== | + | ===== 给你的树整点额外逻辑! |
- | Using the extra '' | + | 使用额外的 |
==== dirtProvider ==== | ==== dirtProvider ==== | ||
- | Sets the '' | + | 还记得巨型云杉木下面的灰化土吗,它就是用这个做到的。 |
+ | |||
+ | 设置一下 | ||
- | Example: | + | 例子: |
<code java> | <code java> | ||
[...] | [...] | ||
Line 458: | Line 456: | ||
==== decorators ==== | ==== decorators ==== | ||
- | Used to add '' | + | 用来在你的树上添加 |
- | This was briefly showcased in the '' | + | 本教程的 |
- | If you want, you can add multiple | + | 如果你想,你可以使用像 |
- | Example: | + | 例子 |
<code java> | <code java> | ||
Line 475: | Line 473: | ||
==== ignoreVines ==== | ==== ignoreVines ==== | ||
- | Makes the tree generation ignore vines stuck in the way. | + | 使树生长时无视藤蔓。 |
- | Example: | + | 例子 |
<code java> | <code java> | ||
Line 486: | Line 484: | ||
==== forceDirt ==== | ==== forceDirt ==== | ||
- | Forces the '' | + | 强制 |
- | Example: | + | 例子: |
<code java> | <code java> | ||
Line 496: | Line 494: | ||
</ | </ | ||
- | ===== Creating a BlockStateProvider ===== | + | ===== 创建一个 |
- | Coming soon. | + | 敬请期待! |
zh_cn/tutorial/trees.txt · Last modified: 2022/08/18 03:40 by 127.0.0.1