diff --git a/src/main/java/net/citizensnpcs/api/ai/Navigator.java b/src/main/java/net/citizensnpcs/api/ai/Navigator.java index 52fd9d08..a5a28123 100644 --- a/src/main/java/net/citizensnpcs/api/ai/Navigator.java +++ b/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; @@ -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 strategy); /** * Sets the current navigation using a list of {@link Vector}s which will be followed in turn. @@ -118,7 +120,7 @@ public interface Navigator { * @param target * The destination */ - void setTarget(Iterable path, PathStrategy strategy); + void setTarget(Iterable path, Function strategy); /** * Sets the current navigation to a {@link Location} destination. @@ -134,5 +136,5 @@ public interface Navigator { * @param target * The destination */ - void setTarget(Location target, PathStrategy strategy); + void setTarget(Location target, Function strategy); } diff --git a/src/main/java/net/citizensnpcs/api/gui/ClickHandler.java b/src/main/java/net/citizensnpcs/api/gui/ClickHandler.java index 3aabc8ff..5fec5044 100644 --- a/src/main/java/net/citizensnpcs/api/gui/ClickHandler.java +++ b/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; @@ -12,6 +13,7 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD }) +@Repeatable(ClickHandlers.class) public @interface ClickHandler { /** * The slot position to handle clicks for. diff --git a/src/main/java/net/citizensnpcs/api/gui/ClickHandlers.java b/src/main/java/net/citizensnpcs/api/gui/ClickHandlers.java new file mode 100644 index 00000000..896cd8bc --- /dev/null +++ b/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(); +} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/api/gui/InventoryMenu.java b/src/main/java/net/citizensnpcs/api/gui/InventoryMenu.java index 0152947a..f7f70e48 100644 --- a/src/main/java/net/citizensnpcs/api/gui/InventoryMenu.java +++ b/src/main/java/net/citizensnpcs/api/gui/InventoryMenu.java @@ -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 stack = Queues.newArrayDeque(); private Collection views = Lists.newArrayList(); - public InventoryMenu(InventoryMenuInfo info) { - transition(info); + public InventoryMenu(InventoryMenuInfo info, Map context) { + transition(info, context); } private boolean acceptFilter(ClickType needle, ClickType[] haystack) { @@ -121,7 +120,7 @@ private int getInventorySize(InventoryType type, int[] dim) { dim[1] = 10; return 10; default: - throw new UnsupportedOperationException(); // TODO + throw new UnsupportedOperationException(); } } @@ -180,14 +179,14 @@ public void onInventoryClose(InventoryCloseEvent event) { } private InventoryMenuPattern parsePattern(int[] dim, List transitions, - Bindable patternInfo) { - String pattern = patternInfo.data.info.value(); + Bindable patternInfo) { + String pattern = patternInfo.data.value(); Map slotMap = Maps.newHashMap(); - for (MenuSlot slot : patternInfo.data.slots) { + for (MenuSlot slot : patternInfo.data.slots()) { slotMap.put(slot.pat(), slot); } Map transitionMap = Maps.newHashMap(); - for (MenuTransition transition : patternInfo.data.transitions) { + for (MenuTransition transition : patternInfo.data.transitions()) { transitionMap.put(transition.pat(), transition); } @@ -205,7 +204,7 @@ private InventoryMenuPattern parsePattern(int[] dim, List clazz) { + transition(clazz, Maps.newHashMap()); + } + + public void transition(Class clazz, Map 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 context) { if (page != null) { + context.putAll(page.ctx.data()); stack.add(page); } page = new PageContext(); @@ -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 slotInfo = info.slots[i]; int pos = posToIndex(dim, slotInfo.data.value()); @@ -279,7 +283,7 @@ private void transition(InventoryMenuInfo info) { transitions.add(transition); } for (int i = 0; i < info.patterns.length; i++) { - Bindable patternInfo = info.patterns[i]; + Bindable patternInfo = info.patterns[i]; InventoryMenuPattern pattern = parsePattern(dim, transitions, patternInfo); patternInfo.bind(page.page, pattern); page.patterns[i] = pattern; @@ -324,15 +328,15 @@ private static class InventoryMenuInfo { Invokable[] clickHandlers; Constructor constructor; Menu menuAnnotation; - Bindable[] patterns; + Bindable[] patterns; Bindable[] slots; Bindable[] 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" }) @@ -341,8 +345,6 @@ private Bindable[] getBindables(Class clazz, Class< List> 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) { @@ -362,8 +364,6 @@ private Bindable[] 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(null, t)); } @@ -375,90 +375,19 @@ private Bindable[] getBindables(Class clazz, Class< } @SuppressWarnings("unchecked") - private Invokable[] getHandlers(Class clazz) { + private Invokable[] getClickHandlers(Class clazz) { List> 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(handler, LOOKUP.unreflect(method))); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - return invokables.toArray(new Invokable[invokables.size()]); - } - - private Bindable getPatternBindable(MethodHandle bind, AccessibleObject object) { - MenuPattern[] annotation = object.getAnnotationsByType(MenuPattern.class); - if (annotation.length != 1) - return null; - MenuPattern pattern = annotation[0]; - Collection 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 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(bind, new MenuPatternInfo(pattern, slots, transitions)); - } - - private Bindable getPatternBindable(MethodHandle bind, Class object) { - MenuPattern[] annotation = object.getAnnotationsByType(MenuPattern.class); - if (annotation.length != 1) - return null; - MenuPattern pattern = annotation[0]; - Collection 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 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(bind, new MenuPatternInfo(pattern, slots, transitions)); - } - - @SuppressWarnings({ "unchecked" }) - private Bindable[] getPatternBindables(Class clazz) { - Collection> 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(handler, LOOKUP.unreflect(method))); } catch (IllegalAccessException e) { e.printStackTrace(); } } - bindables.add(getPatternBindable(bind, field)); - } - - List 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(); @@ -474,18 +403,6 @@ public Invokable(T data, MethodHandle invoke) { } } - private static class MenuPatternInfo { - MenuPattern info; - Collection slots = Lists.newArrayList(); - Collection transitions = Lists.newArrayList(); - - public MenuPatternInfo(MenuPattern info, Collection slots, Collection transitions) { - this.info = info; - this.slots = slots; - this.transitions = transitions; - } - } - private static class PageContext { private Invokable[] clickHandlers; private MenuContext ctx; @@ -506,18 +423,21 @@ private static void cacheInfo(Class 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 clazz) { + return createWithContext(clazz, Maps.newHashMap()); + } + + public static InventoryMenu createWithContext(Class clazz, + Map 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, InventoryMenuInfo> CACHED_INFOS = new WeakHashMap, InventoryMenuInfo>(); diff --git a/src/main/java/net/citizensnpcs/api/gui/MenuPattern.java b/src/main/java/net/citizensnpcs/api/gui/MenuPattern.java index 975b45ff..3f268c55 100644 --- a/src/main/java/net/citizensnpcs/api/gui/MenuPattern.java +++ b/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 */ diff --git a/src/main/java/net/citizensnpcs/api/gui/MenuPatterns.java b/src/main/java/net/citizensnpcs/api/gui/MenuPatterns.java new file mode 100644 index 00000000..616165a5 --- /dev/null +++ b/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(); +} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/api/gui/MenuSlot.java b/src/main/java/net/citizensnpcs/api/gui/MenuSlot.java index 390a4fb9..6bee982f 100644 --- a/src/main/java/net/citizensnpcs/api/gui/MenuSlot.java +++ b/src/main/java/net/citizensnpcs/api/gui/MenuSlot.java @@ -13,7 +13,7 @@ * Defines a slot with a certain item. Can be linked to a {@link InventoryMenuSlot} or simply at the class level. */ @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.FIELD }) +@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) @Repeatable(MenuSlots.class) public @interface MenuSlot { /** diff --git a/src/main/java/net/citizensnpcs/api/gui/MenuSlots.java b/src/main/java/net/citizensnpcs/api/gui/MenuSlots.java index 64dc2810..e8249508 100644 --- a/src/main/java/net/citizensnpcs/api/gui/MenuSlots.java +++ b/src/main/java/net/citizensnpcs/api/gui/MenuSlots.java @@ -6,7 +6,7 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.FIELD }) +@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) public @interface MenuSlots { MenuSlot[] value(); } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/api/gui/MenuTransition.java b/src/main/java/net/citizensnpcs/api/gui/MenuTransition.java index c158c8a5..22d7e952 100644 --- a/src/main/java/net/citizensnpcs/api/gui/MenuTransition.java +++ b/src/main/java/net/citizensnpcs/api/gui/MenuTransition.java @@ -13,7 +13,7 @@ * class level. */ @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.FIELD }) +@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) @Repeatable(MenuTransitions.class) public @interface MenuTransition { /** diff --git a/src/main/java/net/citizensnpcs/api/gui/MenuTransitions.java b/src/main/java/net/citizensnpcs/api/gui/MenuTransitions.java index 036ffcc0..1b0daaab 100644 --- a/src/main/java/net/citizensnpcs/api/gui/MenuTransitions.java +++ b/src/main/java/net/citizensnpcs/api/gui/MenuTransitions.java @@ -6,7 +6,7 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.FIELD }) +@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) public @interface MenuTransitions { MenuTransition[] value(); }