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.
This commit is contained in:
LexManos 2016-09-17 15:08:23 -07:00
parent c58a66a816
commit 1107088acb
6 changed files with 126 additions and 16 deletions

View File

@ -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<T> extends GenericEvent<T>
{
private final Object obj;
private final T obj;
private final Map<ResourceLocation, ICapabilityProvider> caps = Maps.newLinkedHashMap();
private final Map<ResourceLocation, ICapabilityProvider> view = Collections.unmodifiableMap(caps);
public AttachCapabilitiesEvent(Object obj)
@SuppressWarnings("unchecked")
@Deprecated
public AttachCapabilitiesEvent(T obj)
{
this((Class<T>)Object.class, obj);
}
public AttachCapabilitiesEvent(Class<T> 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<net.minecraft.tileentity.TileEntity>
{
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<net.minecraft.entity.Entity>
{
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<net.minecraft.item.Item>
{
@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<net.minecraft.world.World>
{
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()

View File

@ -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)

View File

@ -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<IEventListener> others = listeners.get(target);

View File

@ -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<T> extends Event implements IGenericEvent<T>
{
private Class<T> type;
protected GenericEvent(Class<T> type)
{
this.type = type;
}
@Override
public Type getGenericType()
{
return type;
}
}

View File

@ -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<T>
{
Type getGenericType();
}

View File

@ -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<TileEntity> 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