指令最佳化(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. 使用進度取代計分板
礙於篇幅因素,下次有機會再發文詳解。
謝謝大家。