最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

深度剖析Minecraft #2 方塊更新

2020-02-04 11:53 作者:Fallen_Breath  | 我要投稿

2. 方塊更新

感謝?遲昫123?與?qwrrdshfsghv?的捉蟲

2.1 方塊更新性質(zhì)

2.1.1 方塊更新的種類

1.13 之后,方塊更新分為了兩種類型,分別是?NeighborChanged?與?PostPlacement,簡稱 NC 與 PP 更新。若要與 1.13 之前相比,可將 1.13 之前的所有方塊更新都視為 NC 更新

這兩種方塊更新的類型在官方的反混淆表(來自 1.14.4)中的名稱分別為 neighborChanged 與 updateShape,其命名也能有助于理解上述對兩類方塊更新具體含義

2.1.1.1 NeighborChanged

NeighborChanged 更新,指的是最基礎(chǔ)的,最符合“方塊更新”一次含義的更新。紅石元件的狀態(tài)變化、方塊的放置與破壞、方塊開始移動以及方塊到位都可以產(chǎn)生 NC 更新。除此之外,各種雜七雜八地方塊變化大多也都能產(chǎn)生 NC 更新

游戲里能產(chǎn)生 NC 更新的事件太多了,不便于一一列舉。不過能響應(yīng) NC 更新的卻不算多。所有能響應(yīng) NC 更新的事件有:

  • 活板門、柵欄門、木門、鐵門更新開關(guān)狀態(tài)

  • 霜冰檢測融化

  • 活塞檢測移動

  • 活塞頭給予活塞底座 NC 更新

  • 紅石粉、中繼器、比較器、紅石火把、各類鐵軌、命令方塊、投擲器、發(fā)射器、音符盒、紅石燈、TNT更新狀態(tài)

  • 水、巖漿檢測狀態(tài)

  • 靈魂沙、巖漿塊添加生成氣泡柱的 TT 事件

  • 海綿嘗試吸水

NC更新方塊

對,就這些。不過,根據(jù)日常經(jīng)驗來看,有不少需要方塊更新的事件卻不在這。不要著急,他們在 PostPlacement 更新中

有此可見,各類紅石元件處于 bud 態(tài)時,如無信號源的伸出活塞,不點燃的 TNT 等,需要的是 NC 更新,才能讓它們意識到狀態(tài)改變而恢復(fù)到正常的狀態(tài)

2.1.1.2 PostPlacement

PostPlacement,指的是方塊發(fā)生變化后導(dǎo)致的臨近方塊與之交互情況發(fā)生變化的更新。

所有能響應(yīng) PP 更新的事件有:

  • 各類依附性方塊(火把、雪片地毯蛋糕、各類花草作物、拉桿按鈕、木門鐵門、火焰等)判斷依附的方塊是否合法并決定是否掉落

  • 連接型方塊(柵欄石墻玻璃板、樓梯、箱子、紅石粉絆線、地獄門、高草紫頌植物等)更新當(dāng)前與相鄰方塊連接狀態(tài)

  • 中繼器更新被鎖狀態(tài)

  • 音符盒更新樂器類型

  • 樹葉更新離木距離

  • 混凝土粉末判定是否凝固

  • 水源與可含水的方塊添加更新流體狀態(tài)的 TT 事件

  • 偵測器添加發(fā)出信號的 TT 事件

  • 重力方塊添加檢測掉落的 TT 事件

  • 草徑、耕地添加檢測是否被壓的 TT 事件

  • 仙人掌添加狀態(tài)是否合法的 TT 事件

  • 活珊瑚添加檢測是否離水的 TT 事件

PP更新方塊

有一點值得注意,調(diào)用 PP 更新時是帶有一個方向參數(shù)的,也就是 PP 更新是有著方向區(qū)別的,方向不對的 PP 更新在某些代碼中存在特判情況下并不能影響方塊的狀態(tài)。比如,對于一個依附于西面方塊上的浮空火把,從東南北上下放置破壞方塊觸發(fā) PP 更新是無法讓它掉落的。這一點也是 1.13+ 與 1.12- 的一個重要的區(qū)別。

2.2 方塊更新的實現(xiàn)

先把會出現(xiàn)的名詞列一遍:

  • 一個位置的方塊(以下簡稱方塊)受到了 NC 更新

  • 一個方塊發(fā)出了 NC 更新

  • 一個方塊發(fā)出了除?<方向>?外的 NC 更新

  • 一個方塊受到了 PP 更新

  • 一個方塊發(fā)出了 PP 更新

注1:<方向>?為???西????中的任意一者

