Plugin Help [Solved] Grabbing all entity events?

Discussion in 'Plugin Help/Development/Requests' started by pickernickel, Jun 22, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    pickernickel

    I was wondering if anyone knew how to swiftly grab all the events extending a certain class. In my particular case, I want to register an event handler to grab all entity related events. I know this has been asked before but all the threads I found were old so I was hoping someone had come across a solution since then. I would prefer not to manually register to each individual event type because I want my plugin to catch events that may have been added by other plugins as well.

    As to what my plugin is actually supposed to be doing, I need it to grab all entity events and grab the metadata of the entity involved. If it finds a specific metadata string, it will use the value of the metadata to look up a listener in a hash map and pass the event to them.

    Edit: If anyone knew how to get all events in general, I could use that as well. From there I could use the instanceof operator to get the rest but getting all events is the tricky part.
     
    Last edited: Jun 24, 2015
  2. Offline

    Boomer

    considering that any event I make in my plugin is not an extension of entitydoessomething, but rather an extension of Event ... thats all you can work from. Your certain class is Event
     
  3. Offline

    pickernickel

    I understand that not all custom events extend the player event, but in general, I want to capture all entity events but don't want to limit it strictly to Bukkit's default events. For example, if a chat plugin fires a custom player chat event or one of Citizen's npcs fire an event, they all extend PlayerEvent. I would want to receive any of those events but I have no way of knowing which events will be available for listening to until runtime.
     
  4. Offline

    pickernickel

    I ended up solving this issue myself. It involved using Java proxies to create a sort of wrapper around the original PluginManager and used some reflection to replace the server's private final variable to the wrapper as opposed to the original. This allowed me to intercept all method calls to the class and filter out the "fireEvent" method call. This is the code:

    Code:
    PluginManager manager = Bukkit.getServer().getPluginManager();
        listeners = new HashMap<String, HashMap<Class<? extends Event>, Method>>();
        try
        {
            Field field = Bukkit.getServer().getClass().getField("pluginManager");
            field.setAccessible(true);
           
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
           
            PluginManager proxy = (PluginManager) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class<?>[] { PluginManager.class }, new InvocationHandler() {
                        PluginManager target = manager;
    
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
                {
                    // TODO Auto-generated method stub
                    if(method.getName().equals("fireEvent"))
                    {
                    List<MetadataValue> metadata = new ArrayList<MetadataValue>();
                    if(args[0] instanceof EntityEvent && ((EntityEvent)args[0]).getEntity().hasMetadata("arena"))
                    {
                        metadata = ((EntityEvent)args[0]).getEntity().getMetadata("arena");
                    }
                    else if(args[0] instanceof PlayerEvent && ((PlayerEvent)args[0]).getPlayer().hasMetadata("arena"));
                    {
                        metadata = ((PlayerEvent)args[0]).getPlayer().getMetadata("arena");
                    }
                   
                    if(!metadata.isEmpty())
                    {
                        Map<Class<? extends Event>, Method> arenaMap = listeners.get(metadata.get(0).asString());
                        if(arenaMap.containsKey(args[0].getClass()))
                        {
                        arenaMap.get(args[0].getClass());
                        }
                    }
                    }
                    return method.invoke(target, args);
                }
                    });
           
            field.set(Bukkit.getServer(), proxy);
        }
        catch (Exception e)
        {
            MetagameFramework.getPlugin().getLogger().log(Level.SEVERE, "Failed to hook onto Bukkit events! Possibly outdated plugin or server.");
            e.printStackTrace();
            return;
        }
        }
     
Thread Status:
Not open for further replies.

Share This Page