[Minecraft/我的世界 1.16.x] 鐵傀儡刷新機(jī)制代碼解讀

今天閑著無(wú)聊看了一下MC1.16.1的代碼就順便講一下這個(gè)鐵傀儡的刷新好了。部分函數(shù)并沒(méi)有列出,純口述,因?yàn)樘嗔恕?/p>
開(kāi)頭先吐槽一下這個(gè)專(zhuān)欄編輯器,真的是魔鬼般難用,無(wú)奈直接截圖。

Minecraft的循環(huán)程序是以每秒20周期的固定速度運(yùn)行的,即tps: 20.0。因此每刻發(fā)生在每0.05秒。在游戲中的一天將正好為24000刻,或20分鐘。但是這個(gè)速率也不是完全固定的。如果電腦的性能不足以跟上這個(gè)速度,一個(gè)游戲刻的運(yùn)行時(shí)間就被延長(zhǎng),每秒的游戲刻就會(huì)變少。由于游戲中的絕大多數(shù)動(dòng)作都是以游戲刻而不是真實(shí)世界的時(shí)鐘作為時(shí)間基準(zhǔn),這意味著在較慢的電腦上很多事情都要花更長(zhǎng)的時(shí)間來(lái)完成。
每過(guò)去一刻,游戲的各方面都會(huì)更新:移動(dòng)的實(shí)體位置會(huì)發(fā)生變化,生物會(huì)檢查周?chē)h(huán)境并更新自身的行為,玩家的生命值和饑餓值會(huì)根據(jù)玩家的處境發(fā)生變化,等等。這些游戲的方面是服務(wù)端的行為,和負(fù)責(zé)渲染游戲本身的客戶(hù)端的更新速度沒(méi)有關(guān)系。也就是說(shuō),游戲的幀率(FPS)不影響TPS,電腦的圖形性能不會(huì)影響到游戲機(jī)制。-Minecraft Wiki

村民會(huì)在兩種情況下嘗試生成鐵傀儡,分別是:受到驚嚇 和 與其他村民扯蛋(聊天)。
驚嚇

恐嚇式鐵傀儡生成由PanicTask類(lèi)控制,這里截取了其中的兩個(gè)方法:
keepRunning方法有三個(gè)參數(shù),其中long?l為當(dāng)前時(shí)間。所以第八行的if語(yǔ)句的含義就是每100ticks嘗試一次鐵傀儡的生成,即真實(shí)時(shí)間5秒。(其實(shí)是要被100整除,但持續(xù)的恐嚇的話(huà),就不用在意了;但假如你要想用間斷性攻擊村民的方法,可能還是得考慮一下的。)
其中的villagerEntity.summonGolem方法的第二個(gè)參數(shù)為需要的有效村民數(shù)量,即3個(gè)。
shouldKeepRunning方法會(huì)調(diào)用里面的兩個(gè)getter來(lái)查詢(xún)村民的Brain對(duì)象中是否包含被恐嚇或受傷的記憶,即MemoryModuleType.NEAREST_HOSTILE 和 MemoryModuleType.HURT_BY。這兩個(gè)值會(huì)在對(duì)應(yīng)的sensor類(lèi)中被更新,并使用父類(lèi)Sensor的默認(rèn)sense間隔,每20tick更新一次,即每秒都更新。
這兩個(gè)方法被Task父類(lèi)中的tick方法調(diào)用,判斷shouldKeepRunning為true之后,便會(huì)調(diào)用一次keepRunning來(lái)嘗試生成鐵傀儡。(更多的代碼我沒(méi)有去看了,應(yīng)該就是每個(gè)tick都會(huì)被執(zhí)行一次?)

聊天

村民間靠互相吹牛逼()生成鐵傀儡的方法比較簡(jiǎn)單,直接寫(xiě)在了村民自己的類(lèi)里面。
在嘗試生成鐵傀儡前,游戲會(huì)判斷這兩個(gè)村民距上次聊天(嘗試生成鐵傀儡)是否已經(jīng)過(guò)了1200ticks,即60秒。這意味著這兩個(gè)村民嘴皮子說(shuō)爛也就只能一分鐘生成一次。
且通過(guò)這種方式生成鐵傀儡需要至少5個(gè)有效的村民。
到此為止兩個(gè)生成鐵傀儡的方法已經(jīng)講完了,接下來(lái)會(huì)詳細(xì)說(shuō)明鐵傀儡的生成。