注2:一個方塊發(fā)出方塊更新,也就是一個方塊于其所在位置發(fā)出方塊更新,或者說是一個位置發(fā)出了方塊更新,由于指的都是一種事件并無歧義,都是可行的表述,可視上下文語境挑選合適者

2.2.1 一個方塊受到了 NC 更新

一個方塊受到了 NC 更新,將會調(diào)用位于這個方塊的?neighborChanged?方法,并處理受到更新后的改變(見2.1.1.1 NeighborChanged)

具體代碼見下 World 類中的?neighborChanged?方法

2.2.2 一個方塊發(fā)出了 NC 更新

六毗鄰方塊

當(dāng)一個方塊發(fā)出 NC 更新時,這個方塊將會使其毗鄰的六個方塊依次受到 NC 更新。這里的“依次受到”的順序為:

  1. 西 -x

  2. 東 +x

  3. 下 -y

  4. 上 +y

  5. 北 -z

  6. 南 +z

具體代碼見下 World 類中的?notifyNeighborsOfStateChange

2.2.3 一個方塊發(fā)出了除 <方向> 外的 NC 更新

注:<方向>?為???西????中的任意一者

一個方塊發(fā)出了除?<方向>?外的 NC 更新的表現(xiàn),與上 2.2.2 并無太大區(qū)別區(qū)別僅為這次發(fā)出的 NC 更新將會跳過指定的一個方向,也就是只更新 5 個毗鄰的方塊

這種特殊的方塊更新于中繼器/比較器/偵測器在其指向方塊發(fā)出更新時使用

五毗鄰方塊

具體代碼見下 World 類中的?notifyNeighborsOfStateExcept?方法

2.2.4 一個方塊受到了 PP 更新

一個方塊受到了 PP 更新,將會調(diào)用位于這個方塊的?updatePostPlacement?方法,并處理受到更新后的改變(見2.1.1.2 PostPlacement)

具體代碼見下 IBlockState 類中的?updatePostPlacement?方法

2.2.5 一個方塊發(fā)出了 PP 更新

六毗鄰方塊

當(dāng)一個方塊發(fā)出 PP 更新時,這個方塊將會使其毗鄰的六個方塊依次受到 PP 更新。這里的“依次受到”的順序為:

  1. 西 -x

  2. 東 +x

  3. 北 -z

  4. 南 +z

  5. 下 -y

  6. 上 +y

可以發(fā)現(xiàn),PP 更新的更新順序是 xzy 而非 NC 更新的 xyz。這一點是值得注意的

具體代碼見下 Block 類中的?updateNeighbors?方法

2.3 瞎扯

NC 與 PP 更新這兩種更新概念非常類似容易混淆,我個人覺得可以這樣理解:

  • NC 是紅石元件等功能性方塊的狀態(tài)的更新

  • PP 是因與周圍方塊交互,導(dǎo)致一個方塊狀態(tài)改變的更新

因為 NC 更新的大部分是屬于紅石元件的相應(yīng),而 PP 更新更偏向于相鄰方塊狀態(tài)變化造成的響應(yīng)。不過得具體情況具體分析不能一概而論。

可以發(fā)現(xiàn)上述部分我描述方塊更新的具體例子時都是列舉響應(yīng)方塊更新的實例,沒有列舉產(chǎn)生方塊更新的事件。這是因為 MC 里能產(chǎn)生方塊更新的地方實在是太多了。

1.13 把方塊更新拆成兩類的做法有些魔幻,不知道麻將是想優(yōu)化游戲還是只是想亂改改賭一賭能不能修掉 TNT 復(fù)制。不過至少對于絕大部分電路中利用到方塊更新的部分是沒有影響的

麻將代碼中還有些很迷惑的地方,比如同樣是氣泡柱產(chǎn)生源,除了放下方塊時均會添加嘗試生成氣泡的 TT 事件外,靈魂沙只在受到 NC 更新時添加 TT 事件,而巖漿塊只在受到上方的來自水的 PP 更新時添加 TT 事件

2.4 方塊變化的實現(xiàn)

MC 里絕大部分對世界中方塊的修改是通過?World?類的?setBlockState?[setBlockState]?來實現(xiàn)的。以將位置 Pos 的方塊從 A 修改至 B 的流程如下:

[setBlockState]: net/minecraft/world/World.java:226

  1. 運算方塊變化導(dǎo)致區(qū)段信息的改變

  2. 更新 Heightmap

  3. 調(diào)用 A 的?onReplaced?方法

  4. 更新天空光

  5. 調(diào)用 B 的?onBlockAdded?方法

  6. 更新可能的新的方塊實體

  7. 更新方塊光

  8. 位于 Pos 的方塊發(fā)出一次 NC 更新

  9. 若 B 能被比較器響應(yīng)則更新附近的比較器

  10. 位于 Pos 的方塊發(fā)出一次 PP 更新

