本期我們將繼續講解Minecraft Forge Mod的開發,重點是Forge的配置文件。最後我們會補充上期教程中漏掉的Capability的一個關鍵點。
在此之前,有人詢問事件註冊為何沒有生效。你可以參考這張圖,左邊是事件註冊的方法,右邊是對應的寫法。如果你使用了@SubscribeEvent這樣的方法,就需要將註冊的方法定義為static void。另外,如果通過@Mod.EventBusSubscriber註冊事件,在Register內填入實例或方法引用時,註冊的方法就不能是static。
接著我們來講Forge的配置文件。首先新建一個名為CONFIG的包,然後創建一個Java類,例如命名為CommonConfig。在這個類中,首先要定義一個公共的構建工具,比如private static ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();,然後考慮要定義哪些變量。假設之前我們寫的是固定數值,每次升級增加或扣除一個經驗點,而我們想要自定義這個數值,可以聲明一個整數類型的經驗值變量,類似:
private static ForgeConfigSpec.IntValue xpIncrease = builder.comment("Experience points increase").defineInRange("xpIncrease", 1, 0, Integer.MAX_VALUE);。
我們也想要自定義扣除多少經驗,所以可以聲明一個xpDecrease變量,使用
下列代碼來定義扣除的經驗值範圍。
builder.defineInRange("xpDecrease", 1, 0, Integer.MAX_VALUE);
接下來,我們需要定義一個列表。在這個列表中,我們不希望固定規則對所有方塊應用相同的經驗值操作,而是希望能夠自由地決定哪些方塊增加經驗值,哪些方塊減少經驗值。為此,我們需要定義一個列表變量:
private static ForgeConfigSpec.ConfigValue<List<? extends Block>> blocksGetXp = builder.comment("Blocks that give experience points").defineList("blocksGetXp", Collections.singletonList(Blocks.CARROTS), obj -> ForgeRegistries.BLOCKS.containsKey((ResourceLocation)obj.toString()), "Validation method for block entries");
在這裡,我們首先將對象轉換為Stream,然後將其作為字符串驗證是否存在這個方塊。我們需要編寫一個驗證方法:
private static boolean allow(Object obj) { return ForgeRegistries.BLOCKS.containsKey(new ResourceLocation(obj.toString())); }
最後,將該驗證方法傳遞給defineList方法即可。
此外,如果忘記了方塊的ID,可以在原版註冊鏈中查找。例如,"canvas potatoes" 應為 "carved pumpkins"。
最後我們只需構建這個配置即可,使用public static ForgeConfigSpec spec = builder.build(); 完成構建,這樣就創建好了。
另外有一個關鍵步驟是將這個配置註冊到我們的Mod中。在構造函數中,可以通過modLoadingContext.get().registerConfig來實現。第一個參數是類型,有三種類型:CLINET、COMMON和SERVER。CLINET和COMMON會在客戶端和服務器端都生效,而SERVER則會在創建的存檔中有一個專門的配置文件。通常我們可以先使用COMMON類型,第二個參數就是之前創建的配置spec 對象,如CommonConfig.builder.
註冊完成後,我們需要處理這些參數。可以先將獲取到的列表轉換成塊對象以便後續處理。例如,聲明一個私有靜態方法getConfig(),在其中定義一些變量,如public static int xpIncrease; public static int xpDecrease;,然後轉換這兩個列表為 Set 類型。由於這些配置在整個遊戲中都是唯一的並且不會改變,因此可以將它們設置為靜態變量。
接下來我們使用一個 Map 對象,可以讓我們對這些內容進行自定義轉換。首先是將方塊名稱轉換為對應的方塊對象,在getBlockName方法中,我們使用ForgeRegistries.BLOCKS.getValue(new ResourceLocation(blockName))來獲取方塊對象,最後將其轉換為 Set 並存儲在blockSet中。
接著在getConfig方法中執行get操作,用於初始化配置內容。我們可以在適當的時機觸發這些操作,比如在事件總線上監聽特定事件。例如,可以在客戶端完全加載後執行onSetup方法,通過監聽FMLClientSetupEvent事件,調用getConfig()方法。另外,也可以在重新加載配置時觸發處理,通過監聽ModConfigEvent.Reloading事件,並再次調用getConfig()。
然後,我們需要根據配置來應用經驗值的增加和減少。可以通過CommonConfig.xpDecrease和CommonConfig.xpIncrease來獲取對應的數值。修改判斷條件,將名字改為useXp,並檢查方塊列表中是否包含當前方塊,以決定是否使用經驗。
進一步完善,考慮到不希望在作物已成熟時使用骨粉扣除經驗,我們可以添加額外的判斷條件。如果方塊是可生長的方塊並且目標方塊不是泥土方塊或海綿方塊,同時目標方塊是有效的目標方塊,我們就可以從事件中獲取級別和位置等信息,並將其傳入判斷方法中。如果條件滿足,則將相關操作應用在對應的方塊上。
對於漲經驗的操作,同樣可以按照類似的邏輯進行處理。我們可以仿照扣除經驗的部分,根據配置漲經驗的數值並更新對應的方塊。
只需調整一些地方,主要是關於blockState的處理。在判斷中,將block.getState()改為event.getState().getBlock(),這樣就能正確獲取到方塊對象了。
接著,在對方塊進行經驗值處理時,我們可以根據配置中定義的方塊和經驗值來更新對應的邏輯。如果包含在列表中,我們可以直接複製之前的處理邏輯,然後稍作修改以符合新的要求。
回到主方法,添加一個static修飾符,並對條件進行反轉處理。對於已成熟的作物,我們希望它不會消耗經驗值,因此需要對判斷條件進行相應的修改。
運行測試後,我們可以觀察到在配置文件中設置的默認值和對應的作物列表。通過測試,可以驗證使用骨粉對土豆的影響情況,包括漲經驗、使用次數等。同時,也可以嘗試對其他作物進行類似的測試,以驗證邏輯是否生效。
若需修改配置文件,可以直接在配置界面進行更改。比如將兩種作物都設置為消耗經驗值,然後測試小麥等作物的表現。根據實際需求,可以調整經驗值增加的數量,並觀察不同作物的表現。
總的來說,這個邏輯並不複雜,主要是對各種情況進行判斷和處理。對於自定義修改或完善邏輯,你可以根據具體需求來對代碼進行適當的調整。
import net.minecraftforge.event.entity.player.PlayerEvent;import net.minecraftforge.eventbus.api.SubscribeEvent;import net.minecraftforge.fml.common.Mod;@Mod.EventBusSubscriber(modid ="your_mod_id")publicclassPlayerCloneEventListener{@SubscribeEventpublicstaticvoidonPlayerClone(PlayerEvent.Cloneevent){if(event.isWasDeath()) {PlayerEntity originalPlayer =event.getOriginal();PlayerEntity newPlayer =event.getPlayer();// 複製經驗值if(originalPlayer.experienceLevel >0) {newPlayer.addExperienceLevel(originalPlayer.experienceLevel - newPlayer.experienceLevel);}// 複製其他Capability,這裡以經驗值Capability為例YourCapability oldCap = originalPlayer.getCapability(YourCapability.CAPABILITY).orElse(null);YourCapability newCap = newPlayer.getCapability(YourCapability.CAPABILITY).orElse(null);if(oldCap !=null&& newCap !=null) {newCap.setXP(oldCap.getXP());}}}}
這段代碼主要處理了在玩家死亡時經驗值丟失的問題,以及如何保留Capability在死亡事件中不重置。在PlayerCloneEvent事件監聽器中,我們需要複製原始玩家的經驗值到新的玩家對象中,以確保在死亡後不會丟失經驗值。
首先,在PlayerCloneEvent事件監聽方法中,我們通過獲取原始玩家對象和當前玩家對象,並將原始玩家的經驗值複製給新的玩家對象。這樣可以保證在複製過程中經驗值得以保存。
接著,我們需要進行一些額外的操作,比如獲取並設置經驗值,確保正確複製老玩家的經驗值。最後,清理多餘的代碼,使整個邏輯更加簡潔明瞭。
通過這樣的處理,就能夠解決在玩家死亡時經驗值丟失的問題,並確保Capability在死亡事件中得以保留不重置。這種方式相對簡單有效,只需添加一個事件監聽器即可實現所需功能。