AI写作智能体 自主规划任务,支持联网查询和网页读取,多模态高效创作各类分析报告、商业计划、营销方案、教学内容等。 广告
## FML生命周期事件 FML生命周期事件,顾名思义,就是FML加载、关闭、和Mod加载等等相关的事件,这些希望监听对应事件的方法使用`@EventHandler`注解修饰,并且应在被`@Mod`注解修饰的主类下,Forge会寻找并注册仅含一个参数并且参数符合特定类型的方法。如下面三个FML生命周期事件是最常用的: * `FMLPreInitializationEvent` * `FMLInitializationEvent` * `FMLPostInitializationEvent` 这三个事件的使用方法已经讲过,此处不再赘述。 还有下面两个事件: * `FMLConstructionEvent`在Mod开始加载时触发。 * `FMLLoadCompleteEvent`在Mod加载完成时触发。 除上面这些之外,还有下面的这些比较常用的用于服务端的FML生命周期事件: * `FMLServerAboutToStartEvent` * `FMLServerStartingEvent` * `FMLServerStartedEvent` * `FMLServerStoppingEvent` * `FMLServerStoppedEvent` 想必读者已经可以猜出来这五个事件的异同,并了解这些事件被触发的条件了。 ## 注册事件 Forge的事件系统一直在Forge中占有十分重要的地位,可以这么说,没有事件,就没有Mod。大家可以注意到,主类的`preInit`,`init`,`postInit`方法,全部都是事件驱动的。换句话说,理论上一个Mod的开发教程本身应该从事件讲起。 Forge的事件系统几乎涵盖了方方面面,从服务端到客户端,从世界生成到物品方块行为,从玩家行为到一般实体行为,等等。 Forge的事件系统分为两类,一类是FML生命周期事件,一类是Minecraft事件。 Forge本身提供了很多Minecraft事件,这些事件基本上可以完成对Minecraft大部分物品、方块、实体等特性的修改,并且这些事件的数量还在不断地上升。开发者只需要注册一个包含监听这些事件的方法的类,Forge就会挂钩上这些方法。这些方法使用`@SubscribeEvent`注解进行修饰,Forge寻找并挂钩这些方法的方式和上面的FML生命周期事件类似,只不过由于挂钩的方式不同,调用的时候效率要更高。 首先我们创造一个类。在包`net.xiaobang.bm.common`下新建一个文件`EventLoader.java`: `src/main/java/net/xiaobang/bm/common/EventLoader.java` ~~~ package net.xiaobang.bm.common; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.PlayerInteractEvent; public class EventLoader { public EventLoader(FMLInitializationEvent e) { MinecraftForge.EVENT_BUS.register(this);//注册本类的所有事件 /* 除此之外,Forge还提供了需要在MinecraftForge.TERRAIN_GEN_BUS上注册的地形生成事件,需要在 MinecraftForge.ORE_GEN_BUS上注册的矿物生成事件等等。 */ } @SubscribeEvent//当forge注册所有事件的时候,会扫描具有此注解的方法,再挂钩。Forge会根据方法的参数类型 //来区分不同的事件,比如onPlayerInteract方法挂钩的就是玩家在和物品或方块互动的时候触发的事件PlayerInteractEvent public void onPlayerInteract(PlayerInteractEvent event){//玩家点击事件 if (!event.world.isRemote)//判断是否是客户端调用此事件,event.world.isRemote与event.entityPlayer.isServerWorld同理 System.out.println("玩家" + event.entityPlayer.getDisplayName() + "左键/右键了一下"); } } ~~~ (注释写不下,写这里了)`@SubscribeEvent`注解有两个参数,其中一个是`receiveCanceled`,与是否取消该事件相关,默认为`false`,这个参数不太常用,我们不去管它。还有一个参数是`priority`,比较常用,表示事件的优先级,可能的情况有五种: * `EventPriority.HIGHEST` * `EventPriority.HIGH` * `EventPriority.NORMAL` * `EventPriority.LOW` * `EventPriority.LOWEST` 默认的优先级是`EventPriority.NORMAL`,当然,如果想自定优先级,往往都会选择`EventPriority.HIGH`,和`EventPriority.HIGHEST`。如果没有特殊需求,这一项最好默认。 最后在CommonProxy注册EventLoader: **`src/main/java/net/xiaobang/bm/common/CommonProxy.java`**(部分) ~~~ public void init(FMLInitializationEvent event) { new CraftingLoader(); new EventLoader(); } ~~~ 最后的最后,打开游戏尝试一下把。 ## Event类解析 Forge提供的所有事件,都是`cpw.mods.fml.common.eventhandler.Event`类的子类。当前Forge版本下这个类的所有的子类的用法zzzz大佬在他的教程[附录](https://fmltutor.ustc-zzzz.net/%E9%99%84%E5%BD%95A-%E4%BA%8B%E4%BB%B6%E5%88%97%E8%A1%A8)(高版本)中列出了一张表,以供读者参考。这一部分针对Event类本身。 Event类添加了下面几个公开方法: * `public boolean isCancelable()` 返回该事件是否可以被取消。 * `public boolean isCanceled()` 返回该事件是否已被取消。 * `public void setCanceled(boolean cancel)` 设置该事件是否被取消。 * `public boolean hasResult()` 返回该事件是否有结果,添加了`@HasResult`注解的事件默认为`true`,否则为`false`。 * `public Result getResult()` 返回该事件的结果,有`Result.DENY`,`Result.DEFAULT`,`Result.ALLOW`三种,默认为`Result.DEFAULT`。 * `public void setResult(Result value)` 为该事件设置一个结果。 * `public ListenerList getListenerList()` 获取所有注册该事件的监听器。 * `public EventPriority getPhase()` 获取该事件的优先级,上面已有说明。 * `public void setPhase(EventPriority value)` 设置该事件的优先级,上面已有说明。 (以上大部分来自zzzz大佬的教程)