diff --git a/pom.xml b/pom.xml index 5576082..aad9dfc 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ dev.unlegitdqrk unlegitlibrary - 1.7.8 + 1.7.9 https://unlegitdqrk.dev/ Just a big library diff --git a/src/main/java/dev/unlegitdqrk/unlegitlibrary/event/EventManager.java b/src/main/java/dev/unlegitdqrk/unlegitlibrary/event/EventManager.java index 6417439..12859b3 100644 --- a/src/main/java/dev/unlegitdqrk/unlegitlibrary/event/EventManager.java +++ b/src/main/java/dev/unlegitdqrk/unlegitlibrary/event/EventManager.java @@ -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, Map>> registeredListener = new HashMap<>(); - private final Map, Object> eventListeners = new HashMap<>(); + // eventClass -> priority -> listenerInstance -> method + private final Map, Map>> registeredListener = + new ConcurrentHashMap<>(); - public void registerListener(Class listenerClass) throws Exception { - if (isListenerRegistered(listenerClass)) return; + // listenerClass -> set of listener instances (identity-based) + private final Map, Set> 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 listenerClass = listenerInstance.getClass(); - if (isListenerRegistered(listenerClass)) return; - - registerListenerInstance(listenerInstance); + public void registerListener(Class 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 eventClass = (Class) 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 eventClass = (Class) 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 clazz) { + if (clazz == null) return; + + Set 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 instances = eventListeners.get(listener.getClass()); + if (instances != null) { + instances.remove(listener); + if (instances.isEmpty()) eventListeners.remove(listener.getClass()); } - eventListeners.put((Class) instance.getClass(), instance); - } - - public synchronized void unregisterListener(Class listenerClass) { - if (!isListenerRegistered(listenerClass)) return; - - Object instance = eventListeners.get(listenerClass); - - for (Map> priorityMap : registeredListener.values()) { - for (Map listeners : priorityMap.values()) { - listeners.remove(instance); + for (Map> byPriority : registeredListener.values()) { + for (Map 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 listenerClass) { - return eventListeners.containsKey(listenerClass); + public boolean isListenerRegistered(Class clazz) { + Set instances = eventListeners.get(clazz); + return instances != null && !instances.isEmpty(); } public void executeEvent(Event event) { - Map> listenersByPriority = registeredListener.get(event.getClass()); - if (listenersByPriority == null) return; + if (event == null) return; + + Map> byPriority = registeredListener.get(event.getClass()); + if (byPriority == null) return; for (EventPriority priority : EventPriority.values()) { - Map listeners = listenersByPriority.getOrDefault(priority, Collections.emptyMap()); - + Map listeners = byPriority.getOrDefault(priority, Collections.emptyMap()); for (Map.Entry 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(); } } } } -} - +} \ No newline at end of file diff --git a/src/main/java/dev/unlegitdqrk/unlegitlibrary/network/system/client/NetworkClient.java b/src/main/java/dev/unlegitdqrk/unlegitlibrary/network/system/client/NetworkClient.java index 33fd78e..092a03f 100644 --- a/src/main/java/dev/unlegitdqrk/unlegitlibrary/network/system/client/NetworkClient.java +++ b/src/main/java/dev/unlegitdqrk/unlegitlibrary/network/system/client/NetworkClient.java @@ -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() { diff --git a/src/main/java/dev/unlegitdqrk/unlegitlibrary/network/system/server/NetworkServer.java b/src/main/java/dev/unlegitdqrk/unlegitlibrary/network/system/server/NetworkServer.java index 6f87394..47db799 100644 --- a/src/main/java/dev/unlegitdqrk/unlegitlibrary/network/system/server/NetworkServer.java +++ b/src/main/java/dev/unlegitdqrk/unlegitlibrary/network/system/server/NetworkServer.java @@ -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;