最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

MinecraftFORGE事件系統(tǒng)淺談

2023-07-31 17:39 作者:MegaDarkness  | 我要投稿

前言:讀者應(yīng)該具有一定的Java基礎(chǔ)

Forge事件系統(tǒng)

MC原版并沒有事件這種東西,事件系統(tǒng)是Forge提供的修改添減原版內(nèi)容,特性的東西。

Forge的事件系統(tǒng)覆蓋面極廣,模組注冊,世界生成,玩家行為,渲染等。

例如:當玩家刻更新時的事件(TickEvent.PlayerTickEvent)。

絕大多數(shù)的事件都是在主事件總線上觸發(fā)(MinecraftForge.EVENT_BUS)。

使用

將事件訂閱到事件總線上。

EventBus提供的shutdown()方法是來關(guān)閉總線的。

創(chuàng)建Event Handler

事件方法是void類型的,不返回結(jié)果。該方法可以是靜態(tài)(static void)或?qū)嵗?void)的。

注冊方法:

?

值得一提的是,泛型事件處理程序也需要指定泛型的類。必須在 main mod 類的構(gòu)造函數(shù)中注冊事件處理程序。

?

實例事件

public?class?MyForgeEventHandler??{

????@SubscribeEvent

????public?void?pickupItem(EntityItemPickupEvent?event)?{

????????System.out.println("Item?picked?up!");

????}

}

我們先從實例的方法開始說起。可以看到這里最為特殊的就是@SubscribeEvent注解,它用來標記這是一個訂閱器,至于它具體監(jiān)聽的事件是由它的參數(shù)類型決定的,在這里它的參數(shù)類型是EntityItemPickupEvent,說明它監(jiān)聽的是實體撿起物品這個事件。

當然,對于實例方式的事件處理這樣還不夠,我們還得手動在某個地方實例化它并把它注入到事件總線里,我們之前說過Minecraft里有兩條事件總線「Forge總線」和「Mod總線」,Mod總線主要負責游戲的生命周期事件,也就是初始化過程的事件,而Forge總線負責的就是除了生命周期事件外的所有事件。你可以用MinecraftForge.EVENT_BUS.register()方法將你的事件實例注冊到Forge總線中,也可用FMLJavaModLoadingContext.get().getModEventBus().register()方法將其注冊到Mod總線中,一般情況下你應(yīng)該在你的Mod主類的初始化方法里注冊這些事件。

在我們的例子里就是如下:

MinecraftForge.EVENT_BUS.register(new?MyForgeEventHandler());

靜態(tài)事件

當然所有的事件處理器都要手動注冊非常的麻煩,F(xiàn)orge同樣提供了一個靜態(tài)的注冊事件的方法。內(nèi)容如下:

?@Mod.EventBusSubscriber

public?class?MyStaticClientOnlyEventHandler?{

????@SubscribeEvent

????public?static?void?drawLast(RenderLevelLastEvent?event)?{

????????System.out.println("Drawing!");

????}

}

可以看到,這里與實例注冊不同的是增加了@Mod.EventBusSubscriber,他會自動注冊類下帶有 @SubscribeEvent注解的靜態(tài)方法。

你可以用@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)來指定你要注入到Mod總線中。當然這里的參數(shù)不止一個,大家可以自行查看@Mod.EventBusSubscriber的具體內(nèi)容。

更為詳細的使用事件方法請看?早上?的Forge事件機制淺談。

子事件

例如:TickEvent下有PlayerTickEvent,ClientTickEvent等

許多事件本身有不同的變體。這些可以是不同的,但都基于一個共同的因素(例如),或者可以是具有多個階段的事件(例如)。請注意,如果偵聽父事件類,則將收到對所有子類的方法的調(diào)用。?

模組事件總線

mod 事件總線主要用于偵聽 mods 應(yīng)初始化的生命周期事件。mod 總線上的每個事件都需要實現(xiàn) 。其中許多事件也是并行運行的,因此可以同時初始化模組。這確實意味著您無法在這些事件中直接執(zhí)行來自其他模組的代碼。為此使用系統(tǒng)。IModBusEvent InterModComms

?

以下是在 mod 事件總線上的 mod 初始化期間調(diào)用的四個最常用的生命周期事件:

FMLCommonSetupEvent

FMLClientSetupEvent & FMLDedicatedServerSetupEvent

InterModEnqueueEvent

InterModProcessEvent

注意

????和 僅在其各自的分發(fā)上調(diào)用。FMLClientSetupEvent?FMLDedicatedServerSetupEvent。

????這幾個生命周期事件都是并行運行的,因為它們都是 的子類。如果要在任何 期間在主線程上運行運行代碼,可以使用 來執(zhí)行此操作。??????ParallelDispatchEvent ParallelDispatchEvent#enqueueWork

?

在生命周期事件旁邊,有一些雜項事件在 mod 事件總線上觸發(fā),您可以在其中注冊、設(shè)置或初始化各種內(nèi)容。與生命周期事件相比,這些事件中的大多數(shù)不是并行運行的。舉個典型例子:RegisterEvent

這里有一個很好的經(jīng)驗法則:當事件應(yīng)該在 mod 初始化期間處理時,會在 mod 事件總線上觸發(fā)事件。

?

Event類解析

????Forge提供的所有事件,都是Event類的子類。當前Forge版本下這個類的所有的子類的用法zzzz大佬在他的教程附錄中列出了一張表,以供讀者參考。這一部分針對Event類本身。

Event類添加了下面幾個公開方法:

·?public boolean isCancelable()

返回該事件是否可以被取消。

·?public boolean isCanceled()

返回該事件是否已被取消。

·?public void setCanceled(boolean cancel)

