指令最佳化(optimize)是一門大學問,許多最佳化的方式有利用演算法、利用Minecraft特性、利用官方建議等等。
小弟在此分享一部國外大神Cloud Wolf拍的影片「如何最佳化你的資料包」:
整理幾個重點:
1. 不要使用紅石
2. 使用函數(shù)樹
3. 盡量在@e內(nèi)加上type=
4. 減少nbt=
5. 使用藥水雲(yún)取代盔甲架
1. 不要使用紅石
紅石會讓你變慢,因為每一個tick,遊戲都在檢查紅石是否被觸發(fā)。反之,單單只是放一個函數(shù)檔案在資料包內(nèi),並不會影響效能。
如果你想要計時或延時功能,用計分板和/schedule指令,不要使用紅石。
2. 使用函數(shù)樹
把需要大量檢測的的指令分組,建立函數(shù)樹(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
並把原本的測試分成兩半,寫入兩個函數(shù)內(nèi)。
假設(shè)foo在bar上的分數(shù)是8,原先的寫法不論如何都要檢查10次,但新的寫法只要檢查一次1..5,然後function test:1_to_5就會被跳過,接著測試6..10通過,進入function test:6_to_10,檢查6、7、8、9、10,總共7次即可。
3. 盡量在@e內(nèi)加上type=
不要直接打@e[tag=xxx]或@e[scores={xxx=x..}]去指定實體,而是盡可能地加上type,這樣遊戲才不用走訪(traverse)所有實體去檢查是否條件通過,而是只需要走訪指定的實體即可。
4. 減少nbt=
NBT標籤的檢測非常耗效能,能避免則避免,或是使用進度(advancement)、述詞(predicate)等方式代替。
例如像檢測玩家的主手是否拿著鑽石劍,傳統(tǒng)方法@a[nbt={SelectedItem:{id:"minecraft:diamond_sword"}}],就是NBT檢測。
若是改用述詞就能夠降低消耗,不過也要注意,要使用到述詞提供的功能,而不是用述詞套NBT檢測,那樣不會省到。
以下是檢測主手拿著鑽石劍的述詞:
有關(guān)進度和述詞的wiki:
Mojang工程師Bartosz Bok,在述詞發(fā)布的那天對其表示:
5. 使用藥水雲(yún)取代盔甲架
由於影片拍攝的時間是2020年3月,所以沒有提到。不過從2021年4月的1.17快照21w15a開始,我們有更好的「標記(marker)」可以使用。
根據(jù)Minecraft wiki,標記擁有以下特性:
不過藥水雲(yún)依然是很有用的實體,例如顯示懸浮文字時,而且1.16和之前的資料包也需要使用到藥水雲(yún)。
早在1.9時代就有人比較過藥水雲(yún)和盔甲架(Stands vs Clouds),藥水雲(yún)沒有材質(zhì),省去遊戲算圖(render)的時間。同時它天生隱形,碰撞箱極小,因此取代盔甲架不成問題。
現(xiàn)今需要使用到盔甲架的場合,只剩下裝備欄,或是在標記出現(xiàn)之前儲存虛擬NBT。
以上就是Cloud Wolf在影片中提到的如何最佳化資料包。而我個人也有部分心得:
1. 使用UUID取代@e指定
2. 指定時加上limit=1
3. 使用假玩家儲存分數(shù)
4. 使用進度取代計分板
礙於篇幅因素,下次有機會再發(fā)文詳解:【心得】如何最佳化地圖效能(下)。
謝謝大家。