欢迎光临散文网 会员登陆 & 注册

1.16生物踩坑

2021-07-04 21:46 作者:道家深湖  | 我要投稿

我之前在1.12写过生物,甚至还有菜鸟版教程(https://www.bilibili.com/video/BV1Ar4y1K7Qk?p=10)。


令我没想到的是,1.16里搞生物比1.12还要复杂些。多出来的要点是:

  1. 你必须手动注册刷怪蛋,写好了实体后不会自然有“暴徒卵”。

  2. 你不能直接使用MC自己的刷怪蛋,需要自己写一个刷怪蛋物品类以匹配延迟注册框架。

  3. 你必须手动在FMLInit里设置任务,以确保生成该生物时不会报属性exception。

  4. 你必须明确地给生物注册一个渲染器,否则生物一出现会直接崩溃。不只是生物,任何实体都是如此。


1.16里,比较通用的方式是使用DeferRegistry。如果你照抄Boson教程的话,就会用这种方式注册东西。但……也有些mod不这么干。比如暮色森林,你不能直接照抄暮色的生物源码,因为两种体系不兼容。

诚然,Boson的教程教了如何写实体,也教了如何写生物(https://boson.v2mcdev.com/entity/passiveentityandai.html),但是他没有教如何写刷怪蛋,只是用指令召唤了所写的生物。。在1.12,一般你看到的教程里,注册生物后就自然而然地有了刷怪蛋,反而是没有蛋会比较困难些。

首先我抄了暮色的源码,然后我发现抛异常了,因为物品的注册比生物早,试图在注册物品时引用生物类型就直接崩了。

延迟注册版,并不能用

那么,是不是暮色的非延迟注册导致的呢?我改成了延迟注册,仍然不行。

根据群友的指点,我知道了问题所在。

群友给出的截图

首先,你不能直接用普通的刷怪蛋,因为他不包含supplier(必须立刻传入对象)。物品比实体先注册,所以实体无法被存进刷怪蛋。于是,你得自己扩展SpawnEggItem类,让他接受supplier,对原本的值传空(实际不能传空,需要随便传个东西进去),然后覆盖获取实体类型的方法。

https://forums.minecraftforge.net/topic/81614-how-do-i-make-an-entityspawnegg-class-that-accepts-a-registry-supplier/?tab=comments#comment-387356

然后群友给出了上述的链接。根据链接,我写出了如下的代码:


以下为com.deeplake.backtones.registry.EntityRegistry节选,在这里注册了生物 MJDS_SKELETON:


然后又在我的ItemRegisty里注册了刷怪蛋。

其中UNCOMON_PROP是随便一个物品属性,是什么不重要,默认的也可。当然了,这个刷怪蛋既没有翻译,也没有图片,都得自己搞。不过搞这都很简单,这里就不赘述了。

你可能会问,为什么要搞个DOLPHIN进去呢?我这骷髅又不是海豚。很简单,我只是随便传了个不为空的类别进去,让他通过notNull检查。你传什么都行,只要不为空。你也可以封装进构造函数,把这脏代码藏起来——反正脏的是forge,不必有负罪感。底层写的差,带动上层一起差。

你试图消灭造轮子行为吗?

https://github.com/MinecraftForge/MinecraftForge/pull/6299

别人也是这么想的,然而没成功。顺便一提,链接里的Candiboo是我还在菜鸟期就给过我指引的大佬。


那么,到此,进了游戏确实有刷怪蛋了,但是刷不出来生物。刷的时候报错:

如果你忘了手动注册属性

万能的群大佬zomb又给我指了一条路:https://forums.minecraftforge.net/topic/96085-spawn-custom-mob-error-executing-task-on-server/?tab=comments#comment-437958

于是乎,我的主类里多了如下代码。

是的,你需要手动告诉forge需要给这生物注册属性,这么无聊的步骤在1.12是完全没有的。


然后你用刷怪蛋一刷……游戏崩了,因为没注册渲染类。注册过就好了。


我有一些生物是没有模型的,因此我写了个什么都不渲染的VoidRender给它们。这是我注册实体渲染的地方:


好,这就差不多了。顺便提醒一下各位,1.16官方表里,生物的getPosition这个成员不要使用,它是纯客户端的。在服务器里一跑就崩。

你呀,总是能给我搞出点新花样


顺便提一下关于复活生物的事。

我在一个生物死亡或被去除的瞬间(onRemovedFromWorld)的类型和nbt都存了下来,希望之后可以复活他。几经尝试,最终复活的代码如上。值得指出的有两点:

  1. deathTime必须手动重置,它是会存到nbt里的。如果你不重置,可能会导致生物死时服务端线程不调用onRemovedFromWorld。

  2. 你需要手动把血回满,血也是存在nbt里的。顺便,revive没有卵用,那是给玩家类使用的,一般的生物调用了没有意义。我把生物的uuid设为新的了,这一步可有可无。

顺便,这里也演示了如何在1.16召唤实体与生物。干净版代码如下:

和1.12里没什么区别吧,只不过addToWorld变成了addFreshEntity。

总之,在各位大佬的帮助下,我总算是在1.16写出了生物了。

这里给出某知名小说里的俳句:

That is not dead which can eternal lie

And with strange aeons even death may die

我做的事情是写了一个骷髅战士,它死亡或被去除时,会在其出生点生成一个复活云雾。云雾周围16格没有玩家时,复活云雾消失,骷髅战士重新复活。这模仿的是某个FC游戏里,玩家离开某处再回来时,会发现怪物都重置了的效果。

……以及我对之的翻译:

未死之身永世卧

万古升诡灭阎罗


1.16生物踩坑的评论 (共 条)

分享到微博请遵守国家法律