EventFactory.java 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * Copyright 2020 shedaniel
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package me.shedaniel.architectury.event;
  17. import com.google.common.reflect.AbstractInvocationHandler;
  18. import me.shedaniel.architectury.ExpectPlatform;
  19. import net.jodah.typetools.TypeResolver;
  20. import net.minecraft.world.InteractionResult;
  21. import net.minecraft.world.InteractionResultHolder;
  22. import org.apache.commons.lang3.ArrayUtils;
  23. import org.jetbrains.annotations.NotNull;
  24. import java.lang.reflect.Array;
  25. import java.lang.reflect.Method;
  26. import java.lang.reflect.Proxy;
  27. import java.util.Objects;
  28. import java.util.function.Consumer;
  29. import java.util.function.Function;
  30. public final class EventFactory {
  31. private EventFactory() {}
  32. public static <T> Event<T> create(Function<T[], T> function) {
  33. Class<?>[] arguments = TypeResolver.resolveRawArguments(Function.class, function.getClass());
  34. return new EventImpl<>(arguments[1], function);
  35. }
  36. @SuppressWarnings("UnstableApiUsage")
  37. public static <T> Event<T> createLoop(Class<T> clazz) {
  38. return create(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
  39. @Override
  40. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  41. for (T listener : listeners) {
  42. method.invoke(listener, args);
  43. }
  44. return null;
  45. }
  46. }));
  47. }
  48. @SuppressWarnings("UnstableApiUsage")
  49. public static <T> Event<T> createInteractionResult(Class<T> clazz) {
  50. return create(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
  51. @Override
  52. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  53. for (T listener : listeners) {
  54. InteractionResult result = (InteractionResult) method.invoke(listener, args);
  55. if (result != InteractionResult.PASS) {
  56. return result;
  57. }
  58. }
  59. return InteractionResult.PASS;
  60. }
  61. }));
  62. }
  63. @SuppressWarnings("UnstableApiUsage")
  64. public static <T> Event<T> createInteractionResultHolder(Class<T> clazz) {
  65. return create(listeners -> (T) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{clazz}, new AbstractInvocationHandler() {
  66. @Override
  67. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  68. for (T listener : listeners) {
  69. InteractionResultHolder result = (InteractionResultHolder) Objects.requireNonNull(method.invoke(listener, args));
  70. if (result.getResult() != InteractionResult.PASS) {
  71. return result;
  72. }
  73. }
  74. return InteractionResultHolder.pass(null);
  75. }
  76. }));
  77. }
  78. @SuppressWarnings("UnstableApiUsage")
  79. public static <T> Event<Consumer<T>> createConsumerLoop(Class<T> clazz) {
  80. return create(listeners -> (Consumer<T>) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{Consumer.class}, new AbstractInvocationHandler() {
  81. @Override
  82. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  83. for (Consumer<T> listener : listeners) {
  84. method.invoke(listener, args);
  85. }
  86. return null;
  87. }
  88. }));
  89. }
  90. @SuppressWarnings("UnstableApiUsage")
  91. public static <T> Event<Actor<T>> createActorLoop(Class<T> clazz) {
  92. return create(listeners -> (Actor<T>) Proxy.newProxyInstance(EventFactory.class.getClassLoader(), new Class[]{Actor.class}, new AbstractInvocationHandler() {
  93. @Override
  94. protected Object handleInvocation(@NotNull Object proxy, @NotNull Method method, Object @NotNull [] args) throws Throwable {
  95. for (Actor<T> listener : listeners) {
  96. InteractionResult result = (InteractionResult) method.invoke(listener, args);
  97. if (result != InteractionResult.PASS) {
  98. return result;
  99. }
  100. }
  101. return InteractionResult.PASS;
  102. }
  103. }));
  104. }
  105. @ExpectPlatform
  106. public static <T> Event<Consumer<T>> attachToForge(Event<Consumer<T>> event) {
  107. throw new AssertionError();
  108. }
  109. private static class EventImpl<T> implements Event<T> {
  110. private final Function<T[], T> function;
  111. private T invoker = null;
  112. private T[] listeners;
  113. private Class<?> clazz;
  114. public EventImpl(Class<?> clazz, Function<T[], T> function) {
  115. this.clazz = Objects.requireNonNull(clazz);
  116. this.function = function;
  117. this.listeners = emptyArray();
  118. }
  119. private T[] emptyArray() {
  120. try {
  121. return (T[]) Array.newInstance(clazz, 0);
  122. } catch (Exception e) {
  123. throw new RuntimeException(e);
  124. }
  125. }
  126. @Override
  127. public T invoker() {
  128. if (invoker == null) {
  129. update();
  130. }
  131. return invoker;
  132. }
  133. @Override
  134. public void register(T listener) {
  135. listeners = ArrayUtils.add(listeners, listener);
  136. invoker = null;
  137. }
  138. @Override
  139. public void unregister(T listener) {
  140. listeners = ArrayUtils.removeElement(listeners, listener);
  141. invoker = null;
  142. }
  143. @Override
  144. public boolean isRegistered(T listener) {
  145. return ArrayUtils.contains(listeners, listener);
  146. }
  147. @Override
  148. public void clearListeners() {
  149. listeners = emptyArray();
  150. invoker = null;
  151. }
  152. public void update() {
  153. if (listeners.length == 1) {
  154. invoker = listeners[0];
  155. } else {
  156. invoker = function.apply(listeners);
  157. }
  158. }
  159. }
  160. }