forked from SteamWar/SteamWar
Allow @Linked on fields
The value of a @Linked field of a linked class is linked like a linked class itself, e.g. registered as listener, and unlinked again on unlink. The field has to be initialised when linking. HullHiderCommand and TPSSystem use it instead of registering their listeners by hand.
This commit is contained in:
@@ -28,6 +28,7 @@ import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -38,6 +39,7 @@ public abstract class AbstractLinker<T> {
|
||||
|
||||
protected final T plugin;
|
||||
private Map<Class<?>, Object> instances = new HashMap<>();
|
||||
private final List<Object> fieldInstances = new ArrayList<>();
|
||||
|
||||
protected AbstractLinker(@NonNull T plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -90,6 +92,7 @@ public abstract class AbstractLinker<T> {
|
||||
((Enable) any).enable();
|
||||
}
|
||||
linkObject(any);
|
||||
linkFields(any);
|
||||
});
|
||||
} catch (SecurityException e) {
|
||||
Throwable cause = e.getCause();
|
||||
@@ -119,6 +122,31 @@ public abstract class AbstractLinker<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private void linkFields(Object any) {
|
||||
for (Field field : any.getClass().getDeclaredFields()) {
|
||||
if (field.getAnnotation(Linked.class) == null) continue;
|
||||
|
||||
Object value;
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
value = field.get(Modifier.isStatic(field.getModifiers()) ? null : any);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new SecurityException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
String message = "Linked field " + any.getClass().getName() + "." + field.getName() + " is not initialised";
|
||||
throw new SecurityException(message, new IllegalStateException(message));
|
||||
}
|
||||
|
||||
fieldInstances.add(value);
|
||||
if (value instanceof Enable) {
|
||||
((Enable) value).enable();
|
||||
}
|
||||
linkObject(value);
|
||||
}
|
||||
}
|
||||
|
||||
public final void unlink() {
|
||||
instances.forEach((aClass, any) -> {
|
||||
unlinkObject(any);
|
||||
@@ -126,6 +154,12 @@ public abstract class AbstractLinker<T> {
|
||||
((Disable) any).disable();
|
||||
}
|
||||
});
|
||||
fieldInstances.forEach(any -> {
|
||||
unlinkObject(any);
|
||||
if (any instanceof Disable) {
|
||||
((Disable) any).disable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public final void addLinkableInstance(@NonNull Object instance) {
|
||||
|
||||
@@ -26,8 +26,12 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* On a class: the class is instantiated and linked.
|
||||
* On a field of a linked class: the (already initialised) value of the field is linked as well, e.g. registered as listener.
|
||||
*/
|
||||
@IndexAnnotated
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
public @interface Linked {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user