
FastEvent
Project Abandoned
In summary, the optimization approach itself remains valid, but the Forge and NeoForge platforms do not allow modification of the event registration mechanism – EventBus.
Unlike core classes of Minecraft or Forge, which are loaded as part of the game itself, EventBus operates as an external library. This makes it impossible to apply code transformation tools like Mixin or Transformer to it.
In the experimental version 1.2.0, I made an attempt to achieve even greater performance gains by applying an unconventional approach to modifying the ASMEventHandler
class. Unfortunately, this solution turned out to be non-functional in game versions starting from 1.18.2. These builds are now archived and will not receive updates.
Purpose of This Mod
FastEvent was intended as an optimization addon for Forge and NeoForge, radically accelerating the central event processing system – the foundation of Forge.
Speed Optimization: Examples from Testing
Creating a universally suitable test for every supported Minecraft version is extremely difficult, as the event processing systems in them differ significantly. For clarity, let's use a benchmark report from the open project Cleanroom, where the same high-speed optimization techniques were applied:
10,000 Event Handlers Registered, 0 Events Posted:
Benchmark Mode Cnt Score Error Units
BusPerformanceTest.register10000Legacy avgt 5 1126.498 ± 284.633 ms/op
BusPerformanceTest.register10000Modern avgt 5 1058.961 ± 173.586 ms/op
Speed improvement was about 6.4%.
1,000 Event Handlers Registered, 10,000 Events Posted:
Benchmark Mode Cnt Score Error Units
BusPerformanceTest.register1000test10000Legacy avgt 5 4407.963 ± 4250.643 ms/op
BusPerformanceTest.register1000test10000Modern avgt 5 3550.578 ± 1991.352 ms/op
Speed improvement increased to 24%.
Technical Functionality Details of the Mod
When developers use annotations like @EventBusSubscriber
or @SubscribeEvent
to assign event handlers, the EventBus cannot directly access the method. Instead, it only has a method descriptor object. The simplest solution is to use direct invocation via it: method.invoke(...)
. The JVM virtual machine interprets this call and transfers control to the corresponding method, allowing the handler to receive the event.
However, method.invoke(...)
works very slowly. To speed this up, the standard EventBus mechanism generates new specialized classes for each event handler method during the game's runtime. This helps avoid the slow reflection-based call.
But class generation itself also noticeably slows down performance. The solution chosen in FastEvent is to replace class creation with the operation of constructing lambda expressions. This constructs event handlers faster. An additional advantage is that the lambda remains "hidden" to the virtual machine, giving the JVM the opportunity to apply additional optimizations.
Implementation Comparison via Clear Code
class Listen {
public void onEvent(Event event) {
}
}
Listen lis = new Listen();
// Standard Forge Approach – Creating a Class per Handler
class IEventListener$Listen$onEvent implements IEventListener {
private Listen instance;
public IEventListener$Listen$onEvent(Listen instance) {
this.instance = instance;
}
@Override
public void invoke(Event event) {
instance.onEvent(event);
}
}
IEventListener handler = new IEventListener$Listen$onEvent(lis);
// Fast Implementation via Lambda through FastEvent
IEventListener handler = lis::onEvent;