村民生成鐵傀儡的條件

首先是canSummonGolem,這個(gè)方法查詢(xún)了這個(gè)村民是否具有生成鐵傀儡的基本條件:即睡過(guò)覺(jué),工作過(guò),并且在過(guò)去的30秒內(nèi)沒(méi)有看見(jiàn)過(guò)鐵傀儡。
hasRecentlyWorkedAndSlept方法查詢(xún)了村民Brain對(duì)象中上一次睡覺(jué)時(shí)間,假如睡過(guò)覺(jué),則將當(dāng)前時(shí)間和上一次睡覺(jué)的時(shí)間相減法,假如間隔小于24000ticks,即20分鐘,則返回true。也就是說(shuō)村民至少在二十分鐘內(nèi)睡過(guò)覺(jué),才具備生成鐵傀儡的條件。
hasSeenGolemRecently方法查詢(xún)了村民上一次看見(jiàn)鐵傀儡的時(shí)間,假如查詢(xún)不到,則直接返回false。如果查詢(xún)的到,判斷距離上一次看見(jiàn)鐵傀儡,是否已經(jīng)經(jīng)過(guò)了600ticks,即30秒,如過(guò)小于30秒,則true。
LastSeenTime的記憶由GolemLastSeenSensor類(lèi)更新,他每間隔200tick,即10秒查詢(xún)一次村民Brain中看見(jiàn)的周?chē)匆?jiàn)的活體的記憶(MemoryModuleType.MOBS)的列表,如果存在鐵傀儡,就刷新LastSeenTime的時(shí)間(重置冷卻時(shí)間)。
然而這并不意味著你有10秒鐘的時(shí)間來(lái)移除鐵傀儡,因?yàn)镸OBS的列表由NearestLivingEntitiesSensor更新,而這個(gè)類(lèi)繼承了Sensor類(lèi)默認(rèn)構(gòu)造的sense間隔,即每秒1次。
此外,由于NearestLivingEntitiesSensor偵測(cè)生物的范圍為:從this對(duì)象的邊框往外6個(gè)方向拓展16格。即對(duì)于村民來(lái)說(shuō),需要在33*34*33的空間內(nèi)看不見(jiàn)鐵傀儡。

生成鐵傀儡的summonGolem方法

經(jīng)過(guò)第4行,即上一部分所講的判斷后,游戲創(chuàng)建了一個(gè)以村民為中心,向6個(gè)方向拓展10格的空間??紤]到村民尺寸,這個(gè)空間應(yīng)該是21*22*21。
第6行獲取了這個(gè)空間里所有的村民,并保存到一個(gè)列表中。第7行找出了這個(gè)列表中所有具備生成鐵傀儡條件村民,即上文提到的基本條件。
接下來(lái),游戲?qū)Ρ全@取的村民數(shù)量和所需的數(shù)量,假如數(shù)量滿(mǎn)足條件,則調(diào)用spawnIronGolem方法嘗試生成鐵傀儡。假如鐵傀儡成功生成,即11行ironGolemEntity不為null,則更新這個(gè)村民上一次看見(jiàn)鐵傀儡的時(shí)間。

嘗試生成鐵傀儡:

