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

湖中日常001:从一句提问到Item享元

2022-01-23 14:08 作者:道家深湖  | 我要投稿


群友配图1号
群友配图2号

为什么在isRemote的情况下修改的fl的值会同步到 !isRemote 的服务端的fl上啊

  那天我吃完饭,打开手机,往群里转了一条业界分析《迷你世界》的文章,然后打开群,看到有这样一条提问。首先我想吐槽的是后面那张图截得不清不楚,根本看不出到底谁是前端谁是后端,但我再一看,!isRemote对应的日志输出是a开头,else对应的是b开头,这说明确实后端是a。

嗯,isRemote 是前端,所以 !isRemote 是后端,所以 else 是前端。有点绕,这里把 isRemote = true 的部分写前面会减小一点理解成本,但那不重要了。

onLeftClickEntity是Item类里一个接口,即使我不打开IDE我也知道这是Item类的,因为我之前写《神兵》的代码时就覆写了这玩意,造成不少问题,所以颇有印象。

虽然我没有研究过这个代码的调用原理,但我很确定这个onLeftClickEntity是在前后端各调用一次的,这是我不少实践留下来的印象。可是,既然他都划出来了isRemote,怎么会前后端紊乱的问题呢?

“上整个代码,这截图啥也看不出。”我觉得,他一定是哪个其他的地方改了这个变量的值,于是我要求他提供更为完整的代码截图,尽管我知道这其实无济于事——万一是哪个其他文件改了呢?只有上传整个工程才能彻底排除这个可能。

其他地方的串扰估且不论,颇为有意思的是,他还是前端的往后端同步了。要知道,一般的逻辑都是后端往前端同步,或者干脆没同步,像这种莫名同步的事可以说是闻所未闻。Item的nbt是从后端往前端自动同步的,所以……

所以他这“fl”变量是写在哪了呢?这好像不是nbt啊,他该不会是写在Item里了吧?

考虑到一般的modder都是Run Client单机测试的,所以这种时候其实是前后端各一个线程,两者共享一个对象。如果有一边改了,那真的会“同步”。

但你为什么要在游戏中修改Item的成员变量????

于是我说,“fl是什么东西?你要知道一件事,如果你在item类里存了个对象。那么所有的同种类物品共享这个值。单机游戏里,这玩意应该是前后端共享一个item对象的。”

完整截图

话音刚落,图来了。我看了完整截图,果然。这变量写在了Item里,那肯定不行。“为什么会同步”是次要的问题,因为根本就不该这么写。一个写错的东西会如何,那不重要。

我:“你试图修改item里的东西,这个出发点就错了。嗯,那就是我(刚才)说的原理。”

提问者:“fl是flag。”(这句是在回答前面我问的“fl是什么东西?”)

我:“你先看懂我说的是什么意思。”我没意识到他是在回答我前一句话,我以为这是在自我辩解,令我更加火大。

提问者:“但是我没有加static关键字啊?”

那么,这句确实是在辩解。我这次是合理火大。

我:(暗骂一句tnnd)“item是享元的。这跟你是否static无关,这是mc架构决定的。所有的同类物品是共享item对象的,这是不争的事实……”

提问者:“我明白了,得在itemStack里加nbt才行。”

我:“……不要让我浪费太多时间重复。(看到了上一句)那我还要提醒你,nbt是前后端同步的。”

事实上,当我写mod的时候,哪怕是初学,也从未试图这么干过。毕竟,ItemStack摆在那呢,为啥要想不开去搞Item。那时候我还不知道“享元”这词,后来我是通过这个设计才知道的。

如果回顾写物品的过程就会发现,比如新加一个物品叫做“钻石苹果”,那么对应的Item只有在注册的时候new过一次。而且,这Item也不包含个数什么的,这是无法忽略的一点。

假如包里有十个钻石苹果,分为三堆,它们每一堆都是一个ItemStack,对应三个ItemStack对象,但是引用同一个Item对象。

另外,不同meta的同一物品,对应的是相同的Item对象。如果想获取具有特定meta的物品堆,应该在new ItemStack的时候传参数。

public ItemStack(Item itemIn, int amount, int meta)

这个函数里的第三个参数可以指定特定meta的物品堆。

为什么要这样处理?这可以说是显然的,同一程度的不同的物品堆,很大程度上共享了相同的特质,把那些特质(比如攻击伤害)每个物品都存一个float,完全没必要。如果你要自己写一个游戏的话,你写着写着也会自然这么做。多想一想如果你自己写一个MC的话,你会怎么做,很多东西自然就理解了。

不过,我们还是经常会遇到一些同类物品不同效果的需求的。最典型的就是匠魂的工具,玛玉灵手柄的镐和石头手柄的镐是同一物品,但效果截然不同,这种就要通过读取ItemStack的nbt来实现。如果想在物品里存储一些信息,那就要靠nbt了。





湖中日常001:从一句提问到Item享元的评论 (共 条)

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