其中 8.、9.、10. 在不同類型中的方塊變化里是可選跳過的,具體實現(xiàn)是游戲在調(diào)用?setBlockState?的時候會傳遞一個?flags參數(shù),通過設(shè)置?flags?不同二進(jìn)制位中的 0/1 來實現(xiàn)對修改完方塊后觸發(fā)各種方式各種類型方塊更新的控制,也就是說?setBlockState?會產(chǎn)生的方塊更新的種類與方式有著非常多種可能,因此一一列舉是不太現(xiàn)實的。不過,經(jīng)驗告訴我們:

  • 方塊的人工放置與破壞、音符盒與活塞的動作會先后產(chǎn)生 NC 與 PP 更新

  • 各種方塊狀態(tài)的改變?nèi)玳T的開關(guān)、柵欄的連接、中繼器的激活會在其所在位置產(chǎn)生 PP 更新

  • 可強(qiáng)充能的紅石信號源元件能產(chǎn)生大范圍的 NC 更新

  • 等等

2.5 方塊更新檢測器 / 發(fā)生器

一個被 QC 激活的 bud 態(tài)活塞,即為一個 NC 更新檢測器,這也是最常用的 NC 更新檢測器。當(dāng)活塞底座受到 NC 更新時,活塞將在下一個 BE 階段開始伸縮一次

bud活塞

能響應(yīng) PP 更新并能多次使用的方塊寥寥無幾,做常用的就是偵測器了。當(dāng)偵測器臉朝著的方塊發(fā)出一個 PP 更新時,偵測器將會立即添加一個 TT 事件并在對應(yīng)的 TT 階段輸出脈沖,因此偵測器是一個很棒的 PP 更新檢測器。圖里則是偵測器檢測柵欄門開關(guān)的一個例子

偵測器

上面就是兩種十分常用的方塊更新檢測器,當(dāng)然能檢測 NC 或 PP 更新的方式還有很多,這里就不一一敘述了。

至于方塊更新發(fā)生器,能同時發(fā)出 NC + PP 更新的事件有很多,如方塊的放置、音符盒的點擊。他們都能同時使 NC 更新檢測器與 PP 更新檢測器響應(yīng)

放置方塊

如果要只發(fā)出 NC 更新,可以使用紅石元件,如中繼器。中繼器在調(diào)節(jié)檔位時會在其指向的方塊的位置發(fā)出一個 NC 更新

中繼器更新

還有一種可行的方法是打開箱子。對于一個箱子,當(dāng)玩家打開它時它會發(fā)出一個 NC 更新

打開箱子

如果僅需發(fā)出 PP 更新,常用的方法則是開關(guān)柵欄門/活板門。當(dāng)柵欄門/活板門開關(guān)時,它們僅會發(fā)出一個 PP 更新而無 NC 更新

打開柵欄門

2.6 即時更新元件

即時更新元件,指的是那些收到方塊更新后立即在當(dāng)前階段改變其狀態(tài),并發(fā)出指定類型的更新(可能沒有)的元件。它們被廣泛地用于信號傳遞以及方塊更新的傳導(dǎo)

2.6.1 充能 / 激活鐵軌

當(dāng)充能 / 激活鐵軌(以下以充能鐵軌為例)受到 NC 更新時,它會先檢測當(dāng)前位置是否合法。若不合法,則掉落,否則執(zhí)行鐵軌的更新

在鐵軌的更新中,首先鐵軌會通過計算臨近鐵軌狀態(tài)來判斷當(dāng)前的狀態(tài)是否需要改變,具體怎么判斷的這里就不多解釋了。如果需要更新,鐵軌會依次執(zhí)行位于 BlockRailPowered 類的?updateState?方法中的以下內(nèi)容:

 ? ?worldIn.setBlockState(pos, state.with(POWERED, Boolean.valueOf(flag1)), 3);
? ?worldIn.notifyNeighborsOfStateChange(pos.down(), this);

? ?if (state.get(SHAPE).isAscending())
? ?{
? ? ? ?worldIn.notifyNeighborsOfStateChange(pos.up(), this);
? ?}


也就是:

  1. 改變方塊狀態(tài),在鐵軌處依次發(fā)出 NC 與 PP 更新

  2. 在鐵軌下方一格發(fā)出 NC 更新

  3. 若鐵軌是傾斜放置的,則在鐵軌上方一格發(fā)出 NC 更新

