Solved Disable plugin in certain world?

Discussion in 'Plugin Development' started by Xp10d3, Jan 17, 2020.

  1. Offline

    Xp10d3

    I know people say it is impossible, but I am sure PerWorldPlugins and DisableMe proves otherwise (sorry; no offense meant). I have asked people how to do this, and they say its a simple concept, so I am wondering how to do this. How do I disable a plugin in a certain world and have it enabled in others? I have an "engine" that gets the world the player's in, checks if it is in that world, then disables all the plugins listed for ALL world (or just in general). I want to change the disable all plugins listed in all worlds to only certain worlds. How do I do this??

    Code:
    package play.corelia.online;
    
    import java.util.List;
    import java.util.ListIterator;
    
    import org.bukkit.Bukkit;
    import org.bukkit.World;
    import org.bukkit.configuration.file.FileConfiguration;
    import org.bukkit.entity.Player;
    import org.bukkit.event.player.PlayerPortalEvent;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class Core extends JavaPlugin {
       
        // Get the value "config"
        FileConfiguration config = getConfig();
       
        // The supress warning is related to the variable pluginsInstalled at (ListIterator<String>).
        @SuppressWarnings("unchecked")
        public void onEnable() {
           
            // Get the config location location.world.
            List<String> worldConfig = this.getConfig().getStringList("location.world.");
            // Set the worldConfig variable to a string.
            String worldConfigString = worldConfig.toString();
           
            // Get the list pluginsInstalled.
            ListIterator<String> pluginsInstalled = (ListIterator<String>) this.getConfig().getList("plugins.installed.");
            // Set the pluginsInstalled variable to a string.
            String pluginsInstalledString = pluginsInstalled.toString();
           
            String messageOne = "The following worlds have been detected in the config:";
            if (worldConfig != null) {
                this.getServer().getConsoleSender().sendMessage(messageOne);
                this.getServer().getConsoleSender().sendMessage(worldConfigString);
            }
            String messageTwo = "The following plugins have been detected in the config:";
            if (pluginsInstalled != null) {
                this.getServer().getConsoleSender().sendMessage(messageTwo);
                this.getServer().getConsoleSender().sendMessage(pluginsInstalledString);
            }
            config = getConfig();
            loadConfig();
        }
       
        public void loadConfig(){
            getConfig().options().copyDefaults(true);
            saveConfig();
        }
       
        @SuppressWarnings({ "unlikely-arg-type", "unchecked" })
        public void getWorld() {
            Player player = Bukkit.getPlayer(getName());
           
            World world = Bukkit.getServer().getWorld(player.getWorld().getName());
            List<String> worldConfig = this.getConfig().getStringList("location.world.");
            ListIterator<String> pluginsInstalled = (ListIterator<String>) this.getConfig().getList("plugins.installed.");
            if (world.equals(worldConfig)) {
                if (getServer().getPluginManager().getPlugin(pluginsInstalled.next()) != null) {
                    Bukkit.getPluginManager().disablePlugin(getServer().getPluginManager().getPlugin(pluginsInstalled.next()));
                } else {
                    return;
                }
            }
        }
       
        public void ifInPortal(PlayerPortalEvent event) {
            getWorld();
        }
       
    }
    
     
  2. Offline

    Pr0totype2

    Plugins aren't a per-world thing. You either have it enabled for the server or you have it unloaded.
    What you could do however is attempting to get all commands from that plugin, then listen to the command events and if the player's in a certain world using a certain command from a plugin you don't want to have enabled in there, simply cancel it.
     
  3. Online

    timtower Moderator Moderator

    @Xp10d3 Lets start with this question: why make something so complicated and error sensitive when they already exist?
    You need to listen to all events, all commands. Even timer based things can mess it up for you.
     
  4. Offline

    Xp10d3

    I got the same answer from others as well So how would I get the events from other plugins? And I know it already exists, but I would prefer to make a 1.15 version since all the current plugins are outdated with PerWorldPlugins being only 1.13 and below.
     
  5. Online

    timtower Moderator Moderator

    @Xp10d3 Have you considered just taking the source of PWP and updating it to 1.15?
     
  6. Offline

    Xp10d3

    @timtower Yes. It is extremely confusing and way out of my skill range. I have taken a look at it and I barely understand it. I can get my way around configs and stuff, but using the Bukkit core or CommandMaps is something I don't understand/have experience in.

    EDIT: Also I would like to have the plugin be compatible with Spigot and possibly Paper since it's what people use more of in professional servers.

    EDIT TWO: If this helps, I got some code help from a Discord server and they sent something that can listen on the events. I am one step closer, but I get an error at:
    Code:
    handler.getRegisteredListeners().forEach(
    
    all the way to the the end saying, "Cannot invoke forEach((<no type> Listener) -> {}) on the array type RegisteredListener[]".
    Code:
        static <Type extends Event> void filter(Class<Type> type, BiPredicate<Plugin, Type> filter) {
              final HandlerList handler = (HandlerList) type.getDeclaredMethod("getHandlerList").invoke(null);
              handler.getRegisteredListeners().forEach(Listener -> {
                handler.unregister(listener);
                handler.register(new RegisteredListener(listener.getListener(), ($, event) -> {
                  if (filter.test(listener.getPlugin(), (Type) event)) listener.callEvent(event);
                }, listener.getPriority(), listener.getPlugin()));
            });
        }
    
    @Pr0totype2 Thanks. That was really helpful :) I don't know how to listen on Commands, though.
     
    Last edited: Jan 21, 2020
  7. Offline

    KarimAKL

    1. Why is the 'L' in "Listener" upper case here?
    2. I'd recommend learning how to read the errors.
    The error is saying that there's no forEach() method for the type RegisteredListener[], and that's because it's an array. You can fix this by making a list from the array; use the Arrays.asList() method for that.
     
  8. Offline

    Xp10d3

    I know how to read errors -__^ And I made a typo for that part. I know that it should be "listener". But what do you mean by using the Array.asList() method? Do I wrap the method in it? If so, where? Finally what do I register "listener" as? Is it:
    Code:
    Listener listener = ...
    
    Or whatever?
     
  9. Offline

    KarimAKL

    Code:Java
    1. Arrays.asList(handler.getRegisteredListeners()).forEach(...);

    I don't know, i haven't tried anything like this before.
     
    Xp10d3 likes this.
  10. Offline

    Xp10d3

    Thanks! The method asks me to add an argument in the
    Code:
     handler.register()
    line. The error says: The constructor RegisteredListener(Listener, EventExecutor, EventPriority, Plugin) is undefined. When I add the argument, I have three options: isEnabled, naggable, and false. I'm confused which one to do; sorry if this is a nooby question. Finally, I get an error at:
    Code:
    type.getDeclaredMethod("getHandlerList").invoke(null);
    
    Error: Unhandled exception type NoSuchMethodException. It asks to add throws declaration, surround with try/multi-catch, or surround with try/catch.


    Code:
        @SuppressWarnings("unchecked")
        static <Type extends Event> void filter(Class<Type> type, BiPredicate<Plugin, Type> filter) {
              final HandlerList handler = (HandlerList) type.getDeclaredMethod("getHandlerList").invoke(null);
              Arrays.asList(handler.getRegisteredListeners()).forEach(listener -> {
                handler.unregister(listener);
                handler.register(new RegisteredListener(listener.getListener(), ($, event) -> {
                  if (filter.test(listener.getPlugin(), (Type) event)) listener.callEvent(event);
                }, listener.getPriority(), listener.getPlugin(), false));
              });
        };
    
     
  11. Offline

    caderapee

    @Xp10d3 The method invoke will execute the method. It needs a parameter that is the instance of the class.

    For listen to commands, you can retrieve the field 'commandMap' from the main class of bukkit, by passing the Bukkit.getServer() as instance. Then i guess listen to playPreprocess
     
    Last edited: Jan 21, 2020
  12. Offline

    Xp10d3

    ... That sounds really complicated xD I'm using Spigot, though, so will I be able to get CommandMap using Bukkit.getServer()? Also I don't know what playPreprocess is... Also where do I input the parameter? Is it related to my error?

    EDIT: Oh didn't read that correctly xD Sorry what do I do in the type.getDeclaredMethod("getHandlerList").invoke(null); line? That's where I get my error.
    @caderapee

    EDIT 2: I'm still confused on what you mean by having the parameter be the instance of the class. Are you talking about:
    Code:
    type.getDeclaredMethod("getHandlerList").invoke(Core.class);
    
     
    Last edited: Jan 21, 2020
    caderapee likes this.
  13. Offline

    Strahan

    When I need plugin variation per world, I just use BungeeCord. Very simple.
     
  14. Offline

    Xp10d3

    BungeeCord requires a second server which costs money. So what does caderapee mean by:
    Is that referring to this line:
    Code:
    type.getDeclaredMethod("getHandlerList").invoke(null);
    
    I so, what do I do? What parameter do I add and how? Sorry, I am super confused. I got as far as replacing null for Core.class and I got the same error (Unhandled exception type InvocationTargetException).

    EDIT: @Strahan I mean everyone is telling me to use BungeeCord but I'd like to keep everything on one server. It saves money and time for setting up Bungee, but thanks for the suggestion. Bungee would make things easier, but I prefer keeping things to one server :) (also I don't know how to use Bungee :p)
     
    Last edited: Jan 22, 2020
  15. Offline

    Strahan

    Yep. Quality solutions aren't always free. If you are aiming to make a big public server, you're going to have to accept that it likely won't be cheap. I suppose you could BC to various free hosting accounts, but that seems sketchy. Everyone is telling you BC because it's the best solution for what you want to achieve.

    That said, are the plugins you want to be world aware plugins you made yourself? If so, then it's easily doable. If you mean to manage other plugins, it won't be feasible. Listening for the command is easy, but that's just one little part of it. You'd need to capture any activity the plugins perform, not just commands. Things tied to events may be possible, but there are still other things plugins do that you may not have a vector for interception.

    If I had to do this with one server, I'd either update PWP or decompile every plugin I have and make them world aware. Of course, if you are one of those people with like 80 plugins that's gonna be a tall order lol
     
  16. Offline

    Xp10d3

    Alright. I see. I get where you are coming from, and I see the benefits, but I still prefer to use a customizable disable events plugin, so that still leaves me with my error and problem with that line. I am kinda asking this because 1) I need this, even though I see the benefit of disabling events in the plugins I made myself, 2) I am also making this because someone asked me to, and he doesn't want me to know the plugins he's using, and 3) yeah BungeeCord is expensive even though it's the best solution xD And I have considered (a lot) updating PWP but I just don't understand the code...

    EDIT: Wait, what do you mean by not feasible? Aren't I just cancelling other events in other plugins? And I'm cool with just cancelling the events. As long as it somewhat works that's alright with me.
    EDIT 2: Never mind. Got some help elsewhere.
     
    Last edited: Jan 23, 2020

Share This Page