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