Update to using a newer method.

This commit is contained in:
Zontreck 2024-02-12 18:54:40 -07:00
parent fc125dfd32
commit ee629e2bc8
10 changed files with 277 additions and 9 deletions

View file

@ -1,14 +1,22 @@
package dev.zontreck.eventsbus;
import dev.zontreck.eventsbus.annotations.Priority;
import dev.zontreck.eventsbus.annotations.SingleshotEvent;
import dev.zontreck.eventsbus.annotations.Subscribe;
import dev.zontreck.eventsbus.events.EventBusReadyEvent;
import dev.zontreck.eventsbus.events.ResetEventBusEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
/**
* To be removed
* <br/>
* Use {} instead
*/
@Deprecated()
public class Bus {
/**
* The main event bus!

View file

@ -0,0 +1,93 @@
package dev.zontreck.eventsbus;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* Used internally. Do not directly invoke
* <br/>
* Accessor is set Protected intentionally!!!!!!!!!
*/
class ClassScanner {
/**
* Start the process of scanning the classes and forcing them to load in
* <br/>
* This is used by the event dispatcher
*/
protected static void DoScan() {
// Scan all classes in the classpath
Set<Class<?>> scannedClasses = scanClasses();
// Force loading of all scanned classes
for (Class<?> clazz : scannedClasses) {
try {
// Load the class
Class.forName(clazz.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
private static Set<Class<?>> scanClasses() {
String classpath = System.getProperty("java.class.path");
String[] classpathEntries = classpath.split(File.pathSeparator);
Set<Class<?>> scannedClasses = new HashSet<>();
for (String classpathEntry : classpathEntries) {
File file = new File(classpathEntry);
if (file.isDirectory()) {
scanClassesInDirectory(file, "", scannedClasses);
} else if (file.isFile() && classpathEntry.endsWith(".jar")) {
scanClassesInJar(file, scannedClasses);
}
}
return scannedClasses;
}
private static void scanClassesInDirectory(File directory, String packageName, Set<Class<?>> scannedClasses) {
File[] files = directory.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
scanClassesInDirectory(file, packageName + "." + file.getName(), scannedClasses);
} else if (file.getName().endsWith(".class")) {
String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
try {
Class<?> clazz = Class.forName(className);
scannedClasses.add(clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
private static void scanClassesInJar(File jarFile, Set<Class<?>> scannedClasses) {
try (JarFile jf = new JarFile(jarFile)) {
for (JarEntry entry : Collections.list(jf.entries())) {
if (entry.getName().endsWith(".class")) {
String className = entry.getName().replace("/", ".").substring(0, entry.getName().length() - 6);
try {
Class<?> clazz = Class.forName(className);
scannedClasses.add(clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View file

@ -1,6 +1,9 @@
package dev.zontreck.eventsbus;
import dev.zontreck.eventsbus.annotations.Cancellable;
import dev.zontreck.eventsbus.annotations.Priority;
public class Event {
private boolean cancelled = false;

View file

@ -0,0 +1,145 @@
package dev.zontreck.eventsbus;
import dev.zontreck.eventsbus.annotations.EventSubscriber;
import dev.zontreck.eventsbus.annotations.Priority;
import dev.zontreck.eventsbus.annotations.SingleshotEvent;
import dev.zontreck.eventsbus.annotations.Subscribe;
import dev.zontreck.eventsbus.events.EventBusReadyEvent;
import dev.zontreck.eventsbus.events.ResetEventBusEvent;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
public class EventDispatcher
{
private static List<Method> singleshot = new ArrayList<>();
private static List<Class<?>> subscribers = new ArrayList<>();
/**
* Scans every Java class that is currently loaded. It then checks for Subscribe, and a proper parameter before posting the Event.
* The Event will only be posted if not cancelled using {@link Event#setCancelled(boolean)} and that {@link Subscribe#allowCancelled()} allows.
* @param event The event to post
* @return True if cancelled.
*/
public static boolean Post(Event event)
{
for(PriorityLevel level : PriorityLevel.values())
{
for(Class<?> clazz : subscribers)
{
for(Method M :clazz.getMethods())
{
if(!M.isAnnotationPresent(Subscribe.class)) continue;
Subscribe subscriber = M.getAnnotation(Subscribe.class);
boolean canPost=true;
Class<?> param = M.getParameterTypes()[0];
if(param == event.getClass())
{
if(M.isAnnotationPresent(SingleshotEvent.class))
{
if(singleshot.contains(M))
{
canPost=false;
}
}
} else canPost=false;
PriorityLevel eventPriotityLevel= PriorityLevel.HIGH; // Default
if(M.isAnnotationPresent(Priority.class))
{
Priority prio = M.getAnnotation(Priority.class);
eventPriotityLevel=prio.Level();
}
if(level != eventPriotityLevel)
{
canPost=false;
}
// Dispatch the event now
try {
if(event.isCancelled() && !subscriber.allowCancelled())
continue;
else
M.invoke(null, event);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
}
return event.isCancelled();
}
/**
* Scan all event subscribers
*/
public static void Scan()
{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Package[] packages = Package.getPackages();
List<Class<?>> loaded = new ArrayList<>();
for(Package pkg : packages)
{
try{
String packageName = pkg.getName();
Field classesField = ClassLoader.class.getDeclaredField("classes");
classesField.setAccessible(true);
List<Class<?>> classes = (List<Class<?>>) classesField.get(classLoader);
for(Class<?> clazz : classes)
{
if(clazz.getPackage().getName().equalsIgnoreCase(packageName))
{
if(clazz.isAnnotationPresent(EventSubscriber.class))
loaded.add(clazz);
}
}
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
subscribers = loaded;
}
/**
* Resets the events system.
* <br/>
* This action clears the Singleshot list for the events that should only be invoked once. And rescans all classes incase new classes were dynamically loaded.
*/
public static void Reset()
{
Post(new ResetEventBusEvent());
singleshot.clear();
Scan();
ClassScanner.DoScan();
Post(new EventBusReadyEvent());
}
}

View file

@ -1,4 +1,4 @@
package dev.zontreck.eventsbus;
package dev.zontreck.eventsbus.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View file

@ -1,4 +1,4 @@
package dev.zontreck.eventsbus;
package dev.zontreck.eventsbus.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -6,7 +6,6 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.METHOD)
public @interface Subscribe {
@Target(value = ElementType.TYPE)
public @interface EventSubscriber {
}

View file

@ -1,4 +1,6 @@
package dev.zontreck.eventsbus;
package dev.zontreck.eventsbus.annotations;
import dev.zontreck.eventsbus.PriorityLevel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View file

@ -1,4 +1,4 @@
package dev.zontreck.eventsbus;
package dev.zontreck.eventsbus.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View file

@ -0,0 +1,18 @@
package dev.zontreck.eventsbus.annotations;
import dev.zontreck.eventsbus.Event;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.METHOD)
public @interface Subscribe {
/**
* Marks that the subscribed method will not receive the signal if the event was cancelled with {@link Event#setCancelled(boolean)}
*/
boolean allowCancelled();
}

View file

@ -1,6 +1,6 @@
package dev.zontreck.eventsbus.events;
import dev.zontreck.eventsbus.Cancellable;
import dev.zontreck.eventsbus.annotations.Cancellable;
import dev.zontreck.eventsbus.Event;
/**