Fixed EventManager and NetworkClient

This commit is contained in:
Finn
2026-02-01 19:01:54 +01:00
parent b25e20b150
commit e40d51a894
4 changed files with 107 additions and 65 deletions

View File

@@ -6,7 +6,7 @@
<groupId>dev.unlegitdqrk</groupId> <groupId>dev.unlegitdqrk</groupId>
<artifactId>unlegitlibrary</artifactId> <artifactId>unlegitlibrary</artifactId>
<version>1.7.8</version> <version>1.7.9</version>
<url>https://unlegitdqrk.dev/</url> <url>https://unlegitdqrk.dev/</url>
<description>Just a big library</description> <description>Just a big library</description>

View File

@@ -1,96 +1,120 @@
package dev.unlegitdqrk.unlegitlibrary.event; package dev.unlegitdqrk.unlegitlibrary.event;
import dev.unlegitdqrk.unlegitlibrary.event.impl.Event; import dev.unlegitdqrk.unlegitlibrary.event.impl.Event;
import dev.unlegitdqrk.unlegitlibrary.utils.DefaultMethodsOverrider;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collections; import java.util.*;
import java.util.EnumMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
import java.util.Map;
public final class EventManager extends DefaultMethodsOverrider { public final class EventManager {
private final Map<Class<? extends Event>, Map<EventPriority, Map<Object, Method>>> registeredListener = new HashMap<>(); // eventClass -> priority -> listenerInstance -> method
private final Map<Class<? extends EventListener>, Object> eventListeners = new HashMap<>(); private final Map<Class<? extends Event>, Map<EventPriority, Map<Object, Method>>> registeredListener =
new ConcurrentHashMap<>();
public void registerListener(Class<? extends EventListener> listenerClass) throws Exception { // listenerClass -> set of listener instances (identity-based)
if (isListenerRegistered(listenerClass)) return; private final Map<Class<? extends EventListener>, Set<EventListener>> eventListeners =
new ConcurrentHashMap<>();
EventListener instance = listenerClass.getDeclaredConstructor().newInstance(); public EventManager() {
registerListenerInstance(instance);
} }
public void registerListener(EventListener listenerInstance) { public void registerListener(Class<? extends EventListener> clazz) throws Exception {
if (listenerInstance == null) throw new IllegalArgumentException("Listener instance cannot be null"); if (clazz == null) throw new IllegalArgumentException("Listener class cannot be null");
Class<? extends EventListener> listenerClass = listenerInstance.getClass(); EventListener instance = clazz.getDeclaredConstructor().newInstance();
if (isListenerRegistered(listenerClass)) return; registerListener(instance);
registerListenerInstance(listenerInstance);
} }
private void registerListenerInstance(Object instance) { public void registerListener(EventListener listener) {
for (Method method : instance.getClass().getDeclaredMethods()) { if (listener == null) throw new IllegalArgumentException("Listener instance cannot be null");
Listener listenerAnnotation = method.getAnnotation(Listener.class);
if (listenerAnnotation == null || method.getParameterCount() != 1) continue; // Track instance set for class (identity-based)
eventListeners
.computeIfAbsent(listener.getClass(), k -> Collections.newSetFromMap(new IdentityHashMap<>()))
.add(listener);
Class<?> paramType = method.getParameterTypes()[0]; registerListenerInstance(listener);
if (!Event.class.isAssignableFrom(paramType)) continue; }
@SuppressWarnings("unchecked") private void registerListenerInstance(Object listener) {
Class<? extends Event> eventClass = (Class<? extends Event>) paramType; // Walk up class hierarchy so superclass @Listener methods are registered too
for (Class<?> c = listener.getClass(); c != null && c != Object.class; c = c.getSuperclass()) {
Method[] methods = c.getDeclaredMethods();
registeredListener for (Method method : methods) {
.computeIfAbsent(eventClass, k -> new EnumMap<>(EventPriority.class)) Listener annotation = method.getAnnotation(Listener.class);
.computeIfAbsent(listenerAnnotation.priority(), k -> new HashMap<>()) if (annotation == null) continue;
.put(instance, method);
if (method.getParameterCount() != 1) continue;
Class<?> param = method.getParameterTypes()[0];
if (!Event.class.isAssignableFrom(param)) continue;
@SuppressWarnings("unchecked")
Class<? extends Event> eventClass = (Class<? extends Event>) param;
registeredListener
.computeIfAbsent(eventClass, k -> new EnumMap<>(EventPriority.class))
.computeIfAbsent(annotation.priority(), k -> Collections.synchronizedMap(new IdentityHashMap<>()))
.put(listener, method);
}
}
}
public synchronized void unregisterListener(Class<? extends EventListener> clazz) {
if (clazz == null) return;
Set<EventListener> instances = eventListeners.remove(clazz);
if (instances == null || instances.isEmpty()) return;
for (EventListener instance : instances) {
unregisterListener(instance);
}
}
public synchronized void unregisterListener(EventListener listener) {
if (listener == null) return;
Set<EventListener> instances = eventListeners.get(listener.getClass());
if (instances != null) {
instances.remove(listener);
if (instances.isEmpty()) eventListeners.remove(listener.getClass());
} }
eventListeners.put((Class<? extends EventListener>) instance.getClass(), instance); for (Map<EventPriority, Map<Object, Method>> byPriority : registeredListener.values()) {
} for (Map<Object, Method> listeners : byPriority.values()) {
listeners.remove(listener);
public synchronized void unregisterListener(Class<? extends EventListener> listenerClass) {
if (!isListenerRegistered(listenerClass)) return;
Object instance = eventListeners.get(listenerClass);
for (Map<EventPriority, Map<Object, Method>> priorityMap : registeredListener.values()) {
for (Map<Object, Method> listeners : priorityMap.values()) {
listeners.remove(instance);
} }
} }
// cleanup empty maps
registeredListener.entrySet().removeIf(e -> registeredListener.entrySet().removeIf(e ->
e.getValue().values().stream().allMatch(Map::isEmpty)); e.getValue().values().stream().allMatch(Map::isEmpty)
);
eventListeners.remove(listenerClass);
} }
public boolean isListenerRegistered(Class<? extends EventListener> listenerClass) { public boolean isListenerRegistered(Class<? extends EventListener> clazz) {
return eventListeners.containsKey(listenerClass); Set<EventListener> instances = eventListeners.get(clazz);
return instances != null && !instances.isEmpty();
} }
public void executeEvent(Event event) { public void executeEvent(Event event) {
Map<EventPriority, Map<Object, Method>> listenersByPriority = registeredListener.get(event.getClass()); if (event == null) return;
if (listenersByPriority == null) return;
Map<EventPriority, Map<Object, Method>> byPriority = registeredListener.get(event.getClass());
if (byPriority == null) return;
for (EventPriority priority : EventPriority.values()) { for (EventPriority priority : EventPriority.values()) {
Map<Object, Method> listeners = listenersByPriority.getOrDefault(priority, Collections.emptyMap()); Map<Object, Method> listeners = byPriority.getOrDefault(priority, Collections.emptyMap());
for (Map.Entry<Object, Method> entry : listeners.entrySet()) { for (Map.Entry<Object, Method> entry : listeners.entrySet()) {
Object instance = entry.getKey();
Method method = entry.getValue();
try { try {
Method method = entry.getValue();
method.setAccessible(true); method.setAccessible(true);
method.invoke(instance, event); method.invoke(entry.getKey(), event);
} catch (IllegalAccessException | InvocationTargetException e) { } catch (ReflectiveOperationException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
} }
} }

View File

@@ -153,8 +153,7 @@ public class NetworkClient {
Thread.sleep(5); Thread.sleep(5);
} }
Thread.sleep(10); Thread.sleep(100);
eventManager.executeEvent(new ClientConnectedEvent(this));
} }
private void tcpReceive() { private void tcpReceive() {
@@ -177,11 +176,18 @@ public class NetworkClient {
} }
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
disconnect(); disconnect();
} }
} }
private void connectUDP() throws Exception { private void connectUDP() throws Exception {
if (!isUDPEnabled()) {
Thread.sleep(1000);
eventManager.executeEvent(new ClientConnectedEvent(this));
return;
}
udpChannel = DatagramChannel.open(); udpChannel = DatagramChannel.open();
udpChannel.connect(new InetSocketAddress(host, udpPort)); udpChannel.connect(new InetSocketAddress(host, udpPort));
udpReceiveThread.start(); udpReceiveThread.start();
@@ -195,6 +201,9 @@ public class NetworkClient {
ByteBuffer buffer = UdpCrypto.encrypt(udpKey, baos.toByteArray(), null); ByteBuffer buffer = UdpCrypto.encrypt(udpKey, baos.toByteArray(), null);
udpChannel.write(buffer); udpChannel.write(buffer);
Thread.sleep(1000);
eventManager.executeEvent(new ClientConnectedEvent(this));
} }
private void udpReceive() { private void udpReceive() {

View File

@@ -186,18 +186,27 @@ public class NetworkServer {
sslSocket.startHandshake(); sslSocket.startHandshake();
} }
ConnectedClient client = new ConnectedClient(this, socket, UUID.randomUUID(), udpPort); UUID uuid = generateUUID();
while (uuid == null) Thread.sleep(5);
ConnectedClient client = new ConnectedClient(this, socket, uuid, udpPort);
if (isUDPEnabled()) client.setUdpChannel(udpChannel); if (isUDPEnabled()) client.setUdpChannel(udpChannel);
Thread.sleep(100); Thread.sleep(300);
eventManager.executeEvent(new S_ClientConnectedEvent(this, client)); if (client.isTCPConnected() && client.getUniqueID() != null)
eventManager.executeEvent(new S_ClientConnectedEvent(this, client));
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
break; break;
} }
} }
} }
private UUID generateUUID() {
UUID uuid = UUID.randomUUID();
if (getClientByUuid(uuid) != null) return generateUUID();
return uuid;
}
private void udpReceiveLoop() { private void udpReceiveLoop() {
ByteBuffer buffer = ByteBuffer.allocate(65536); ByteBuffer buffer = ByteBuffer.allocate(65536);
while (!Thread.currentThread().isInterrupted()) { while (!Thread.currentThread().isInterrupted()) {
@@ -290,7 +299,7 @@ public class NetworkServer {
return socket.get(); return socket.get();
} }
private ConnectedClient getClientByUuid(UUID uuid) { public ConnectedClient getClientByUuid(UUID uuid) {
synchronized (connectedClients) { synchronized (connectedClients) {
for (ConnectedClient client : connectedClients) { for (ConnectedClient client : connectedClients) {
if (uuid.equals(client.getUniqueID())) return client; if (uuid.equals(client.getUniqueID())) return client;