不過,注意到,充能鐵軌的?onReplaced?方法本身也有進(jìn)行方塊更新。對于充能鐵軌而言,onReplaced?方法將依次執(zhí)行:

  1. 若鐵軌是傾斜放置的,則在鐵軌上方一格發(fā)出 NC 更新

  2. 在鐵軌自身位置發(fā)出 NC 更新

  3. 在鐵軌下方一格發(fā)出 NC 更新

因此,合并起來,在充能鐵軌狀態(tài)改變時,將會依次執(zhí)行這些方塊更新:

  1. 若鐵軌是傾斜放置的,則在鐵軌上方一格發(fā)出 NC 更新

  2. 在鐵軌自身位置發(fā)出 NC 更新

  3. 在鐵軌下方一格發(fā)出 NC 更新

  4. 在鐵軌自身位置發(fā)出 NC 更新

  5. 在鐵軌自身位置發(fā)出 PP 更新

  6. 在鐵軌下方一格發(fā)出 NC 更新

  7. 若鐵軌是傾斜放置的,則在鐵軌上方一格發(fā)出 NC 更新

別問我為什么要這么繁瑣地更新,要問就問麻將

2.6.2 紅石粉

紅石粉方塊幾乎僅對 NC 更新進(jìn)行響應(yīng),即使是判斷自身位置是否合法也是通過 NC 更新進(jìn)行的。對于 PP 更新,紅石粉接受上方和四周的 PP 更新用來更新與相鄰紅石粉的被實體方塊壓線/連接狀態(tài)

當(dāng)紅石粉受到 NC 更新時,它會計算不考慮自己時它能達(dá)到的信號強(qiáng)度,如果不同,則進(jìn)行更新。紅石粉將會在其位置發(fā)出 NC 更新,并在于其毗鄰的 6 個方塊的位置上發(fā)出 NC 更新,總共有 7 個位置將會發(fā)出 NC 更新。這七個位置的更新順序并不是固定的,游戲會將這 7 個位置存入一個哈希表并導(dǎo)出成列表,隨后逐個讀取列表里的位置進(jìn)行發(fā)出 NC 更新。至于為什么要用哈希表打亂,問麻將去ˉ_(ツ)_/ˉ

2.6.3 活板/柵欄/木門、漏斗

各類活板門、柵欄門、木門鐵門,以及漏斗的機(jī)制,算是比較簡單的。它們在由于玩家操作或者紅石信號導(dǎo)致開關(guān)狀態(tài)的改變時,會在所在位置立即觸發(fā)一個 PP 更新,僅此而已。因此,它們并不能用來更新 bud 態(tài)的元件

2.6.4 音符盒

音符盒與各類門很相似,但卻有不少不同。

  • 音符盒在被玩家右鍵調(diào)音時,或者在被紅石信號激活/取消激活時,會立即在所在的位置先后觸發(fā) NC 與 PP 更新。這也是音符盒可以用于更新 bud 態(tài)的元件的原因

  • 音符盒在被玩家左鍵發(fā)音時,不會觸發(fā)方塊更新

音符盒進(jìn)行上述三類操作(調(diào)音 / 發(fā)音 / 激活)后,會在可以發(fā)音時,即上方是空氣方塊時,計劃一個 BlockEvent ,并在 BE 階段發(fā)出對應(yīng)的聲音并生成音符粒子

2.6.5 依附性方塊

絕大部分依附性方塊,如火把、花草、紅石粉、耕地上的作物,在受到來自其附著方塊位置的 PP 或 NC 更新時,都會立即破壞并依據(jù)情況掉落。因此它們也可稱為即時更新的元件

之所以說是絕大部分,是因為存在某些如紫頌花、仙人掌等的依附性方塊是在 TileTick 階段進(jìn)行掉落的,這也給強(qiáng)制催熟的可能性打下了基礎(chǔ)

2.6.6 半即時更新元件

這類元件僅在激活/觸發(fā)時為即時更新,但在取消激活時是在 TileTick 階段進(jìn)行運算的。它們有:

  • 按鈕

  • 壓力板

  • 絆線

  • 絆線鉤

  • 紅石燈

2.7 更新抑制

一個方塊發(fā)出方塊的更新可以導(dǎo)致了另一個方塊的更新,如果此時另一個方塊也發(fā)出了方塊更新,那么說不定可以再更新一個新的方塊。如果有無限的方塊排一排等著更新,如果給一它們一個方塊更新,它們能一口氣全部更新完嗎?雖然實際上應(yīng)該是可以的,但是基于 MC 的實現(xiàn)機(jī)制,答案是:不行

