EventFactory.java 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * This file is part of architectury.
  3. * Copyright (C) 2020, 2021 shedaniel
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 3 of the License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public License
  16. * along with this program; if not, write to the Free Software Foundation,
  17. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. package me.shedaniel.architectury.event;
  20. import com.google.common.reflect.AbstractInvocationHandler;
  21. import me.shedaniel.architectury.ForgeEvent;
  22. import me.shedaniel.architectury.ForgeEventCancellable;
  23. import me.shedaniel.architectury.annotations.ExpectPlatform;
  24. import net.jodah.typetools.TypeResolver;
  25. import net.minecraft.world.InteractionResult;
  26. import net.minecraft.world.InteractionResultHolder;
  27. import org.jetbrains.annotations.ApiStatus;
  28. import org.jetbrains.annotations.NotNull;
  29. import java.lang.reflect.Array;
  30. import java.lang.reflect.Method;
  31. import java.lang.reflect.Proxy;
  32. import java.util.ArrayList;
  33. import java.util.List;
  34. import java.util.Objects;
  35. import java.util.function.Consumer;
  36. import java.util.function.Function;
  37. public final class EventFactory {
  38. private EventFactory() {}
  39. @Deprecated
  40. @ApiStatus.ScheduledForRemoval
  41. public static <T> Event<T> create(Function<T[], T> function) {
  42. Class<?>[] arguments = TypeResolver.resolveRawArguments(Function.class, function.getClass());
  43. T[] array;
  44. try {
  45. array = (T[]) Array.newInstance(arguments[1], 0);
  46. } catch (Exception e) {
  47. throw new RuntimeException(e);
  48. }
  49. return of(list -> function.apply(list.toArray(array)));
  50. }
  51. public static <T> Event<T> of(Function<List<T>, T> function) {
  52. return new EventImpl<>(function);
  53. }
  54. @SafeVarargs
  55. public static <T> Event<T> createLoop(T... typeGetter) {
  56. if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
  57. return createLoop((Class<T>) typeGetter.getClass().getComponentType());
  58. }
  59. @SuppressWarnings("UnstableApiUsage")
  60. public static <T> Event<T> createLoop(Class<T> clazz) {
  61. return of(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
  62. @Override
  63. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  64. for (T listener : listeners) {
  65. method.invoke(listener, args);
  66. }
  67. return null;
  68. }
  69. }));
  70. }
  71. @SafeVarargs
  72. public static <T> Event<T> createInteractionResult(T... typeGetter) {
  73. if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
  74. return createInteractionResult((Class<T>) typeGetter.getClass().getComponentType());
  75. }
  76. @SuppressWarnings("UnstableApiUsage")
  77. public static <T> Event<T> createInteractionResult(Class<T> clazz) {
  78. return of(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
  79. @Override
  80. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  81. for (T listener : listeners) {
  82. InteractionResult result = (InteractionResult) method.invoke(listener, args);
  83. if (result != InteractionResult.PASS) {
  84. return result;
  85. }
  86. }
  87. return InteractionResult.PASS;
  88. }
  89. }));
  90. }
  91. @SafeVarargs
  92. public static <T> Event<T> createInteractionResultHolder(T... typeGetter) {
  93. if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
  94. return createInteractionResultHolder((Class<T>) typeGetter.getClass().getComponentType());
  95. }
  96. @SuppressWarnings("UnstableApiUsage")
  97. public static <T> Event<T> createInteractionResultHolder(Class<T> clazz) {
  98. return of(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
  99. @Override
  100. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  101. for (T listener : listeners) {
  102. InteractionResultHolder result = (InteractionResultHolder) Objects.requireNonNull(method.invoke(listener, args));
  103. if (result.getResult() != InteractionResult.PASS) {
  104. return result;
  105. }
  106. }
  107. return InteractionResultHolder.pass(null);
  108. }
  109. }));
  110. }
  111. @SafeVarargs
  112. public static <T> Event<Consumer<T>> createConsumerLoop(T... typeGetter) {
  113. if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
  114. return createConsumerLoop((Class<T>) typeGetter.getClass().getComponentType());
  115. }
  116. @SuppressWarnings("UnstableApiUsage")
  117. public static <T> Event<Consumer<T>> createConsumerLoop(Class<T> clazz) {
  118. Event<Consumer<T>> event = of(listeners -> (Consumer<T>) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{Consumer.class}, new AbstractInvocationHandler() {
  119. @Override
  120. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  121. for (Consumer<T> listener : listeners) {
  122. method.invoke(listener, args);
  123. }
  124. return null;
  125. }
  126. }));
  127. Class<?> superClass = clazz;
  128. do {
  129. if (superClass.isAnnotationPresent(ForgeEvent.class)) {
  130. return attachToForge(event);
  131. }
  132. superClass = superClass.getSuperclass();
  133. } while (superClass != null);
  134. return event;
  135. }
  136. @SafeVarargs
  137. public static <T> Event<Actor<T>> createActorLoop(T... typeGetter) {
  138. if (typeGetter.length != 0) throw new IllegalStateException("array must be empty!");
  139. return createActorLoop((Class<T>) typeGetter.getClass().getComponentType());
  140. }
  141. @SuppressWarnings("UnstableApiUsage")
  142. public static <T> Event<Actor<T>> createActorLoop(Class<T> clazz) {
  143. Event<Actor<T>> event = of(listeners -> (Actor<T>) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{Actor.class}, new AbstractInvocationHandler() {
  144. @Override
  145. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  146. for (Actor<T> listener : listeners) {
  147. InteractionResult result = (InteractionResult) method.invoke(listener, args);
  148. if (result != InteractionResult.PASS) {
  149. return result;
  150. }
  151. }
  152. return InteractionResult.PASS;
  153. }
  154. }));
  155. Class<?> superClass = clazz;
  156. do {
  157. if (superClass.isAnnotationPresent(ForgeEventCancellable.class)) {
  158. return attachToForgeActorCancellable(event);
  159. }
  160. superClass = superClass.getSuperclass();
  161. } while (superClass != null);
  162. superClass = clazz;
  163. do {
  164. if (superClass.isAnnotationPresent(ForgeEvent.class)) {
  165. return attachToForgeActor(event);
  166. }
  167. superClass = superClass.getSuperclass();
  168. } while (superClass != null);
  169. return event;
  170. }
  171. @ExpectPlatform
  172. public static <T> Event<Consumer<T>> attachToForge(Event<Consumer<T>> event) {
  173. throw new AssertionError();
  174. }
  175. @ExpectPlatform
  176. public static <T> Event<Actor<T>> attachToForgeActor(Event<Actor<T>> event) {
  177. throw new AssertionError();
  178. }
  179. @ExpectPlatform
  180. public static <T> Event<Actor<T>> attachToForgeActorCancellable(Event<Actor<T>> event) {
  181. throw new AssertionError();
  182. }
  183. private static class EventImpl<T> implements Event<T> {
  184. private final Function<List<T>, T> function;
  185. private T invoker = null;
  186. private ArrayList<T> listeners;
  187. public EventImpl(Function<List<T>, T> function) {
  188. this.function = function;
  189. this.listeners = new ArrayList<>();
  190. }
  191. @Override
  192. public T invoker() {
  193. if (invoker == null) {
  194. update();
  195. }
  196. return invoker;
  197. }
  198. @Override
  199. public void register(T listener) {
  200. listeners.add(listener);
  201. invoker = null;
  202. }
  203. @Override
  204. public void unregister(T listener) {
  205. listeners.remove(listener);
  206. listeners.trimToSize();
  207. invoker = null;
  208. }
  209. @Override
  210. public boolean isRegistered(T listener) {
  211. return listeners.contains(listener);
  212. }
  213. @Override
  214. public void clearListeners() {
  215. listeners.clear();
  216. listeners.trimToSize();
  217. invoker = null;
  218. }
  219. public void update() {
  220. if (listeners.size() == 1) {
  221. invoker = listeners.get(0);
  222. } else {
  223. invoker = function.apply(listeners);
  224. }
  225. }
  226. }
  227. }