Skip to content

Commit

Permalink
Further GUI work, tweak navigator API
Browse files Browse the repository at this point in the history
  • Loading branch information
fullwall committed Jan 27, 2021
1 parent 2d2209e commit f4d678c
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 121 deletions.
8 changes: 5 additions & 3 deletions src/main/java/net/citizensnpcs/api/ai/Navigator.java
@@ -1,5 +1,7 @@
package net.citizensnpcs.api.ai;

import java.util.function.Function;

import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
Expand Down Expand Up @@ -102,7 +104,7 @@ public interface Navigator {
* @param aggressive
* Whether to attack the target when close enough
*/
void setTarget(Entity target, boolean aggressive, PathStrategy strategy);
void setTarget(Entity target, boolean aggressive, Function<NavigatorParameters, PathStrategy> strategy);

/**
* Sets the current navigation using a list of {@link Vector}s which will be followed in turn.
Expand All @@ -118,7 +120,7 @@ public interface Navigator {
* @param target
* The destination
*/
void setTarget(Iterable<Vector> path, PathStrategy strategy);
void setTarget(Iterable<Vector> path, Function<NavigatorParameters, PathStrategy> strategy);

/**
* Sets the current navigation to a {@link Location} destination.
Expand All @@ -134,5 +136,5 @@ public interface Navigator {
* @param target
* The destination
*/
void setTarget(Location target, PathStrategy strategy);
void setTarget(Location target, Function<NavigatorParameters, PathStrategy> strategy);
}
2 changes: 2 additions & 0 deletions src/main/java/net/citizensnpcs/api/gui/ClickHandler.java
@@ -1,6 +1,7 @@
package net.citizensnpcs.api.gui;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
Expand All @@ -12,6 +13,7 @@
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
@Repeatable(ClickHandlers.class)
public @interface ClickHandler {
/**
* The slot position to handle clicks for.
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/net/citizensnpcs/api/gui/ClickHandlers.java
@@ -0,0 +1,12 @@
package net.citizensnpcs.api.gui;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface ClickHandlers {
ClickHandler[] value();
}
144 changes: 32 additions & 112 deletions src/main/java/net/citizensnpcs/api/gui/InventoryMenu.java
Expand Up @@ -26,19 +26,18 @@
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;

import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Queues;

// TODO: injection, documentation
public class InventoryMenu implements Listener {
private PageContext page;
private final Queue<PageContext> stack = Queues.newArrayDeque();
private Collection<InventoryView> views = Lists.newArrayList();

public InventoryMenu(InventoryMenuInfo info) {
transition(info);
public InventoryMenu(InventoryMenuInfo info, Map<String, Object> context) {
transition(info, context);
}

private boolean acceptFilter(ClickType needle, ClickType[] haystack) {
Expand Down Expand Up @@ -121,7 +120,7 @@ private int getInventorySize(InventoryType type, int[] dim) {
dim[1] = 10;
return 10;
default:
throw new UnsupportedOperationException(); // TODO
throw new UnsupportedOperationException();
}
}

Expand Down Expand Up @@ -180,14 +179,14 @@ public void onInventoryClose(InventoryCloseEvent event) {
}

private InventoryMenuPattern parsePattern(int[] dim, List<InventoryMenuTransition> transitions,
Bindable<MenuPatternInfo> patternInfo) {
String pattern = patternInfo.data.info.value();
Bindable<MenuPattern> patternInfo) {
String pattern = patternInfo.data.value();
Map<Character, MenuSlot> slotMap = Maps.newHashMap();
for (MenuSlot slot : patternInfo.data.slots) {
for (MenuSlot slot : patternInfo.data.slots()) {
slotMap.put(slot.pat(), slot);
}
Map<Character, MenuTransition> transitionMap = Maps.newHashMap();
for (MenuTransition transition : patternInfo.data.transitions) {
for (MenuTransition transition : patternInfo.data.transitions()) {
transitionMap.put(transition.pat(), transition);
}

Expand All @@ -205,7 +204,7 @@ private InventoryMenuPattern parsePattern(int[] dim, List<InventoryMenuTransitio
col = 0;
continue;
}
int[] pos = patternInfo.data.info.offset();
int[] pos = patternInfo.data.offset();
pos[0] += row;
pos[1] += col;

Expand All @@ -222,7 +221,7 @@ private InventoryMenuPattern parsePattern(int[] dim, List<InventoryMenuTransitio
col++;
}

return new InventoryMenuPattern(patternInfo.data.info, patternSlots, patternTransitions);
return new InventoryMenuPattern(patternInfo.data, patternSlots, patternTransitions);
}

private int posToIndex(int[] dim, int[] pos) {
Expand All @@ -235,14 +234,19 @@ public void present(Player player) {
}

public void transition(Class<? extends InventoryMenuPage> clazz) {
transition(clazz, Maps.newHashMap());
}

public void transition(Class<? extends InventoryMenuPage> clazz, Map<String, Object> context) {
if (!CACHED_INFOS.containsKey(clazz)) {
cacheInfo(clazz);
}
transition(CACHED_INFOS.get(clazz));
transition(CACHED_INFOS.get(clazz), context);
}

private void transition(InventoryMenuInfo info) {
private void transition(InventoryMenuInfo info, Map<String, Object> context) {
if (page != null) {
context.putAll(page.ctx.data());
stack.add(page);
}
page = new PageContext();
Expand All @@ -264,7 +268,7 @@ private void transition(InventoryMenuInfo info) {
throw new RuntimeException(e);
}
page.dim = dim;
page.ctx = new MenuContext(this, slots, inventory);
page.ctx = new MenuContext(this, slots, inventory, context);
for (int i = 0; i < info.slots.length; i++) {
Bindable<MenuSlot> slotInfo = info.slots[i];
int pos = posToIndex(dim, slotInfo.data.value());
Expand All @@ -279,7 +283,7 @@ private void transition(InventoryMenuInfo info) {
transitions.add(transition);
}
for (int i = 0; i < info.patterns.length; i++) {
Bindable<MenuPatternInfo> patternInfo = info.patterns[i];
Bindable<MenuPattern> patternInfo = info.patterns[i];
InventoryMenuPattern pattern = parsePattern(dim, transitions, patternInfo);
patternInfo.bind(page.page, pattern);
page.patterns[i] = pattern;
Expand Down Expand Up @@ -324,15 +328,15 @@ private static class InventoryMenuInfo {
Invokable<ClickHandler>[] clickHandlers;
Constructor<? extends InventoryMenuPage> constructor;
Menu menuAnnotation;
Bindable<MenuPatternInfo>[] patterns;
Bindable<MenuPattern>[] patterns;
Bindable<MenuSlot>[] slots;
Bindable<MenuTransition>[] transitions;

public InventoryMenuInfo(Class<?> clazz) {
patterns = getPatternBindables(clazz);
patterns = getBindables(clazz, MenuPattern.class, InventoryMenuPattern.class);
slots = getBindables(clazz, MenuSlot.class, InventoryMenuSlot.class);
transitions = getBindables(clazz, MenuTransition.class, InventoryMenuTransition.class);
clickHandlers = getHandlers(clazz);
clickHandlers = getClickHandlers(clazz);
}

@SuppressWarnings({ "unchecked" })
Expand All @@ -341,8 +345,6 @@ private <T extends Annotation> Bindable<T>[] getBindables(Class<?> clazz, Class<
List<Bindable<T>> bindables = Lists.newArrayList();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
if (field.getAnnotationsByType(MenuPattern.class).length != 0)
continue;
T[] annotations = field.getAnnotationsByType(annotationType);
MethodHandle bind = null;
if (field.getType() == concreteType) {
Expand All @@ -362,8 +364,6 @@ private <T extends Annotation> Bindable<T>[] getBindables(Class<?> clazz, Class<
reflect.addAll(Arrays.asList(clazz.getDeclaredMethods()));
for (AccessibleObject object : reflect) {
object.setAccessible(true);
if (object.getAnnotationsByType(MenuPattern.class).length != 0)
continue;
for (T t : object.getAnnotationsByType(annotationType)) {
bindables.add(new Bindable<T>(null, t));
}
Expand All @@ -375,90 +375,19 @@ private <T extends Annotation> Bindable<T>[] getBindables(Class<?> clazz, Class<
}

@SuppressWarnings("unchecked")
private Invokable<ClickHandler>[] getHandlers(Class<?> clazz) {
private Invokable<ClickHandler>[] getClickHandlers(Class<?> clazz) {
List<Invokable<ClickHandler>> invokables = Lists.newArrayList();
for (Method method : clazz.getDeclaredMethods()) {
method.setAccessible(true);
ClickHandler handler = method.getAnnotation(ClickHandler.class);
if (handler == null) {
continue;
}
try {
invokables.add(new Invokable<ClickHandler>(handler, LOOKUP.unreflect(method)));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return invokables.toArray(new Invokable[invokables.size()]);
}

private Bindable<MenuPatternInfo> getPatternBindable(MethodHandle bind, AccessibleObject object) {
MenuPattern[] annotation = object.getAnnotationsByType(MenuPattern.class);
if (annotation.length != 1)
return null;
MenuPattern pattern = annotation[0];
Collection<MenuSlot> slots = Lists.newArrayList();
for (MenuSlot slot : object.getAnnotationsByType(MenuSlot.class)) {
if (slot.pat() != '0' && pattern.value().contains(Character.toString(slot.pat()))) {
slots.add(slot);
}
}
Collection<MenuTransition> transitions = Lists.newArrayList();
for (MenuTransition transition : object.getAnnotationsByType(MenuTransition.class)) {
if (transition.pat() != '0' && pattern.value().contains(Character.toString(transition.pat()))) {
transitions.add(transition);
}
}
return new Bindable<MenuPatternInfo>(bind, new MenuPatternInfo(pattern, slots, transitions));
}

private Bindable<MenuPatternInfo> getPatternBindable(MethodHandle bind, Class<?> object) {
MenuPattern[] annotation = object.getAnnotationsByType(MenuPattern.class);
if (annotation.length != 1)
return null;
MenuPattern pattern = annotation[0];
Collection<MenuSlot> slots = Lists.newArrayList();
for (MenuSlot slot : object.getAnnotationsByType(MenuSlot.class)) {
if (slot.pat() != '0' && pattern.value().contains(Character.toString(slot.pat()))) {
slots.add(slot);
}
}
Collection<MenuTransition> transitions = Lists.newArrayList();
for (MenuTransition transition : object.getAnnotationsByType(MenuTransition.class)) {
if (transition.pat() != '0' && pattern.value().contains(Character.toString(transition.pat()))) {
transitions.add(transition);
}
}
return new Bindable<MenuPatternInfo>(bind, new MenuPatternInfo(pattern, slots, transitions));
}

@SuppressWarnings({ "unchecked" })
private Bindable<MenuPatternInfo>[] getPatternBindables(Class<?> clazz) {
Collection<Bindable<MenuPatternInfo>> bindables = Lists.newArrayList();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
MethodHandle bind = null;
if (field.getType() == InventoryMenuPattern.class) {
for (ClickHandler handler : method.getAnnotationsByType(ClickHandler.class)) {
try {
bind = LOOKUP.unreflectSetter(field);
invokables.add(new Invokable<ClickHandler>(handler, LOOKUP.unreflect(method)));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
bindables.add(getPatternBindable(bind, field));
}

List<AccessibleObject> reflect = Lists.newArrayList();
reflect.addAll(Arrays.asList(clazz.getDeclaredConstructors()));
reflect.addAll(Arrays.asList(clazz.getDeclaredMethods()));
for (AccessibleObject object : reflect) {
object.setAccessible(true);
if (object.getAnnotationsByType(MenuPattern.class).length != 0)
continue;
bindables.add(getPatternBindable(null, object));
}
bindables.add(getPatternBindable(null, clazz));
return Collections2.filter(bindables, Predicates.notNull()).toArray(new Bindable[0]);
return invokables.toArray(new Invokable[invokables.size()]);
}

private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
Expand All @@ -474,18 +403,6 @@ public Invokable(T data, MethodHandle invoke) {
}
}

private static class MenuPatternInfo {
MenuPattern info;
Collection<MenuSlot> slots = Lists.newArrayList();
Collection<MenuTransition> transitions = Lists.newArrayList();

public MenuPatternInfo(MenuPattern info, Collection<MenuSlot> slots, Collection<MenuTransition> transitions) {
this.info = info;
this.slots = slots;
this.transitions = transitions;
}
}

private static class PageContext {
private Invokable<ClickHandler>[] clickHandlers;
private MenuContext ctx;
Expand All @@ -506,18 +423,21 @@ private static void cacheInfo(Class<? extends InventoryMenuPage> clazz) {
found.setAccessible(true);
info.constructor = found;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
CACHED_INFOS.put(clazz, info);
}

public static InventoryMenu create(Class<? extends InventoryMenuPage> clazz) {
return createWithContext(clazz, Maps.newHashMap());
}

public static InventoryMenu createWithContext(Class<? extends InventoryMenuPage> clazz,
Map<String, Object> context) {
if (!CACHED_INFOS.containsKey(clazz)) {
cacheInfo(clazz);
}
InventoryMenuInfo info = CACHED_INFOS.get(clazz);
return new InventoryMenu(info);
return new InventoryMenu(CACHED_INFOS.get(clazz), context);
}

private static Map<Class<? extends InventoryMenuPage>, InventoryMenuInfo> CACHED_INFOS = new WeakHashMap<Class<? extends InventoryMenuPage>, InventoryMenuInfo>();
Expand Down
11 changes: 9 additions & 2 deletions src/main/java/net/citizensnpcs/api/gui/MenuPattern.java
@@ -1,21 +1,28 @@
package net.citizensnpcs.api.gui;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Defines a pattern of slots. Can be linked to a {@link InventoryMenuPattern} or simply at the class level.
* Defines a pattern of slots and/or transitions. Can be linked to a {@link InventoryMenuPattern} or simply at the class
* level.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.FIELD })
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD })
@Repeatable(MenuPatterns.class)
public @interface MenuPattern {
/**
* The offset position to start the pattern at.
*/
int[] offset();

MenuSlot[] slots() default {};

MenuTransition[] transitions() default {};

/**
* The pattern string. 0 = AIR
*/
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/net/citizensnpcs/api/gui/MenuPatterns.java
@@ -0,0 +1,12 @@
package net.citizensnpcs.api.gui;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD })
public @interface MenuPatterns {
MenuPattern[] value();
}

0 comments on commit f4d678c

Please sign in to comment.