From 037faad8bd52a9ef3258a418722cb7bdd6c89ec7 Mon Sep 17 00:00:00 2001 From: MehVahdJukaar Date: Tue, 30 Jul 2024 12:34:50 +0200 Subject: [PATCH] more sketchy work on forge specific zeta bus --- .../zeta/event/bus/wip/ForgeZetaBus.java | 117 ++++++++++++------ .../zeta/event/bus/wip/ZetaBus.java | 4 +- 2 files changed, 81 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/violetmoon/zeta/event/bus/wip/ForgeZetaBus.java b/src/main/java/org/violetmoon/zeta/event/bus/wip/ForgeZetaBus.java index b88db00..c83171b 100644 --- a/src/main/java/org/violetmoon/zeta/event/bus/wip/ForgeZetaBus.java +++ b/src/main/java/org/violetmoon/zeta/event/bus/wip/ForgeZetaBus.java @@ -1,9 +1,9 @@ package org.violetmoon.zeta.event.bus.wip; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.eventbus.api.IEventBus; import org.apache.logging.log4j.Logger; +import org.checkerframework.checker.units.qual.A; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.violetmoon.zeta.Zeta; @@ -11,51 +11,31 @@ import java.lang.annotation.Annotation; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; +// this is quite jank. Basically converts all zeta events to forge ones, then delegates to the forge bus directly public class ForgeZetaBus extends ZetaBus { private final Map, Function> forgeToZetaMap = new HashMap<>(); - private final Map, Function> zetaToForgeMap = new HashMap<>(); - //ForgeZAddReloadListener.class, (Function) ForgeZAddReloadListener::new + private final Map, Function> zetaToForgeMap = new HashMap<>(); private final IEventBus forgeBus; + private final Map convertedHandlers = new HashMap<>(); /** * @param subscriberAnnotation The annotation that subscribe()/unsubscribe() will pay attention to. * @param eventRoot The superinterface of all events fired on this bus. */ - public ForgeZetaBus(Zeta z, Class subscriberAnnotation, Class eventRoot, @Nullable Logger logSpam) { + public ForgeZetaBus(Zeta z, Class subscriberAnnotation, Class eventRoot, + @Nullable Logger logSpam, IEventBus forgeBus) { super(z, subscriberAnnotation, eventRoot, logSpam); - this.forgeBus = MinecraftForge.EVENT_BUS; - } - - public void registerEventMappings(Class zetaEvent, - Function forgeToZeta, - Class forgeEvent, - Function zetaToForge) { - forgeToZetaMap.put(zetaEvent, forgeToZeta); - zetaToForgeMap.put(forgeEvent, zetaToForge); - } - - // takes a method that takes a zeta event and turns into one that takes a forge event - private Consumer remapMethod(MethodHandle zetaEventConsumer, Class zetaEventClass) { - Function forgeToZetaFunc = forgeToZetaMap.get(zetaEventClass); - return createForgeConsumer(zetaEventConsumer, forgeToZetaFunc); - } - - private Consumer createForgeConsumer(MethodHandle zetaEventConsumer, Function forgeToZetaFunc) { - return event -> { - try { - zetaEventConsumer.invoke(forgeToZetaFunc.apply(event)); - } catch (Throwable e) { - throw new RuntimeException(e); - } - }; + this.forgeBus = forgeBus; } @Override @@ -78,32 +58,93 @@ protected void addListener(Method method, Object receiver, Class owningClazz) if (receiver != null) handle = handle.bindTo(receiver); - forgeBus.addListener(remapMethod(handle, (Class) eventType)); + Consumer consumer = remapMethod(handle, (Class) eventType); + forgeBus.addListener(consumer); + //store here so we can unregister later + convertedHandlers.put(new Key(method, receiver, owningClazz), consumer); } @Override - protected void removeListener(Method m, Object receiver, Class owningClazz) { - + protected void unregisterMethod(Method m, Object receiver, Class owningClazz) { + var handler = convertedHandlers.remove(new Key(m, receiver, owningClazz)); + if (handler != null) { + forgeBus.unregister(handler); + } } + private record Key(Method method, Object receiver, Class owningClazz) { + } @Override public T fire(@NotNull T event) { - forgeBus.post(remapEvent(event)); + forgeBus.post(remapEvent(event, event.getClass())); return event; } - private Event remapEvent(@NotNull T event) { - Function zetaToForgeFunc = zetaToForgeMap.get(event.getClass()); + @Override + public T fire(@NotNull T event, Class firedAs) { + forgeBus.post(remapEvent(event, firedAs)); + return event; + } + + // reflection hacks below. be warned + + private Event remapEvent(@NotNull T event, Class firedAs) { + Function zetaToForgeFunc = zetaToForgeMap.computeIfAbsent((Class) firedAs, this::findWrappedEvent); return createForgeEvent(event, zetaToForgeFunc); } + // takes a method that takes a zeta event and turns into one that takes a forge event + private Consumer remapMethod(MethodHandle zetaEventConsumer, Class zetaEventClass) { + Function forgeToZetaFunc = forgeToZetaMap.computeIfAbsent(zetaEventClass,this::findWrappingConstructor); + return createForgeConsumer(zetaEventConsumer, forgeToZetaFunc); + } + + + private Function findWrappedEvent(Class zetaEventClass) { + for (Field field : zetaEventClass.getDeclaredFields()) { + if (Event.class.isAssignableFrom(field.getType())) { + return instance -> { + try { + return (Event) field.get(instance); + } catch (IllegalAccessException illegalAccessException) { + throw new RuntimeException(illegalAccessException); + } + }; + } + } + throw new RuntimeException("No wrapped forge Event found for Zeta event class " + zetaEventClass); + } + + private Function findWrappingConstructor(Class zetaEventClass) { + // Find the constructor that takes a single parameter of type A + for (Constructor constructor : zetaEventClass.getConstructors()) { + Class[] parameterTypes = constructor.getParameterTypes(); + if (parameterTypes.length == 1 && Event.class.isAssignableFrom(parameterTypes[0])) { + return event -> { + try { + return (E) constructor.newInstance(event); + } catch (Exception e) { + throw new RuntimeException(e); + } + }; + } + } + throw new RuntimeException("No forge-Event-wrapping constructor found for Zeta event class " + zetaEventClass); + } + private Event createForgeEvent(@NotNull E event, Function function) { return function.apply((T) event); } - @Override - public T fire(@NotNull T event, Class firedAs) { - return null; + private Consumer createForgeConsumer(MethodHandle zetaEventConsumer, Function forgeToZetaFunc) { + return event -> { + try { + zetaEventConsumer.invoke(forgeToZetaFunc.apply(event)); + } catch (Throwable e) { + throw new RuntimeException(e); + } + }; } + } diff --git a/src/main/java/org/violetmoon/zeta/event/bus/wip/ZetaBus.java b/src/main/java/org/violetmoon/zeta/event/bus/wip/ZetaBus.java index df92d0a..2c6a064 100644 --- a/src/main/java/org/violetmoon/zeta/event/bus/wip/ZetaBus.java +++ b/src/main/java/org/violetmoon/zeta/event/bus/wip/ZetaBus.java @@ -75,11 +75,11 @@ public ZetaBus unsubscribe(@NotNull Object target) { } streamAnnotatedMethods(owningClazz, receiver == null) - .forEach(m -> removeListener(m, receiver, owningClazz)); + .forEach(m -> unregisterMethod(m, receiver, owningClazz)); return this; } - protected abstract void removeListener(Method m, Object receiver, Class owningClazz); + protected abstract void unregisterMethod(Method m, Object receiver, Class owningClazz); /** * Fires an event on the event bus. Each subscriber will be visited in order.