1818package net .elytrium .limboapi .injection .event ;
1919
2020import com .google .common .collect .ListMultimap ;
21- import com .velocitypowered .api .event .EventManager ;
21+ import com .velocitypowered .api .event .EventTask ;
22+ import com .velocitypowered .api .event .PostOrder ;
23+ import com .velocitypowered .api .event .Subscribe ;
2224import com .velocitypowered .api .event .player .GameProfileRequestEvent ;
2325import com .velocitypowered .api .event .player .KickedFromServerEvent ;
2426import com .velocitypowered .api .plugin .PluginContainer ;
25- import com .velocitypowered .api .plugin .PluginManager ;
2627import com .velocitypowered .api .util .GameProfile ;
27- import com .velocitypowered .proxy .VelocityServer ;
28- import com .velocitypowered .proxy .command .VelocityCommandManager ;
29- import com .velocitypowered .proxy .connection .client .ConnectedPlayer ;
3028import com .velocitypowered .proxy .event .VelocityEventManager ;
3129import java .lang .invoke .MethodHandle ;
3230import java .lang .invoke .MethodHandles ;
4644import net .elytrium .limboapi .Settings ;
4745
4846@ SuppressWarnings ("unchecked" )
49- public class EventManagerHook extends VelocityEventManager {
47+ public class EventManagerHook {
5048
5149 private static final Field HANDLERS_BY_TYPE_FIELD ;
52- private static final Field HANDLERS_CACHE_FIELD ;
53- private static final Field HANDLER_ADAPTERS_FIELD ;
54- private static final Field EVENT_TYPE_TRACKER_FIELD ;
55- private static final Field VELOCITY_SERVER_EVENT_MANAGER_FIELD ;
5650 private static final Class <?> HANDLER_REGISTRATION_CLASS ;
57- private static final Field UNTARGETED_METHOD_HANDLERS_FIELD ;
5851 private static final MethodHandle PLUGIN_FIELD ;
59- private static final Field VELOCITY_COMMAND_MANAGER_EVENT_MANAGER_FIELD ;
6052 private static final MethodHandle FIRE_METHOD ;
53+ private static final MethodHandle FUTURE_FIELD ;
6154
6255 private final Set <GameProfile > proceededProfiles = new HashSet <>();
6356 private final LimboAPI plugin ;
57+ private final VelocityEventManager eventManager ;
6458
6559 private Object handlerRegistrations ;
6660 private boolean hasHandlerRegistration ;
6761
68- private EventManagerHook (PluginManager pluginManager , LimboAPI plugin ) {
69- super (pluginManager );
70-
62+ public EventManagerHook (LimboAPI plugin , VelocityEventManager eventManager ) {
7163 this .plugin = plugin ;
64+ this .eventManager = eventManager ;
7265 }
7366
74- @ Override
75- public void register (Object plugin , Object listener ) {
76- super .register (plugin , listener );
77-
78- if (Settings .IMP .MAIN != null && Settings .IMP .MAIN .AUTO_REGENERATE_LISTENERS ) {
79- try {
80- this .reloadHandlers ();
81- } catch (IllegalAccessException e ) {
82- throw new ReflectionException (e );
83- }
84- }
85- }
86-
87- @ Override
88- public void fireAndForget (Object event ) {
89- Object toReply = this .proxyHook (event );
90- if (toReply == null ) {
91- super .fireAndForget (event );
92- }
93- }
94-
95- @ Override
96- public <E > CompletableFuture <E > fire (E event ) {
97- CompletableFuture <E > toReply = this .proxyHook (event );
98- if (toReply == null ) {
99- return super .fire (event );
67+ @ Subscribe (order = PostOrder .FIRST )
68+ public EventTask onGameProfileRequest (GameProfileRequestEvent event ) {
69+ GameProfile originalProfile = event .getGameProfile ();
70+ if (this .proceededProfiles .remove (originalProfile )) {
71+ return null ;
10072 } else {
101- return toReply ;
102- }
103- }
104-
105- private <E > CompletableFuture <E > proxyHook (E event ) {
106- if (event instanceof GameProfileRequestEvent ) {
107- GameProfile originalProfile = ((GameProfileRequestEvent ) event ).getGameProfile ();
108- if (this .proceededProfiles .remove (originalProfile )) {
109- return null ;
110- } else {
111- CompletableFuture <E > fireFuture = new CompletableFuture <>();
112- CompletableFuture <E > hookFuture = new CompletableFuture <>();
113- fireFuture .thenAccept (modifiedEvent -> {
114- try {
115- GameProfileRequestEvent requestEvent = (GameProfileRequestEvent ) modifiedEvent ;
116- this .plugin .getLoginListener ().hookLoginSession (requestEvent );
117- hookFuture .complete (modifiedEvent );
118- } catch (Throwable e ) {
119- throw new ReflectionException (e );
120- }
121- });
73+ CompletableFuture <GameProfileRequestEvent > fireFuture = new CompletableFuture <>();
74+ CompletableFuture <GameProfileRequestEvent > hookFuture = new CompletableFuture <>();
75+ fireFuture .thenAccept (modifiedEvent -> {
76+ try {
77+ this .plugin .getLoginListener ().hookLoginSession (modifiedEvent );
78+ hookFuture .complete (modifiedEvent );
79+ } catch (Throwable e ) {
80+ throw new ReflectionException (e );
81+ }
82+ });
12283
123- if (this .hasHandlerRegistration ) {
124- try {
125- FIRE_METHOD .invoke (this , fireFuture , event , 0 , false , this .handlerRegistrations );
126- } catch (Throwable e ) {
127- fireFuture .complete (event );
128- throw new ReflectionException (e );
129- }
130- } else {
84+ if (this .hasHandlerRegistration ) {
85+ try {
86+ FIRE_METHOD .invoke (this .eventManager , fireFuture , event , 0 , false , this .handlerRegistrations );
87+ } catch (Throwable e ) {
13188 fireFuture .complete (event );
89+ throw new ReflectionException (e );
13290 }
133-
134- return hookFuture ;
91+ } else {
92+ fireFuture . complete ( event ) ;
13593 }
136- } else if ( event instanceof KickedFromServerEvent kicked ) {
137- CompletableFuture < E > hookFuture = new CompletableFuture <>();
138- super . fire ( kicked ). thenRunAsync (( ) -> {
94+
95+ // ignoring other subscribers by directly completing the future
96+ return EventTask . withContinuation ( continuation -> hookFuture . whenComplete (( result , cause ) -> {
13997 try {
140- Function < KickedFromServerEvent , Boolean > callback = this . plugin . getKickCallback ( kicked . getPlayer () );
141- if (callback == null || ! callback . apply ( kicked ) ) {
142- hookFuture .complete (event );
98+ CompletableFuture < GameProfileRequestEvent > future = ( CompletableFuture < GameProfileRequestEvent >) FUTURE_FIELD . invokeExact ( continuation );
99+ if (future != null ) {
100+ future .complete (result );
143101 }
144- } catch (Throwable throwable ) {
145- LimboAPI .getLogger ().error ("Failed to handle KickCallback, ignoring its result" , throwable );
146- hookFuture .complete (event );
102+ } catch (Throwable e ) {
103+ throw new ReflectionException (e );
147104 }
148- }, ((ConnectedPlayer ) kicked .getPlayer ()).getConnection ().eventLoop ());
149- return hookFuture ;
150- } else {
151- return null ;
105+ }));
106+ }
107+ }
108+
109+ @ Subscribe (order = PostOrder .LAST )
110+ public EventTask onKickedFromServer (KickedFromServerEvent event ) {
111+ CompletableFuture <KickedFromServerEvent > hookFuture = new CompletableFuture <>();
112+ try {
113+ Function <KickedFromServerEvent , Boolean > callback = this .plugin .getKickCallback (event .getPlayer ());
114+ if (callback == null || !callback .apply (event )) {
115+ hookFuture .complete (event );
116+ }
117+ } catch (Throwable throwable ) {
118+ LimboAPI .getLogger ().error ("Failed to handle KickCallback, ignoring its result" , throwable );
119+ hookFuture .complete (event );
152120 }
121+
122+ // if kick callback is null and no exception occurred, hookFuture won't be ever finished, and
123+ // the event chain would be broken, that is what we need.
124+ return EventTask .resumeWhenComplete (hookFuture );
153125 }
154126
155127 public void proceedProfile (GameProfile profile ) {
@@ -158,7 +130,7 @@ public void proceedProfile(GameProfile profile) {
158130
159131 @ SuppressWarnings ("rawtypes" )
160132 public void reloadHandlers () throws IllegalAccessException {
161- ListMultimap <Class <?>, ?> handlersMap = (ListMultimap <Class <?>, ?>) HANDLERS_BY_TYPE_FIELD .get (this );
133+ ListMultimap <Class <?>, ?> handlersMap = (ListMultimap <Class <?>, ?>) HANDLERS_BY_TYPE_FIELD .get (this . eventManager );
162134 List disabledHandlers = handlersMap .get (GameProfileRequestEvent .class );
163135 List preEvents = new ArrayList <>();
164136 List newHandlers = new ArrayList <>(disabledHandlers );
@@ -198,27 +170,13 @@ public void reloadHandlers() throws IllegalAccessException {
198170 HANDLERS_BY_TYPE_FIELD = VelocityEventManager .class .getDeclaredField ("handlersByType" );
199171 HANDLERS_BY_TYPE_FIELD .setAccessible (true );
200172
201- HANDLERS_CACHE_FIELD = VelocityEventManager .class .getDeclaredField ("handlersCache" );
202- HANDLERS_CACHE_FIELD .setAccessible (true );
203-
204- HANDLER_ADAPTERS_FIELD = VelocityEventManager .class .getDeclaredField ("handlerAdapters" );
205- HANDLER_ADAPTERS_FIELD .setAccessible (true );
206-
207- VELOCITY_SERVER_EVENT_MANAGER_FIELD = VelocityServer .class .getDeclaredField ("eventManager" );
208- VELOCITY_SERVER_EVENT_MANAGER_FIELD .setAccessible (true );
209-
210- UNTARGETED_METHOD_HANDLERS_FIELD = VelocityEventManager .class .getDeclaredField ("untargetedMethodHandlers" );
211- UNTARGETED_METHOD_HANDLERS_FIELD .setAccessible (true );
212-
213- EVENT_TYPE_TRACKER_FIELD = VelocityEventManager .class .getDeclaredField ("eventTypeTracker" );
214- EVENT_TYPE_TRACKER_FIELD .setAccessible (true );
215-
216173 HANDLER_REGISTRATION_CLASS = Class .forName ("com.velocitypowered.proxy.event.VelocityEventManager$HandlerRegistration" );
217174 PLUGIN_FIELD = MethodHandles .privateLookupIn (HANDLER_REGISTRATION_CLASS , MethodHandles .lookup ())
218175 .findGetter (HANDLER_REGISTRATION_CLASS , "plugin" , PluginContainer .class );
219176
220- VELOCITY_COMMAND_MANAGER_EVENT_MANAGER_FIELD = VelocityCommandManager .class .getDeclaredField ("eventManager" );
221- VELOCITY_COMMAND_MANAGER_EVENT_MANAGER_FIELD .setAccessible (true );
177+ Class <?> continuationTaskClass = Class .forName ("com.velocitypowered.proxy.event.VelocityEventManager$ContinuationTask" );
178+ FUTURE_FIELD = MethodHandles .privateLookupIn (continuationTaskClass , MethodHandles .lookup ())
179+ .findGetter (continuationTaskClass , "future" , CompletableFuture .class );
222180
223181 // The desired 5-argument fire method is private, and its 5th argument is the array of the private class,
224182 // so we can't pass it into the Class#getDeclaredMethod(Class...) method.
@@ -240,20 +198,4 @@ public void reloadHandlers() throws IllegalAccessException {
240198 throw new ReflectionException (e );
241199 }
242200 }
243-
244- public static void init (LimboAPI plugin ) throws ReflectiveOperationException , InterruptedException {
245- VelocityServer server = plugin .getServer ();
246- EventManager newEventManager = new EventManagerHook (server .getPluginManager (), plugin );
247- VelocityEventManager oldEventManager = server .getEventManager ();
248- HANDLERS_BY_TYPE_FIELD .set (newEventManager , HANDLERS_BY_TYPE_FIELD .get (oldEventManager ));
249- HANDLERS_CACHE_FIELD .set (newEventManager , HANDLERS_CACHE_FIELD .get (oldEventManager ));
250- UNTARGETED_METHOD_HANDLERS_FIELD .set (newEventManager , UNTARGETED_METHOD_HANDLERS_FIELD .get (oldEventManager ));
251- HANDLER_ADAPTERS_FIELD .set (newEventManager , HANDLER_ADAPTERS_FIELD .get (oldEventManager ));
252- EVENT_TYPE_TRACKER_FIELD .set (newEventManager , EVENT_TYPE_TRACKER_FIELD .get (oldEventManager ));
253-
254- VELOCITY_SERVER_EVENT_MANAGER_FIELD .set (server , newEventManager );
255- VELOCITY_COMMAND_MANAGER_EVENT_MANAGER_FIELD .set (server .getCommandManager (), newEventManager );
256-
257- oldEventManager .shutdown ();
258- }
259201}
0 commit comments