Skip to content

Commit c0b748a

Browse files
committed
Release 1.1.25
EventManagerHook is now a Listener and is not extended from EventManager More BlockEntityVersions (fixes #157) Gradle updated
1 parent fab2948 commit c0b748a

File tree

10 files changed

+96
-136
lines changed

10 files changed

+96
-136
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Test server: [``ely.su``](https://hotmc.ru/minecraft-server-203216)
5353
<dependency>
5454
<groupId>net.elytrium.limboapi</groupId>
5555
<artifactId>api</artifactId>
56-
<version>1.1.24</version>
56+
<version>1.1.25</version>
5757
<scope>provided</scope>
5858
</dependency>
5959
</dependencies>
@@ -70,7 +70,7 @@ Test server: [``ely.su``](https://hotmc.ru/minecraft-server-203216)
7070
}
7171
7272
dependencies {
73-
compileOnly("net.elytrium.limboapi:api:1.1.24")
73+
compileOnly("net.elytrium.limboapi:api:1.1.25")
7474
}
7575
```
7676

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.1.24
1+
1.1.25

api/src/main/java/net/elytrium/limboapi/api/chunk/BlockEntityVersion.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@
1515

1616
public enum BlockEntityVersion {
1717
LEGACY(EnumSet.range(ProtocolVersion.MINECRAFT_1_7_2, ProtocolVersion.MINECRAFT_1_18_2)),
18-
MINECRAFT_1_19(EnumSet.range(ProtocolVersion.MINECRAFT_1_19, ProtocolVersion.MAXIMUM_VERSION));
18+
MINECRAFT_1_19(EnumSet.of(ProtocolVersion.MINECRAFT_1_19)),
19+
MINECRAFT_1_19_1(EnumSet.of(ProtocolVersion.MINECRAFT_1_19_1)),
20+
MINECRAFT_1_19_3(EnumSet.of(ProtocolVersion.MINECRAFT_1_19_3)),
21+
MINECRAFT_1_19_4(EnumSet.of(ProtocolVersion.MINECRAFT_1_19_4)),
22+
MINECRAFT_1_20(EnumSet.of(ProtocolVersion.MINECRAFT_1_20)),
23+
MINECRAFT_1_20_2(EnumSet.of(ProtocolVersion.MINECRAFT_1_20_2)),
24+
MINECRAFT_1_20_3(EnumSet.of(ProtocolVersion.MINECRAFT_1_20_3)),
25+
MINECRAFT_1_20_5(EnumSet.of(ProtocolVersion.MINECRAFT_1_20_5)),
26+
MINECRAFT_1_21(EnumSet.of(ProtocolVersion.MINECRAFT_1_21));
1927

2028
private static final EnumMap<ProtocolVersion, BlockEntityVersion> MC_VERSION_TO_ITEM_VERSIONS = new EnumMap<>(ProtocolVersion.class);
2129

@@ -48,6 +56,14 @@ public Set<ProtocolVersion> getVersions() {
4856
public static BlockEntityVersion parse(String from) {
4957
return switch (from) {
5058
case "1.19" -> MINECRAFT_1_19;
59+
case "1.19.1" -> MINECRAFT_1_19_1;
60+
case "1.19.3" -> MINECRAFT_1_19_3;
61+
case "1.19.4" -> MINECRAFT_1_19_4;
62+
case "1.20" -> MINECRAFT_1_20;
63+
case "1.20.2" -> MINECRAFT_1_20_2;
64+
case "1.20.3" -> MINECRAFT_1_20_3;
65+
case "1.20.5" -> MINECRAFT_1_20_5;
66+
case "1.21" -> MINECRAFT_1_21;
5167
default -> LEGACY;
5268
};
5369
}

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ allprojects() {
1414
apply(plugin: "org.cadixdev.licenser")
1515

1616
setGroup("net.elytrium.limboapi")
17-
setVersion("1.1.24")
17+
setVersion("1.1.25")
1818

1919
compileJava() {
2020
sourceCompatibility = JavaVersion.VERSION_17
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

plugin/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ buildscript() {
99

1010
plugins() {
1111
id("java")
12-
id("com.github.johnrengelman.shadow").version("7.1.2")
12+
id("io.github.goooler.shadow").version("8.1.8")
1313
}
1414

1515
compileJava() {

plugin/src/main/java/net/elytrium/limboapi/LimboAPI.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ public class LimboAPI implements LimboFactory {
155155
private ProtocolVersion maxVersion;
156156
private LoginListener loginListener;
157157
private boolean compressionEnabled;
158+
private EventManagerHook eventManagerHook;
158159

159160
@Inject
160161
public LimboAPI(Logger logger, ProxyServer server, Metrics.Factory metricsFactory, @DataDirectory Path dataDirectory) {
@@ -186,9 +187,8 @@ public LimboAPI(Logger logger, ProxyServer server, Metrics.Factory metricsFactor
186187
SimpleBlockEntity.init();
187188
SimpleItem.init();
188189
SimpleTagManager.init();
189-
LOGGER.info("Hooking into EventManager, PlayerList/UpsertPlayerInfo and StateRegistry...");
190+
LOGGER.info("Hooking into PlayerList/UpsertPlayerInfo and StateRegistry...");
190191
try {
191-
EventManagerHook.init(this);
192192
LegacyPlayerListItemHook.init(this, LimboProtocol.PLAY_CLIENTBOUND_REGISTRY);
193193
UpsertPlayerInfoHook.init(this, LimboProtocol.PLAY_CLIENTBOUND_REGISTRY);
194194
RemovePlayerInfoHook.init(this, LimboProtocol.PLAY_CLIENTBOUND_REGISTRY);
@@ -268,7 +268,7 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
268268

269269
@Subscribe(order = PostOrder.LAST)
270270
public void postProxyInitialization(ProxyInitializeEvent event) throws IllegalAccessException {
271-
((EventManagerHook) this.server.getEventManager()).reloadHandlers();
271+
this.eventManagerHook.reloadHandlers();
272272
}
273273

274274
@SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "LEGACY_AMPERSAND can't be null in velocity.")
@@ -286,9 +286,11 @@ public void reload() {
286286
this.reloadVersion();
287287
this.packets.createPackets();
288288
this.loginListener = new LoginListener(this, this.server);
289+
this.eventManagerHook = new EventManagerHook(this, this.server.getEventManager());
289290
VelocityEventManager eventManager = this.server.getEventManager();
290291
eventManager.unregisterListeners(this);
291292
eventManager.register(this, this.loginListener);
293+
eventManager.register(this, this.eventManagerHook);
292294
eventManager.register(this, new DisconnectListener(this));
293295
eventManager.register(this, new ReloadListener(this));
294296

@@ -632,6 +634,10 @@ public ProtocolVersion getPrepareMaxVersion() {
632634
return this.maxVersion;
633635
}
634636

637+
public EventManagerHook getEventManagerHook() {
638+
return this.eventManagerHook;
639+
}
640+
635641
@Override
636642
public WorldFile openWorldFile(BuiltInWorldFileType apiType, Path file) throws IOException {
637643
return WorldFileTypeRegistry.fromApiType(apiType, file);

plugin/src/main/java/net/elytrium/limboapi/Settings.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,6 @@ public static class MAIN {
8787
@Comment("Helpful if you want some plugins proceed before LimboAPI. For example, it is needed to Floodgate to replace UUID.")
8888
public List<String> PRE_LIMBO_PROFILE_REQUEST_PLUGINS = List.of("floodgate", "geyser");
8989

90-
@Comment("Regenerates listeners that need to proceed before LimboAPI on each EventManager#register call.")
91-
public boolean AUTO_REGENERATE_LISTENERS = false;
92-
9390
@Comment("Should reduced debug info be enabled (reduced information in F3) if there is no preference for Limbo")
9491
public boolean REDUCED_DEBUG_INFO = false;
9592

plugin/src/main/java/net/elytrium/limboapi/injection/event/EventManagerHook.java

Lines changed: 61 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,13 @@
1818
package net.elytrium.limboapi.injection.event;
1919

2020
import 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;
2224
import com.velocitypowered.api.event.player.GameProfileRequestEvent;
2325
import com.velocitypowered.api.event.player.KickedFromServerEvent;
2426
import com.velocitypowered.api.plugin.PluginContainer;
25-
import com.velocitypowered.api.plugin.PluginManager;
2627
import 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;
3028
import com.velocitypowered.proxy.event.VelocityEventManager;
3129
import java.lang.invoke.MethodHandle;
3230
import java.lang.invoke.MethodHandles;
@@ -46,110 +44,84 @@
4644
import 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

Comments
 (0)