Fixed EventManager and NetworkClient
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -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>
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user