湖中日常001:從一句提問到Item享元


為什么在isRemote的情況下修改的fl的值會同步到?!isRemote?的服務(wù)端的fl上啊
? 那天我吃完飯,打開手機,往群里轉(zhuǎn)了一條業(yè)界分析《迷你世界》的文章,然后打開群,看到有這樣一條提問。首先我想吐槽的是后面那張圖截得不清不楚,根本看不出到底誰是前端誰是后端,但我再一看,!isRemote對應(yīng)的日志輸出是a開頭,else對應(yīng)的是b開頭,這說明確實后端是a。
嗯,isRemote 是前端,所以 !isRemote 是后端,所以 else 是前端。有點繞,這里把 isRemote = true 的部分寫前面會減小一點理解成本,但那不重要了。
onLeftClickEntity是Item類里一個接口,即使我不打開IDE我也知道這是Item類的,因為我之前寫《神兵》的代碼時就覆寫了這玩意,造成不少問題,所以頗有印象。
雖然我沒有研究過這個代碼的調(diào)用原理,但我很確定這個onLeftClickEntity是在前后端各調(diào)用一次的,這是我不少實踐留下來的印象??墒牵热凰紕澇鰜砹薸sRemote,怎么會前后端紊亂的問題呢?
“上整個代碼,這截圖啥也看不出?!蔽矣X得,他一定是哪個其他的地方改了這個變量的值,于是我要求他提供更為完整的代碼截圖,盡管我知道這其實無濟于事——萬一是哪個其他文件改了呢?只有上傳整個工程才能徹底排除這個可能。
其他地方的串擾估且不論,頗為有意思的是,他還是前端的往后端同步了。要知道,一般的邏輯都是后端往前端同步,或者干脆沒同步,像這種莫名同步的事可以說是聞所未聞。Item的nbt是從后端往前端自動同步的,所以……
所以他這“fl”變量是寫在哪了呢?這好像不是nbt啊,他該不會是寫在Item里了吧?
考慮到一般的modder都是Run Client單機測試的,所以這種時候其實是前后端各一個線程,兩者共享一個對象。如果有一邊改了,那真的會“同步”。
但你為什么要在游戲中修改Item的成員變量????
于是我說,“fl是什么東西?你要知道一件事,如果你在item類里存了個對象。那么所有的同種類物品共享這個值。單機游戲里,這玩意應(yīng)該是前后端共享一個item對象的?!?/span>

話音剛落,圖來了。我看了完整截圖,果然。這變量寫在了Item里,那肯定不行?!盀槭裁磿健笔谴我膯栴},因為根本就不該這么寫。一個寫錯的東西會如何,那不重要。
我:“你試圖修改item里的東西,這個出發(fā)點就錯了。嗯,那就是我(剛才)說的原理?!?/p>
提問者:“fl是flag?!保ㄟ@句是在回答前面我問的“fl是什么東西?”)
我:“你先看懂我說的是什么意思?!蔽覜]意識到他是在回答我前一句話,我以為這是在自我辯解,令我更加火大。
提問者:“但是我沒有加static關(guān)鍵字???”
那么,這句確實是在辯解。我這次是合理火大。
我:(暗罵一句tnnd)“item是享元的。這跟你是否static無關(guān),這是mc架構(gòu)決定的。所有的同類物品是共享item對象的,這是不爭的事實……”
提問者:“我明白了,得在itemStack里加nbt才行?!?/p>
我:“……不要讓我浪費太多時間重復(fù)。(看到了上一句)那我還要提醒你,nbt是前后端同步的。”

事實上,當我寫mod的時候,哪怕是初學(xué),也從未試圖這么干過。畢竟,ItemStack擺在那呢,為啥要想不開去搞Item。那時候我還不知道“享元”這詞,后來我是通過這個設(shè)計才知道的。
如果回顧寫物品的過程就會發(fā)現(xiàn),比如新加一個物品叫做“鉆石蘋果”,那么對應(yīng)的Item只有在注冊的時候new過一次。而且,這Item也不包含個數(shù)什么的,這是無法忽略的一點。
假如包里有十個鉆石蘋果,分為三堆,它們每一堆都是一個ItemStack,對應(yīng)三個ItemStack對象,但是引用同一個Item對象。
另外,不同meta的同一物品,對應(yīng)的是相同的Item對象。如果想獲取具有特定meta的物品堆,應(yīng)該在new ItemStack的時候傳參數(shù)。
public ItemStack(Item itemIn, int amount, int meta)
這個函數(shù)里的第三個參數(shù)可以指定特定meta的物品堆。
為什么要這樣處理?這可以說是顯然的,同一程度的不同的物品堆,很大程度上共享了相同的特質(zhì),把那些特質(zhì)(比如攻擊傷害)每個物品都存一個float,完全沒必要。如果你要自己寫一個游戲的話,你寫著寫著也會自然這么做。多想一想如果你自己寫一個MC的話,你會怎么做,很多東西自然就理解了。
不過,我們還是經(jīng)常會遇到一些同類物品不同效果的需求的。最典型的就是匠魂的工具,瑪玉靈手柄的鎬和石頭手柄的鎬是同一物品,但效果截然不同,這種就要通過讀取ItemStack的nbt來實現(xiàn)。如果想在物品里存儲一些信息,那就要靠nbt了。