【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊


3樓貓 發佈時間:2024-12-20 13:23:33 作者:甄別 Language

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第0張

在這一期中,我們將繼續探討Forge的開發教程,著重介紹能力(Capability)的概念。Capability是一種可以為實體添加額外數據的方式,可以通過查閱Forge文檔來了解更多信息。在Forge中,能力通常附加給阻擋實體(blocking entities),而實體(entity)指的是遊戲中的角色或物體。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第1張

除了實體,能力還可以附加到世界級別(world levels)、存儲容器(level trunks)等各種對象上。然而,我們通常將能力應用於實體,尤其是玩家實體。其他類型的實體較少使用。Forge提供了幾種默認的能力,但在本次講解中我們將先自己生成一個能力。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第2張

我們可以以一個例子來說明,比如之前提到的骨粉事件。現在想要升級該事件,給玩家附加一個特殊的能力,稱為“農業經驗”。這個農業經驗可以在正常使用骨粉促使作物生長時消耗,並在收穫其他作物(如小麥、土豆等)時增加。我們需要實現一個農業經驗系統,這時就可以運用自定義的能力(Capability)了。

首先,在代碼中創建一個新的軟件包(package),取名為"capability",再建立一個子包,命名為"farmxp"。在其中創建一個名為"PlayerFarmXP"的類,用於表示玩家的農業經驗能力。在這個類中,我們需要定義一個整數型變量"XP",並創建相應的getter和setter方法。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第3張

接下來,我們需要將數據寫入到NBT標籤中。對於整數類型的數據,我們可以使用putInt方法來存儲到NBT標籤中。還需要實現loadNBTData方法,參數仍然是CompoundTag類型,在這裡我們使用getInt方法從NBT標籤中獲取數據,然後賦值給我們定義的XP變量。

構造函數可以設置默認值為零,並且不需要參數。每收穫一個作物時,農業經驗(XP)增加一個單位。在減少經驗時,需要確保經驗不能為負數,因此可以返回布爾類型進行判斷經驗是否足夠。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第3張

接著,我們新建一個Java類,命名為PlayerFarmXPProvider,實現AbilityProvider接口和INBTSerializable接口。需要實現對應的方法才能註冊。在該類中,我們持有一個PlayerFarmXP對象,並實現serializeNBT和deserializeNBT方法來進行NBT序列化和反序列化操作。

在構造函數中,需要創建一個Capability的實例,並實現getCapability方法。在getCapability方法中,如果判斷到是我們的PlayerFarmXP能力時,就返回LazyOptional對象。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第3張

接下來,讓我們來創建一個私有的LazyOptional<PlayerFarmXP>對象,命名為loFarmXP,通過LazyOptional.of方法創建,使用Lambda表達式將其初始化為this::getPlayerFarmXP。在方法中,如果是PlayerFarmXP的實例,則返回LazyOptional.of,否則返回LazyOptional.empty()。

關於LazyOptional,它是一種在需要時才創建的動態對象。簡單來說,只有在需要時才會進行實例化,具體用法可以按需使用,不必特別深究。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第3張

完成上述操作後,我們需要將這個能力註冊到遊戲中。在ModEventListener中的onRegisterCapabilitiesEvent方法中,使用event.register來註冊我們的PlayerFarmXPProvider類。這樣,我們就成功地註冊了一個能力。

接著,我們需要將這個能力附加到玩家身上。在事件監聽器中,可以編寫一個方法attachCapability來處理AttachCapabilitiesEvent<Entity>事件。判斷實體是否為玩家,並檢查該實體是否具有我們定義的能力,然後向事件中添加能力。最後,在遊戲啟動時,可根據日誌來確認是否成功添加了能力。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第3張

首先,我們需要創建一個新的包命名為command,在其中新建一個Java類,取名為GetFarmXPCommand。我們可以參考原版命令的寫法,比如獲取世界種子的命令,瞭解參數和邏輯結構。在GetFarmXPCommand中,我們定義了一個命令,命名為DESC,並註冊了該命令。

命令通常包含權限檢查以確定命令是否可執行,可以使用原版hasPermission方法或自定義檢查邏輯。在execute方法中,可以通過getSource和getLevel獲取命令來源和世界實例,然後使用sendFeedback將信息發送給玩家。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第3張

接著,我們需要在DISPATCH中註冊這個命令,並定義其執行邏輯。在execute方法中,可以通過getContext獲取CommandSourceStack和CommandContext,並進一步操作。例如,通過getPlayer獲取執行命令的玩家,再用getCapability獲取PlayerFarmXPProvider,然後判斷其是否存在(若不為空則執行相應操作)。

首先,我們繼續使用Lambda表達式,在GetFarmXPCommand中的execute方法中,可以通過context.getSource().sendSuccess發送消息給命令的執行者。在這裡,我們可以使用ComponentUtils.copyOnClickText來創建一個可點擊複製的文本,用Literal表示純文本,然後以XP: 開頭,再加上getXP()獲取到的經驗值。最後,將false替換為0,表示默認為0。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第3張

接著,我們需要將這個命令註冊到我們的mod中。通常在Forge事件監聽器中,在registerCommands方法中註冊我們的命令,使用CommandDispatcher的register方法。通過ForgeEventBus中的register方法將其與相關事件關聯起來,實現命令的註冊。

另外,我們還需要考慮增加經驗值的邏輯。在處理方塊破壞事件時,可以使用BlockEvent.BreakEvent來判斷是否摧毀了作物等特定方塊,如果是作物,則可以通過以下代碼

來增加經驗值或做其他操作。

event.getPlayer().getCapability(PlayerFarmXPProvider.FARM_XP_CAPABILITY).ifPresent

在這裡,我們需要確保對經驗值進行適當的判斷。可以在PlayerFarmXP類中的對應方法中添加邏輯,確保經驗值足夠時返回true,否則返回false。在處理經驗減少事件時,可以使用xp.decreaseEvent().setCancelled()來取消事件,以防止經驗值不足。

【乾貨】《我的世界》Mod開發教程06:Capability簡述、命令註冊-第3張

通過合適的邏輯控制,當經驗值不足時取消事件的發生,保證了穩健和正確的行為。在遊戲中測試這個邏輯是否有效,確保經驗值隨著操作的合理增減。同時,通過種植、收成、使用骨粉等交互驗證經驗值的變化是否符合預期。

最後提醒,有些情況下需要進一步完善代碼,比如對於不同作物或不同狀態的處理邏輯、對於已成熟植物的特殊處理等;在下期教程我們可以進一步討論和解決這些問題,以提高功能的完整性。


© 2022 3樓貓 下載APP 站點地圖 廣告合作:asmrly666@gmail.com