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>
<artifactId>unlegitlibrary</artifactId>
<version>1.7.8</version>
<version>1.7.9</version>
<url>https://unlegitdqrk.dev/</url>
<description>Just a big library</description>

View File

@@ -1,96 +1,120 @@
package dev.unlegitdqrk.unlegitlibrary.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.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public final class EventManager extends DefaultMethodsOverrider {
public final class EventManager {
private final Map<Class<? extends Event>, Map<EventPriority, Map<Object, Method>>> registeredListener = new HashMap<>();
private final Map<Class<? extends EventListener>, Object> eventListeners = new HashMap<>();
// eventClass -> priority -> listenerInstance -> method
private final Map<Class<? extends Event>, Map<EventPriority, Map<Object, Method>>> registeredListener =
new ConcurrentHashMap<>();
public void registerListener(Class<? extends EventListener> listenerClass) throws Exception {
if (isListenerRegistered(listenerClass)) return;
// listenerClass -> set of listener instances (identity-based)
private final Map<Class<? extends EventListener>, Set<EventListener>> eventListeners =
new ConcurrentHashMap<>();
EventListener instance = listenerClass.getDeclaredConstructor().newInstance();
registerListenerInstance(instance);
public EventManager() {
}
public void registerListener(EventListener listenerInstance) {
if (listenerInstance == null) throw new IllegalArgumentException("Listener instance cannot be null");
Class<? extends EventListener> listenerClass = listenerInstance.getClass();
if (isListenerRegistered(listenerClass)) return;
registerListenerInstance(listenerInstance);
public void registerListener(Class<? extends EventListener> clazz) throws Exception {
if (clazz == null) throw new IllegalArgumentException("Listener class cannot be null");
EventListener instance = clazz.getDeclaredConstructor().newInstance();
registerListener(instance);
}
private void registerListenerInstance(Object instance) {
for (Method method : instance.getClass().getDeclaredMethods()) {
Listener listenerAnnotation = method.getAnnotation(Listener.class);
public void registerListener(EventListener listener) {
if (listener == null) throw new IllegalArgumentException("Listener instance cannot be null");
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];
if (!Event.class.isAssignableFrom(paramType)) continue;
registerListenerInstance(listener);
}
@SuppressWarnings("unchecked")
Class<? extends Event> eventClass = (Class<? extends Event>) paramType;
private void registerListenerInstance(Object listener) {
// 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
.computeIfAbsent(eventClass, k -> new EnumMap<>(EventPriority.class))
.computeIfAbsent(listenerAnnotation.priority(), k -> new HashMap<>())
.put(instance, method);
for (Method method : methods) {
Listener annotation = method.getAnnotation(Listener.class);
if (annotation == null) continue;
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);
}
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);
for (Map<EventPriority, Map<Object, Method>> byPriority : registeredListener.values()) {
for (Map<Object, Method> listeners : byPriority.values()) {
listeners.remove(listener);
}
}
// cleanup empty maps
registeredListener.entrySet().removeIf(e ->
e.getValue().values().stream().allMatch(Map::isEmpty));
eventListeners.remove(listenerClass);
e.getValue().values().stream().allMatch(Map::isEmpty)
);
}
public boolean isListenerRegistered(Class<? extends EventListener> listenerClass) {
return eventListeners.containsKey(listenerClass);
public boolean isListenerRegistered(Class<? extends EventListener> clazz) {
Set<EventListener> instances = eventListeners.get(clazz);
return instances != null && !instances.isEmpty();
}
public void executeEvent(Event event) {
Map<EventPriority, Map<Object, Method>> listenersByPriority = registeredListener.get(event.getClass());
if (listenersByPriority == null) return;
if (event == null) return;
Map<EventPriority, Map<Object, Method>> byPriority = registeredListener.get(event.getClass());
if (byPriority == null) return;
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()) {
Object instance = entry.getKey();
Method method = entry.getValue();
try {
Method method = entry.getValue();
method.setAccessible(true);
method.invoke(instance, event);
} catch (IllegalAccessException | InvocationTargetException e) {
method.invoke(entry.getKey(), event);
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
}
}
}
}

View File

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

View File

@@ -186,18 +186,27 @@ public class NetworkServer {
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);
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) {
break;
}
}
}
private UUID generateUUID() {
UUID uuid = UUID.randomUUID();
if (getClientByUuid(uuid) != null) return generateUUID();
return uuid;
}
private void udpReceiveLoop() {
ByteBuffer buffer = ByteBuffer.allocate(65536);
while (!Thread.currentThread().isInterrupted()) {
@@ -290,7 +299,7 @@ public class NetworkServer {
return socket.get();
}
private ConnectedClient getClientByUuid(UUID uuid) {
public ConnectedClient getClientByUuid(UUID uuid) {
synchronized (connectedClients) {
for (ConnectedClient client : connectedClients) {
if (uuid.equals(client.getUniqueID())) return client;