前往
大廳
主題

【心得】如何最佳化地圖效能(上)

AlexCai | 2022-01-19 21:32:04 | 巴幣 2 | 人氣 480

指令最佳化(optimize)是一門大學問,許多最佳化的方式有利用演算法、利用Minecraft特性、利用官方建議等等。
小弟在此分享一部國外大神Cloud Wolf拍的影片「如何最佳化你的資料包」:
整理幾個重點:
1. 不要使用紅石
2. 使用函數樹
3. 盡量在@e內加上type=
4. 減少nbt=
5. 使用藥水雲取代盔甲架

1. 不要使用紅石
紅石會讓你變慢,因為每一個tick,遊戲都在檢查紅石是否被觸發。反之,單單只是放一個函數檔案在資料包內,並不會影響效能。
如果你想要計時或延時功能,用計分板和/schedule指令,不要使用紅石。

2. 使用函數樹
把需要大量檢測的的指令分組,建立函數樹(function tree),這樣才不用每次需要檢查時都從頭檢查一遍。
舉例,原先的指令長這樣:
execute if score foo bar matches 1 run ...
execute if score foo bar matches 2 run ...
execute if score foo bar matches 3 run ...
...
execute if score foo bar matches 9 run ...
execute if score foo bar matches 10 run ...
這些指令可以被縮減為
execute if score foo bar matches 1..5 run function test:1_to_5
execute if score foo bar matches 6..10 run function test:6_to_10
並把原本的測試分成兩半,寫入兩個函數內。
假設foo在bar上的分數是8,原先的寫法不論如何都要檢查10次,但新的寫法只要檢查一次1..5,然後function test:1_to_5就會被跳過,接著測試6..10通過,進入function test:6_to_10,檢查6、7、8、9、10,總共7次即可。

3. 盡量在@e內加上type=
不要直接打@e[tag=xxx]或@e[scores={xxx=x..}]去指定實體,而是盡可能地加上type,這樣遊戲才不用走訪(traverse)所有實體去檢查是否條件通過,而是只需要走訪指定的實體即可。

4. 減少nbt=
NBT標籤的檢測非常耗效能,能避免則避免,或是使用進度(advancement)、述詞(predicate)等方式代替。
例如像檢測玩家的主手是否拿著鑽石劍,傳統方法@a[nbt={SelectedItem:{id:"minecraft:diamond_sword"}}],就是NBT檢測。
若是改用述詞就能夠降低消耗,不過也要注意,要使用到述詞提供的功能,而不是用述詞套NBT檢測,那樣不會省到。
以下是檢測主手拿著鑽石劍的述詞:
有關進度和述詞的wiki:
Mojang工程師Bartosz Bok,在述詞發布的那天對其表示:

5. 使用藥水雲取代盔甲架
由於影片拍攝的時間是2020年3月,所以沒有提到。不過從2021年4月的1.17快照21w15a開始,我們有更好的「標記(marker)」可以使用。
根據Minecraft wiki,標記擁有以下特性:
不過藥水雲依然是很有用的實體,例如顯示懸浮文字時,而且1.16和之前的資料包也需要使用到藥水雲。
早在1.9時代就有人比較過藥水雲和盔甲架(Stands vs Clouds),藥水雲沒有材質,省去遊戲算圖(render)的時間。同時它天生隱形,碰撞箱極小,因此取代盔甲架不成問題。
現今需要使用到盔甲架的場合,只剩下裝備欄,或是在標記出現之前儲存虛擬NBT。

以上就是Cloud Wolf在影片中提到的如何最佳化資料包。而我個人也有部分心得:
1. 使用UUID取代@e指定
2. 指定時加上limit=1
3. 使用假玩家儲存分數
4. 使用進度取代計分板

礙於篇幅因素,下次有機會再發文詳解:【心得】如何最佳化地圖效能(下)
謝謝大家。

創作回應

更多創作