前往
大廳
主題

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

AlexCai | 2022-04-03 21:06:08 | 巴幣 0 | 人氣 221

自Minecraft發行以來,玩家和開發人員與效能之間的愛恨情仇從未停止,諸如Optifine等最佳化模組如雨後春筍般冒出,1.15更被官方定位為修復錯誤和改善效能的更新。本文將接續上一篇介紹Cloud Wolf「如何最佳化你的資料包」影片的文章,繼續介紹我個人撰寫並最佳化資料包時的部分心得。

1. 使用UUID取代@e指定
2. 指定時加上limit=1
3. 使用假玩家儲存分數
4. 使用進度取代計分板

以下一一說明:
1. 使用UUID取代@e指定
每一個實體都會對應到一個通用唯一辨識碼(Universally Unique Identifier),縮寫為UUID,像我自己的UUID就是59c1027b-5559-4e6a-91e4-2b8b949656ce。這不是什麼秘密,namemc.com上都能找到。
Minecraft會將遊戲內的所有實體建立雜湊表(hash map),並由UUID作為關鍵(key)。每當一個@e被執行,實際上都在走訪(traverse)整張表,確認實體是否符合@e內的條件。
然而,若是使用UUID指定實體,等於直接指定雜湊表的關鍵,整體執行效率會快非常多。
舉例,假設事先在某處召喚了一個標記後,要在該標記的位置放置一塊石頭,利用目標選擇器的寫法就是:
summon marker ~ ~ ~ {Tags:["place_stone"]}
execute at @e[type=marker,tag=place_stone] run setblock ~ ~ ~ stone
然而,這樣的寫法卻會走訪世界上的所有標記,確認其帶有place_stone的tag後,再放置石頭。
(事實上這樣的寫法可以加上limit=1最佳化,不過這部分等到第2點再提。)
如果改用UUID,那麼指令將變為:
summon marker ~ ~ ~ {UUID:[I;0,0,0,0]}
execute at 00000000-0000-0000-0000-000000000000 run setblock ~ ~ ~ stone
等於直接指定該實體,而不用經過tag的檢測。
UUID的寫法非常簡單,{UUID:[I; <整數1>, <整數2>, <整數3>, <整數4>]},其中每個整數在經過10進位轉16進位後,依序對應了UUID字串中的8個字,例如{UUID:[I; 2, 8, 15, 24]},產生出的實體將會是:00000002-0000-0008-0000-000f00000018
另外要注意,如果對象是玩家,那麼在一些指令(scoreboard、tag等)上,ID和UUID的結果將會不同,這時推薦使用execute as UUID run scoreboard players set @s ...,這樣就和使用ID一樣了。
資料來源:Reddit

2. 指定時加上limit=1
剛才說到,如果不使用UUID指定,則遊戲將會走訪所有的實體確認資料,那麼有沒有辦法減少走訪的長度?
答案是有的,那就是在目標選擇器條件內加上limit=1,例如像@e[type=marker,tag=place_stone,limit=1],這樣一來,一旦遊戲走訪到一個實體,就會停止走訪。這個技巧其中一個非常實用的場合,就是使用execute if entity確認是否存在某個特定實體。

3. 使用假玩家儲存分數
如果可以使用假玩家儲存分數,就不要使用實體。
一來,若要在同一個計分板上紀錄大量分數,那麼勢必要召喚大量實體,即使是標記,也在一點一滴地增加遊戲的負荷。
二來,如果大量的計分板皆使用同一個實體進行計分,則容易發生混亂,也有可能衝突。
最後,使用實體就有機會需要進行走訪,那又回到了在目標選擇器條件上最佳化的問題。

4. 使用進度取代計分板
如果可以使用進度(advancement)偵測玩家的行為,那麼就不要使用計分板。使用計分板的壞處是需要額外寫指令偵測玩家的分數變動,並且每一個條件都需要一個目標偵測。
例如偵測玩家吃下蘋果、麵包或胡蘿蔔,若是使用計分板就必須創建三個目標,並撰寫三行指令偵測其中一個達成,最後重置所有分數。
事先創立:

連閃偵測:

執行函數:

非常地不方便。
幸好,進度有提供consume_item,讓使用者不需使用三個偵測、三個重置,而可以用一個偵測、一個重置達成:

而在函數內,只需簡單的使用advancement revoke即可重置:

進度沒有root、沒有parent、甚至沒有display都是有效的,是可以正常執行的。我個人的習慣是在資料包的advancements資料夾內再開一個commands資料夾,以和其他會顯示給玩家看的自定義進度區隔。
有關進度:Wiki
進度生成器:Misode advancement generator

以上,終於把下篇打完啦。最近因為在忙專題的關係都沒有時間打完這篇文章,讓大家久等了。
我個人覺得寫資料包不能不做最佳化,尤其是官方已經有提供一些很好用的工具,例如標記、述詞等。在更新越來越多、Minecraft內容越來越龐大的情況下,地圖和資料包創作者能做的就是盡量最佳化地圖或資料包的效能。
最後呢,由於聖誕節快要到了,因此放上一張聖誕惠惠鎮樓,也預祝各位新年快樂。
謝謝大家。

創作回應

相關創作

更多創作