大面積的bud鐵軌

在處理方塊更新時,游戲內(nèi)是簡單地通過遞歸處理的,而最大的遞歸次數(shù),是由 java 虛擬機(jī)的??臻g所決定的。??臻g不像堆空間,在默認(rèn)條件下容量不大,這導(dǎo)致了當(dāng)出現(xiàn)遞歸更新過量方塊時??臻g將會耗盡,導(dǎo)致 java 拋出了棧溢出的異常(實際上棧溢出后可能拋出的是其他類型的異常,這里為了方便表述稱其為棧溢出異常)

異??墒莻€很危險的東西。出現(xiàn)異常時,程序?qū)恢焙雎灾蟮牟僮鳎恢蓖馓?,直到異常被捕獲。在大部分 MC 流程中,異常將會在最底層的 MinecraftServer 類的?run?方法中被捕獲,隨后游戲?qū)⑸杀罎蟾娌?qiáng)行關(guān)閉服務(wù)器,也就是崩服,服務(wù)器崩潰了

不過,如果一個異常是在玩家操作階段被玩家的動作觸發(fā),則這個異常將會在 Util 類的?runTask?方法中被捕獲并作為一個 Fatal 輸出,而非被 MinecraftServer 捕獲,也就是說玩家動作引發(fā)的異常是不會引起服務(wù)端崩潰的。作為異常之一的棧溢出,如果是由玩家操作引起的,比如玩家打掉了一個接連插了幾千個旗子的方塊,或者玩家在大面積的 bud 態(tài)充能鐵軌旁邊放置了方塊,雖會導(dǎo)致棧溢出,但都不會導(dǎo)致游戲崩潰

手放方塊

由于棧溢出可以跳過在異常捕獲前的所有運算,因此可以用此來跳過一些運算以實現(xiàn)普通游戲里不可能的操作,如跳過對特定方塊的更新,從而制造各種懸空木門、貼在告示牌背面的告示牌、切片的地獄門;也可以跳過對玩家物品欄物品的操作,在不消耗工具耐久或者不消耗手中物品的情況下破壞/放置方塊。這一類操作,我們統(tǒng)稱為為更新抑制

更新抑制

關(guān)于更新抑制與可協(xié)助產(chǎn)生更新抑制的更新抑制器,Xcom6000 制作過一個非常詳細(xì)的講解視頻,紅石科技搬運組已在 bilibili 將其翻譯成熟肉。推薦大家去觀看學(xué)習(xí)。傳送門

2.7.1 方塊更新與深度優(yōu)先搜索

方塊受到更新,方塊改變狀態(tài),方塊發(fā)出更新,依次更新毗鄰方塊,新方塊受到更新……這一層層遞歸的過程,本質(zhì)上正是一個深度優(yōu)先搜索,也就是 DFS(Depth First Search)。每當(dāng)一個 bud 充能鐵軌受到更新了,將會按照其發(fā)出 NC 更新的順序,以及 NC 更新的更新順序,往新的 bud 鐵軌方塊遞歸下去

關(guān)于深度優(yōu)先搜索,或者 DFS,網(wǎng)絡(luò)上相關(guān)的資料一搜一大把,這里就不再重復(fù)闡述了

使用更新抑制來阻斷方塊更新的一個難點,即是如何控制更新順序,使方塊更新在傳遞至需阻止更新的方塊前就進(jìn)入更新抑制器觸發(fā)棧溢出?,F(xiàn)在,方塊更新傳遞的機(jī)制我們已探明(DFS),方塊更新順序我們也已清楚(2.2.2、2.2.5 中 NC / PP更新的更新順序),只要了解清楚 DFS 的機(jī)制確定好更新順序方向,就可以輕松的計算出來了


深度剖析Minecraft #2 方塊更新的評論 (共 條)

分享到微博請遵守國家法律
临桂县| 台中县| 济源市| 宜昌市| 太保市| 阿城市| 烟台市| 古田县| 泉州市| 微山县| 夏津县| 临朐县| 肥东县| 长泰县| 沂南县| 育儿| 于田县| 板桥市| 宽城| 巧家县| 合川市| 襄城县| 淮安市| 红桥区| 山东| 余庆县| 永吉县| 运城市| 霍山县| 新宾| 汉阴县| 南乐县| 郧西县| 丽水市| 阳西县| 保定市| 金昌市| 伊宁县| 灵台县| 嘉祥县| 乌鲁木齐市|