上文講到,當(dāng)這組村民具備生成鐵傀儡的條件時(shí),會(huì)調(diào)用spawnIronGolem進(jìn)行生成嘗試。這個(gè)嘗試會(huì)進(jìn)行10次,直到成功,或者次數(shù)用完為止。
游戲獲取村民腳的位置(有點(diǎn)不太確定是腳的為止還是下面地板的為止,不過(guò)我后來(lái)看setPos的代碼的時(shí)候發(fā)現(xiàn),應(yīng)該指的是腳的位置。),并賦給blockPos對(duì)象。接下來(lái)游戲會(huì)使用Java自帶的隨機(jī)數(shù)生成器生成一個(gè)[0, 16)的隨機(jī)整數(shù),并減掉8,這就是生成鐵傀儡的x和z軸相較于村民的相對(duì)坐標(biāo),即(-8, -8)到(7, 7)的橫向范圍。
獲取到x和z值后,游戲調(diào)用getLegitSpawningPos(這個(gè)方法的名字我瞎jb取的,原來(lái)沒(méi)有命名)查找高度合法的坐標(biāo)blockPos2。假如blockPos2不為空,即找到了合法的坐標(biāo),游戲會(huì)創(chuàng)建一個(gè)鐵傀儡對(duì)象(代碼30行)。(具體過(guò)程詳見(jiàn)下一節(jié))
然后游戲會(huì)調(diào)用鐵傀儡對(duì)象的canSpawn方法(41行),先查詢(xún)blockPos2下方一格(鐵傀儡腳踩的方塊),及其即上方2格(鐵傀儡頭和胸)方塊是否符合刷新鐵傀儡的條件。具體為:
blockPos2 - 1:頂面必須Solid
blockPos2 + i(i = 1, 2):不能是實(shí)心,釋放紅石信號(hào),液體,具有阻止生物生成標(biāo)簽和能造成傷害的方塊。
也就是說(shuō),他只要求1*3的空間里沒(méi)有阻擋物。
然后,游戲判斷blockPos2是否依舊具備生成條件(和上方兩格相同的判斷方法,唯一的區(qū)別是輸入的參數(shù)里,液體屬性是被設(shè)定為Empty的。),并查看在鐵傀儡的碰撞體積內(nèi)是否有某一些奇奇怪怪的實(shí)體(他寫(xiě)了一堆do-while,看得我頭大,懶得看具體是啥了。),有的話(huà)會(huì)導(dǎo)致刷不出來(lái)。
在一切條件都滿(mǎn)足的情況下,鐵傀儡就會(huì)被成功生成。

獲取合法的生成高度

這個(gè)方法接收了剛才隨機(jī)生成的坐標(biāo)blackPos,他的高度是村民腳的那一格!
接下來(lái)游戲直接把這個(gè)高度加了6,賦值給blockPos2。這是最高一層能刷新鐵傀儡的高度,也就是鐵傀儡的腳的位置。
然后游戲循環(huán)13次,向下逐層搜索合法的高度,直到可以刷鐵傀儡為止。即從村民腳開(kāi)始的為止,往上6格,往下6格,都是可以刷新鐵傀儡的。
其中,鐵傀儡腳的位置,即blockPos2,只能為空氣或液體(巖漿也是液體,但是會(huì)在上文提到的canSpawn方法中被排除。這意味著,假如搜索到巖漿,且被認(rèn)為是合法的話(huà),鐵傀儡就會(huì)嘗試生成,而不會(huì)繼續(xù)向下搜索,導(dǎo)致本次生成失敗,即便下方有合法的生成空間。)。而鐵傀儡腳下的方塊,即blockPos,必須具有blocksLight的屬性,也就是不能為透明方塊,或者是一些雜七雜八的東西(我猜用minihud能顯示光照亮度的方塊應(yīng)該才符合條件)。
假如13層都無(wú)法生成,則本次生成失敗。

總結(jié)
空間 (這里為了方便,記村民腳的坐標(biāo)為(0,0,0))
?鐵傀儡生成空間為:(-8,-6,-8)到(7,6,7)
?偵測(cè)鐵傀儡的范圍為:(-16,-16,-16)到(16,17,16)
?一組村民的范圍為:(-10,-10,-10)到(10,11,10)
?你給鐵傀儡1*3的空間他一樣會(huì)刷,就是比較看臉。
時(shí)間
?一旦村民探測(cè)到鐵傀儡,冷卻時(shí)間重置為30秒。
?某種意義上來(lái)說(shuō),村民每秒都能偵測(cè)是否有鐵傀儡。
?村民在驚恐狀態(tài)下每5秒嘗試一次鐵傀儡生成。
?村民互相吹逼,就算瘋狂說(shuō)話(huà),也要60秒才能?chē)L試一次生成。
?村民想刷鐵傀儡,必須20分鐘內(nèi)有睡覺(jué)過(guò),即游戲內(nèi)一天。不然熬夜成仙了也不怕僵尸了(霧)。
數(shù)量
?恐嚇式刷鐵村民需要至少3只。
?普通嘮嗑法需要5只。
失敗的條件
?腳踩方塊需要有blocksLight的屬性,且上表面為Solid。
?腳的方塊只能是空氣或液體。巖漿也是,但是會(huì)和3沖突,導(dǎo)致直接失敗,即便下方還有適宜的方塊。
?腳踩的方塊往上三格,不能是實(shí)心,釋放紅石信號(hào),液體,具有阻止生物生成標(biāo)簽和能造成傷害的方塊。然而腳的那一格可以為液體。

這也不完全算是個(gè)科普,有錯(cuò)誤的話(huà)還請(qǐng)大佬指出2333
@Conn_Lost