From 1107088acb809004a0865fca24b1aaea63fbb7cc Mon Sep 17 00:00:00 2001 From: LexManos Date: Sat, 17 Sep 2016 15:08:23 -0700 Subject: [PATCH] Add support for generic filtering of events. Please DO NOT use this in performance sensitive environments where you will have tons of things added to the listener list. If that's the case define sub-classes as they have completely separate lists and will thus be more efficient when firing the event. --- .../event/AttachCapabilitiesEvent.java | 39 ++++++++++++------- .../common/eventhandler/ASMEventHandler.java | 25 +++++++++++- .../fml/common/eventhandler/EventBus.java | 2 +- .../fml/common/eventhandler/GenericEvent.java | 36 +++++++++++++++++ .../common/eventhandler/IGenericEvent.java | 26 +++++++++++++ .../test/TestCapabilityMod.java | 14 +++++++ 6 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 src/main/java/net/minecraftforge/fml/common/eventhandler/GenericEvent.java create mode 100644 src/main/java/net/minecraftforge/fml/common/eventhandler/IGenericEvent.java diff --git a/src/main/java/net/minecraftforge/event/AttachCapabilitiesEvent.java b/src/main/java/net/minecraftforge/event/AttachCapabilitiesEvent.java index fd8bfa05de..eb0dcc414b 100644 --- a/src/main/java/net/minecraftforge/event/AttachCapabilitiesEvent.java +++ b/src/main/java/net/minecraftforge/event/AttachCapabilitiesEvent.java @@ -26,7 +26,7 @@ import com.google.common.collect.Maps; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.fml.common.eventhandler.Event; +import net.minecraftforge.fml.common.eventhandler.GenericEvent; /** * Fired whenever an object with Capabilities support {currently TileEntity/Item/Entity) @@ -35,20 +35,28 @@ import net.minecraftforge.fml.common.eventhandler.Event; * Please note that as this is fired for ALL object creations efficient code is recommended. * And if possible use one of the sub-classes to filter your intended objects. */ -public class AttachCapabilitiesEvent extends Event +public class AttachCapabilitiesEvent extends GenericEvent { - private final Object obj; + private final T obj; private final Map caps = Maps.newLinkedHashMap(); private final Map view = Collections.unmodifiableMap(caps); - public AttachCapabilitiesEvent(Object obj) + + @SuppressWarnings("unchecked") + @Deprecated + public AttachCapabilitiesEvent(T obj) { + this((Class)Object.class, obj); + } + public AttachCapabilitiesEvent(Class type, T obj) + { + super(type); this.obj = obj; } /** * Retrieves the object that is being created, Not much state is set. */ - public Object getObject() + public T getObject() { return this.obj; } @@ -80,12 +88,13 @@ public class AttachCapabilitiesEvent extends Event /** * A version of the parent event which is only fired for Tile Entities. */ - public static class TileEntity extends AttachCapabilitiesEvent + @Deprecated + public static class TileEntity extends AttachCapabilitiesEvent { private final net.minecraft.tileentity.TileEntity te; public TileEntity(net.minecraft.tileentity.TileEntity te) { - super(te); + super(net.minecraft.tileentity.TileEntity.class, te); this.te = te; } public net.minecraft.tileentity.TileEntity getTileEntity() @@ -97,12 +106,13 @@ public class AttachCapabilitiesEvent extends Event /** * A version of the parent event which is only fired for Entities. */ - public static class Entity extends AttachCapabilitiesEvent + @Deprecated + public static class Entity extends AttachCapabilitiesEvent { private final net.minecraft.entity.Entity entity; public Entity(net.minecraft.entity.Entity entity) { - super(entity); + super(net.minecraft.entity.Entity.class, entity); this.entity = entity; } public net.minecraft.entity.Entity getEntity() @@ -114,16 +124,18 @@ public class AttachCapabilitiesEvent extends Event /** * A version of the parent event which is only fired for ItemStacks. */ - public static class Item extends AttachCapabilitiesEvent + public static class Item extends AttachCapabilitiesEvent { + @Deprecated private final net.minecraft.item.ItemStack stack; private final net.minecraft.item.Item item; public Item(net.minecraft.item.Item item, net.minecraft.item.ItemStack stack) { - super(item); + super(net.minecraft.item.Item.class, item); this.item = item; this.stack = stack; } + @Deprecated public net.minecraft.item.Item getItem() { return this.item; @@ -137,12 +149,13 @@ public class AttachCapabilitiesEvent extends Event /** * A version of the parent event which is only fired for Worlds. */ - public static class World extends AttachCapabilitiesEvent + @Deprecated + public static class World extends AttachCapabilitiesEvent { private final net.minecraft.world.World world; public World(net.minecraft.world.World world) { - super(world); + super(net.minecraft.world.World.class, world); this.world = world; } public net.minecraft.world.World getWorld() diff --git a/src/main/java/net/minecraftforge/fml/common/eventhandler/ASMEventHandler.java b/src/main/java/net/minecraftforge/fml/common/eventhandler/ASMEventHandler.java index 41edc0a661..9394b4191e 100644 --- a/src/main/java/net/minecraftforge/fml/common/eventhandler/ASMEventHandler.java +++ b/src/main/java/net/minecraftforge/fml/common/eventhandler/ASMEventHandler.java @@ -23,6 +23,7 @@ import static org.objectweb.asm.Opcodes.*; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; import java.util.HashMap; import net.minecraftforge.fml.common.ModContainer; @@ -34,7 +35,6 @@ import org.objectweb.asm.Type; import com.google.common.collect.Maps; - public class ASMEventHandler implements IEventListener { private static int IDs = 0; @@ -48,8 +48,15 @@ public class ASMEventHandler implements IEventListener private final SubscribeEvent subInfo; private ModContainer owner; private String readable; + private java.lang.reflect.Type filter = null; + @Deprecated public ASMEventHandler(Object target, Method method, ModContainer owner) throws Exception + { + this(target, method, owner, false); + } + + public ASMEventHandler(Object target, Method method, ModContainer owner, boolean isGeneric) throws Exception { this.owner = owner; if (Modifier.isStatic(method.getModifiers())) @@ -58,8 +65,19 @@ public class ASMEventHandler implements IEventListener handler = (IEventListener)createWrapper(method).getConstructor(Object.class).newInstance(target); subInfo = method.getAnnotation(SubscribeEvent.class); readable = "ASM: " + target + " " + method.getName() + Type.getMethodDescriptor(method); + if (isGeneric) + { + java.lang.reflect.Type type = method.getGenericParameterTypes()[0]; + System.currentTimeMillis(); + if (type instanceof ParameterizedType) + { + filter = ((ParameterizedType)type).getActualTypeArguments()[0]; + System.currentTimeMillis(); + } + } } + @SuppressWarnings("rawtypes") @Override public void invoke(Event event) { @@ -69,7 +87,10 @@ public class ASMEventHandler implements IEventListener { if (!event.isCancelable() || !event.isCanceled() || subInfo.receiveCanceled()) { - handler.invoke(event); + if (filter == null || filter == ((IGenericEvent)event).getGenericType()) + { + handler.invoke(event); + } } } if (GETCONTEXT) diff --git a/src/main/java/net/minecraftforge/fml/common/eventhandler/EventBus.java b/src/main/java/net/minecraftforge/fml/common/eventhandler/EventBus.java index 7a83be48ed..651e3d4637 100644 --- a/src/main/java/net/minecraftforge/fml/common/eventhandler/EventBus.java +++ b/src/main/java/net/minecraftforge/fml/common/eventhandler/EventBus.java @@ -129,7 +129,7 @@ public class EventBus implements IEventExceptionHandler Constructor ctr = eventType.getConstructor(); ctr.setAccessible(true); Event event = (Event)ctr.newInstance(); - ASMEventHandler listener = new ASMEventHandler(target, method, owner); + ASMEventHandler listener = new ASMEventHandler(target, method, owner, IGenericEvent.class.isAssignableFrom(eventType)); event.getListenerList().register(busID, listener.getPriority(), listener); ArrayList others = listeners.get(target); diff --git a/src/main/java/net/minecraftforge/fml/common/eventhandler/GenericEvent.java b/src/main/java/net/minecraftforge/fml/common/eventhandler/GenericEvent.java new file mode 100644 index 0000000000..8e6f07bcf2 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/common/eventhandler/GenericEvent.java @@ -0,0 +1,36 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package net.minecraftforge.fml.common.eventhandler; + +import java.lang.reflect.Type; + +public class GenericEvent extends Event implements IGenericEvent +{ + private Class type; + protected GenericEvent(Class type) + { + this.type = type; + } + + @Override + public Type getGenericType() + { + return type; + } +} diff --git a/src/main/java/net/minecraftforge/fml/common/eventhandler/IGenericEvent.java b/src/main/java/net/minecraftforge/fml/common/eventhandler/IGenericEvent.java new file mode 100644 index 0000000000..9b0e5572ed --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/common/eventhandler/IGenericEvent.java @@ -0,0 +1,26 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package net.minecraftforge.fml.common.eventhandler; + +import java.lang.reflect.Type; + +public interface IGenericEvent +{ + Type getGenericType(); +} diff --git a/src/test/java/net/minecraftforge/test/TestCapabilityMod.java b/src/test/java/net/minecraftforge/test/TestCapabilityMod.java index 1c14bd0b4d..3ecc79dce1 100644 --- a/src/test/java/net/minecraftforge/test/TestCapabilityMod.java +++ b/src/test/java/net/minecraftforge/test/TestCapabilityMod.java @@ -112,6 +112,20 @@ public class TestCapabilityMod event.addCapability(new ResourceLocation("TestCapabilityMod:DummyCap"), new Provider(event.getTileEntity())); } + @SuppressWarnings("rawtypes") + @SubscribeEvent + public void attachEvent(AttachCapabilitiesEvent event) //Test Raw type gets everything still. + { + System.currentTimeMillis(); + } + + @SubscribeEvent + public void attachTileEntity(AttachCapabilitiesEvent event) + { + if (!(event.getObject() instanceof TileEntity)) + throw new IllegalArgumentException("Generic event handler failed! Exprected Tile Entity got " + event.getObject()); + } + // Capabilities SHOULD be interfaces, NOT concrete classes, this allows for // the most flexibility for the implementors. public static interface IExampleCapability