設(shè)置該事件是否被取消。

·?public boolean hasResult()

返回該事件是否有結(jié)果,添加了@HasResult注解的事件默認為true,否則為false。

·?public Result getResult()

返回該事件的結(jié)果,有Result.DENY,Result.DEFAULT,Result.ALLOW三種,默認為Result.DEFAULT。

·?public void setResult(Result value)

為該事件設(shè)置一個結(jié)果。

·?public ListenerList getListenerList()

獲取所有注冊該事件的監(jiān)聽器。

·?public EventPriority getPhase()

獲取該事件的優(yōu)先級,上面已有說明。

·?public void setPhase(EventPriority value)

設(shè)置該事件的優(yōu)先級,上面已有說明。

(以上大部分來自zzzz的教程)

?

自定義一個事件并使用它

????有些時候,Forge本身提供的事件不能滿足模組制作者們的需求,這時候就可以自定義事件。

我們新建一個UseItemEvent 事件。

public?class?UseItemEvent?extends?MegaItemEvent{

????private?final?InteractionHand?interactionHand;

????private?final?Level?level;

????public?UseItemEvent(Player?player,?ItemStack?stack,?InteractionHand?hand,?Level?level)?{

????????super(player,?stack);

????????interactionHand?=?hand;

????????this.level?=?level;

????}

????public?InteractionHand?getInteractionHand()?{

????????return?interactionHand;

????}

????public?boolean?isClient()?{

????????return?level.isClientSide;

????}

????public?Level?getLevel()?{

????????return?level;

????}

}

可以看到,這個事件類提供了兩個getter方法。

?

MegaItemEvent.java下。

public?class?MegaItemEvent?extends?PlayerEvent?{

????private?ItemStack?stack;

????public?MegaItemEvent(Player?player,?ItemStack?itemStack)?{

????????super(player);

????????stack?=?itemStack;

????}

????public?ItemStack?getStack()?{

????????return?stack;

????}

????public?void?setStack(ItemStack?stack)?{

????????this.stack?=?stack;

????}

}

接下來我們需要在指定位置發(fā)布事件(post)。

使用Mixin注入useItem方法(右鍵物品時)。

@Mixin(MultiPlayerGameMode.class)

public?class?MultiPlayerGameModeMixin?{

????@Inject(method?=?"useItem",?at?=?@At("HEAD"))

????public?void?useItem(Player?p_105236_,?Level?p_105237_,?InteractionHand?p_105238_,?CallbackInfoReturnable?cir)?{

????????UseItemEvent?event?=?new?UseItemEvent(p_105236_,?p_105236_.getItemInHand(p_105238_),?p_105238_,?p_105237_);

????????MinecraftForge.EVENT_BUS.post(event);

????}

}

(當然,你也可以自定義一個EventBus來用)。

Events.java下。

@SubscribeEvent

public?static?void?use(UseItemEvent?event)?{

????if?(event.getPlayer().getItemInHand(event.getInteractionHand()).getItem()?instanceof??SwordItem)

????????event.getPlayer().setItemInHand(event.getInteractionHand(),??ItemStack.EMPTY);

}

這個事件的意思就是,當你右鍵一個劍類物品,就會清除它。

右鍵后 可以看到事件成功運行,物品被清除。

創(chuàng)建setter并使用

UseItemEvent.java

下。

public?class?UseItemEvent?extends?MegaItemEvent{

????private?InteractionHand?interactionHand;

????private?final?Level?level;

????public?UseItemEvent(Player?player,?ItemStack?stack,?InteractionHand?hand,?Level?level)?{

????????super(player,?stack);

????????interactionHand?=?hand;

????????this.level?=?level;

????}

????public?InteractionHand?getInteractionHand()?{

????????return?interactionHand;

????}

????public?boolean?isClient()?{

????????return?level.isClientSide;

????}

????public?Level?getLevel()?{

????????return?level;

????}

????

????//新建setter

????public?void?setHand(InteractionHand?hand)?{

????????this.interactionHand?=?hand;

????}

}

MultiPlayerGameModeMixin.java

下。

@Mixin(MultiPlayerGameMode.class)

public?class?MultiPlayerGameModeMixin?{

????@Inject(method?=?"useItem",?at?=?@At("HEAD"))

????public?void?useItem(Player?p_105236_,?Level?p_105237_,?InteractionHand?p_105238_,?CallbackInfoReturnable?cir)?{

????????UseItemEvent?event?=?new?UseItemEvent(p_105236_,?p_105236_.getItemInHand(p_105238_),?p_105238_,?p_105237_);

????????MinecraftForge.EVENT_BUS.post(event);

????????//設(shè)置

????????p_105238_?=?event.getInteractionHand();

????}

}

這里InteractionHand 形參被設(shè)置為事件的hand了。

再進行setHand就會生效,而不是沒有用處。

?

?

Forge事件系統(tǒng)淺談

?Mcmod

該教程版本為1.18.2

MinecraftFORGE事件系統(tǒng)淺談的評論 (共 條)

分享到微博請遵守國家法律
南宫市| 阳东县| 华宁县| 抚顺县| 峨山| 桦南县| 丰县| 常宁市| 商南县| 娄烦县| 新晃| 黄浦区| 神农架林区| 会昌县| 沾化县| 塘沽区| 醴陵市| 昌图县| 公主岭市| 盱眙县| 商水县| 邹城市| 湛江市| 海盐县| 宁安市| 资源县| 曲松县| 资中县| 镇远县| 文山县| 平泉县| 泾源县| 万载县| 江西省| 乌鲁木齐县| 于田县| 双城市| 毕节市| 简阳市| 水富县| 石楼县|