MCBBS Wiki欢迎您共同参与编辑!在参与编辑之前请先阅读Wiki方针

如果在编辑的过程中遇到了什么问题,可以去讨论板提问。

为了您能够无阻碍地参与编辑 未验证/绑定过邮箱的用户,请尽快绑定/验证

MCBBS Wiki GitHub群组已上线!

您可以在回声洞中发表吐槽!

服务器状态监控。点击进入

本站由MCBBS用户自行搭建,与MCBBS及东银河系漫游指南(北京)科技有限公司没有从属关系。点此了解 MCBBS Wiki 不是什么>>

用户:MashKJo/1.12.2模组开发笔记/实现新维度

来自MCBBS Wiki
跳到导航 跳到搜索

要实现一个新维度,在代码层面,通常分为三个步骤:注册该维度、写出该维度的WorldProvider、写出该维度的ChunkGenerator。

注册维度

要注册一个维度,需要一个类型是“维度类型”(net.minecraft.world.DimensionType)的对象,DimensionType类是一个枚举类,这个枚举类默认有三个对象:OVERWORLD、NETHER和THE_END。

public class MyDim
{
    public static int dimID;
    public static DimensionType dimType;
    public void registerDimension()
    {
        dimType = DimensionType.register(dimName, dimSuffix, dimID, MyDimWorldProvider.class, isKeepLoaded);
        DimensionManager.registerDimension(dimID, dimType);
    }
}

要构造一个DimensionType对象,需要如下几个参数:

  • dimName是一个字符串,一般由小写字母和下划线组成,其意义显而易见。
  • dimSuffix可能会让人有点摸不着头脑——“维度后缀”?实际上,它是用来指定存档在保存维度的村庄等建筑的数据时,使用的文件后缀名。它同样是一个字符串。
  • dimID——这个参数别说模组开发者了,即使是会自己排查模组冲突的普通玩家也对它有一定的了解——毕竟不同模组添加的维度的ID如果发生冲突,肯定是会崩游戏的。这个参数当然是一个整型量,一般就是int类型。笔者这里建议不要把维度ID硬编码,而应该设定为从模组的配置文件里读取。
  • MyDimWorldProvider.class用于指定该维度的WorldProvider类。
  • isKeepLoaded是一个布尔值,意思是“是否持续加载该维度”,出于性能上的考量,一般都定为false。

最后,调用DimensionManager类的静态方法registerDimension(int id, DimensionType type),以实现新维度的注册。

看到这里,读者可能已经发现不对劲的地方了:这里的设计有问题吧?要知道如果不借助一些黑科技的话,枚举类是无法在除了它内部以外的地方产生新对象的。但我们的目标不是要添加新维度吗?那自然也需要一个全新的DimensionType才对啊。

答案是:不是“这里的设计有问题”,而是DimensionType是一个原版类,MC原版压根就没有对这块进行设计,因为MC的底层逻辑是不包括“为模组考虑”,即“提供很好的扩展性”的。不过这也无可厚非——因为维度这东西和物品、方块不同,MC从1.0版本到1.12版本,维度只有三个,站在原版的角度看,也确实没必要为新维度的添加专门造轮子。

那么读者又会问了:既然原版的DimensionType类可扩展性几乎为0,那为什么我们在添加新维度的时候还要用到这个类呢?因为Forge出手了。经过Forge的一番patch后,这个类获得了一个名为register的静态方法:

public static DimensionType register(String name, String suffix, int id, Class<? extends WorldProvider> provider, boolean keepLoaded)
{
    String enum_name = name.replace(" ", "_").toLowerCase();
    DimensionType ret = net.minecraftforge.common.util.EnumHelper.addEnum(DimensionType.class, enum_name, ENUM_ARGS,id, name, suffix, provider);
    return ret.setLoadSpawn(keepLoaded);
}

这个方法调用了Forge添加的一个类——EnumHelper,来实现在某个枚举类内部以外的地方添加该枚举类的对象。如果细看addEnum这个方法的话,你会发现这个方法用到了Java的反射机制——果然是黑科技。

DimensionManager是一个完完全全的Forge类,且该类中,实现了对原版三个维度的注册——也就是说,这个类实际上不能体现原版中维度的注册机制——甚至退一万步说,原版中到底有没有“维度的注册”这个概念都不好说。

注意:不要将维度类型和世界类型搞混淆。

WorldProvider

ChunkGenerator