Solved Trying to enable an event with Commands

Discussion in 'Spigot Plugin Development' started by NeverFlame42, Jun 25, 2021.

  1. So I made a plugin that adds potion effects based on the light level you're at. I did this by having the main class and an event class that I called to the main to register. I then set up another class to house the command. I'm able to call the command class to the main class to activate it in game, typing /vampireenable and getting some text. So I know the command is working fine on its own, I just don't know how to get it to activate the event class to add the potion effects to the player. I'm trying to find a way that when I type /vampireenable, it "turns on" the event and can later be turned off with another command. Here's my code:
    Main class -
    Code (Java):
    package me.flame.darkness;

    import org.bukkit.plugin.java.JavaPlugin;

    public final class Main extends JavaPlugin{

        @Override
        public void onEnable() {
            // Plugin startup logic
            System.out.println("The plugin is starting up");

            getServer().getPluginCommand("vampireenable").setExecutor(new Enable(this));

            //getServer().getPluginManager().registerEvents(new Dark(), this);
        }
    }
     
    Event class -
    Code (Text):
    package me.flame.darkness.events;

    import org.bukkit.block.Block;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.PlayerMoveEvent;
    import org.bukkit.potion.PotionEffect;
    import org.bukkit.potion.PotionEffectType;

    public class Dark implements Listener{

        @EventHandler
        public void inDark(PlayerMoveEvent e) {
            Block block = e.getTo().getBlock();
            int lightlevel = block.getLightLevel();

            if(lightlevel < 8){
                e.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.WITHER ,60, 1));
                e.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 60, 2));
                e.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 60, 1));
                e.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.CONFUSION, 60, 1));
            }
            else if (lightlevel == 15){
                e.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 120, 4));
                e.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.SATURATION, 120, 1));
            }

        }
       
    }
     
    Command class (where I need some help figuring out what to put at "//code" to make the plugin enable)-
    Code (Java):
    package me.flame.darkness;


    import org.bukkit.ChatColor;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;



    public class Enable implements CommandExecutor {
        private final Main main;

        public Enable(Main main){
            this.main = main;
        }

        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if(sender instanceof Player){
                Player player = (Player) sender;

                if (player.isOp() || player.hasPermission("vampireenable")){
                   
                    //code

                    player.sendMessage(ChatColor.BLUE + "You are now a reversed vampire!");

                    return true;
                }
                else {
                    player.sendMessage(ChatColor.RED + "You don't have permission to use this command!");
                    return true;
                }

            }
            else {
                main.getLogger().info("You have to be a player to clear your inventory!");
                return true;
            }
        }

    }
     
  2. you are basicly didn't register the event class
     
  3. ?
    You should put the exact same line you put in your main class:
    Code (Java):
    Bukkit.getPluginManager().registerEvents(new Dark(), main);
    I would suggest you to save the Dark instance in your command class though, so you can chek if the listener is already registered and prevent registering it twice, it can also allow you to unregister it by doing:
    Code (Java):
    HandlerList.unregister(yourListener);
     
  4. Why not create one class for listener and the command itself?
    Code (Java):
    public class YourCommand implements CommandExecutor {

        private boolean enable = false;

       // on command
       // on toggle
       if(!this.enable) {
          this.enable = true;
       } else {
          this.enable = false;


      @EventHandler
       public void yourEvent(Event event) {
           if(!enable) return; // ignore the event if not enabled
           
      }
    }
     
  5. Could also work, some minor considerations, the class would also need to implement Listener, and when registering it, the same instance must be registered as a command and as an event listener. Also toggle could just be enable = !enable
     
    • Agree Agree x 1
  6. off topic i like your way to stop spoon feeding code :D
     
  7. You guys have been super helpful, thanks a ton!
     
    • Friendly Friendly x 1
  8. Actually, can you explain this a bit more. I'm pretty new to this and keep getting "unreachable statement".
     
  9. Maybe you accidentally put the event handler method outside your class, watch your brackets, it should look like this:


    Code (Java):
    public class someClass implements someClass{

        public boolean onCommand(){
             ...
         }
       

         public void onEvent(event){
            ...
         }

    }
    and not like this:
    Code (Java):
    public class someClass implements someClass{

        public boolean onCommand(){
             ...
         }
    }

    public void onEvent(event){
        ...
    }



     
    if that's not the case then show your code
     
  10. Ok well I got rid of the unreachable, that was my fault, but I don't quite understand how to do the enable thing.
     
  11. You just have to create a new instance of your command/listener class and then register that class as an event listener and as a command executor. This is the pseudo:
    Code (Java):
    public class mainClass extends JavaPlugin{

        public void onEnable(){
            CommandClass yourClass = new CommandClass();
       
            getServer().gertPluginManager().registerEvents(yourClass, this /*you javaplugin main class instance*/);

            getCommand("command"/*your enable command from plugin.yml*/).setExecutor(yourClass);

        }

    }
     
  12. I get an error for the first line("CommandClass") and to fix it it wants me to make a constructor in the Command class. However, when I do this, it make an error on a line that didn't have an error beforehand.

    Code (Java):
    import org.bukkit.ChatColor;
    import org.bukkit.block.Block;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.player.PlayerMoveEvent;
    import org.bukkit.potion.PotionEffect;
    import org.bukkit.potion.PotionEffectType;

    public class DarkEnable implements CommandExecutor {
        private final Main main;

        public DarkEnable(Main main){
            this.main = main; //this code
        }

        public DarkEnable() {
         
        }
    The error is the main may not have been initialized. Making that Main not final helps but i dont know if that could mess up something else.

    Also, is there anything i would need to put into public DarkEnable
     
  13. Try removing the DarkEnable method with no arguments.

    What you're doing is called constructor overloading (overloading a method means that you have multiple versions of the method with the same name but different number or type of arguments. The version of a particular method that is called is determined by what arguments you pass in when calling the method). Since you're overloading your constructor method, there are multiple ways you can create a DarkEnable object:
    1. Pass it an object of type Main
    2. Pass it nothing
    You're getting an error because Intellij is noticing that there's a way to create a DarkEnable object without initializing your private main variable, which could cause errors if it never is set to a value.
     
    • Agree Agree x 1

  14. yeah, i dont really know what you mean by this. I got it to where there were no errors, but then it stopped working completely in game.
     
  15. What don't you understand? I'd be happy to go into more detail.
    Can you also post the code that has no errors but isn't working?
     
  16. Yes, you are right, you should initialize main in your constructor, making main not final would be ok as long as you remember to initialize it in your constructor, although I'd suggest you to leave it as final. You should also leave just one constructor (the one with Main as parameter).


    Yes, as I said before, you should make it implement both CommandExecutor and Listener. Remember, for your future projects, that this is not always the case, you just want this class to be a command executor and an event listener for making the event easier to "disable"
     
  17. What I'm not understanding is how to get the command and event to work together. I know from testing that they both work on their own, it's when I wanted them to work together that they stop working. I don't understand how to get the event to activate after using a command.

    Main class:

    Code (Java):
    package me.flame.darkness;

    import org.bukkit.Bukkit;
    import org.bukkit.event.Listener;
    import org.bukkit.plugin.java.JavaPlugin;

    public final class Main extends JavaPlugin{

        @Override
        public void onEnable() {
            // Plugin startup logic
            System.out.println("The plugin is starting up");

            DarkEnable turnOn = new DarkEnable();

            getServer().getPluginManager().registerEvents((Listener) turnOn, this);

            getCommand("vampireenable").setExecutor(turnOn);

        }
    }
     
    the other class:

    Code (Java):
    package me.flame.darkness;

    import org.bukkit.ChatColor;
    import org.bukkit.block.Block;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.player.PlayerMoveEvent;
    import org.bukkit.potion.PotionEffect;
    import org.bukkit.potion.PotionEffectType;

    public class DarkEnable implements CommandExecutor {
        private Main main;

        public DarkEnable(){
            this.main = main;
        }


        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if(sender instanceof Player){
                Player player = (Player) sender;

                if(player.isOp() || player.hasPermission("vampireenable")){



                    player.sendMessage(ChatColor.GREEN + "You are now a reverse vampire!");

                    return true;
                }
                else if ((player.isOp() || player.hasPermission("vampiredisable"))){


                    player.sendMessage(ChatColor.GREEN + "You are no longer a reverse vampire!");
                    return true;
                }else {
                    player.sendMessage(ChatColor.RED + "You don't have permission to use this command!");
                    return true;
                }

            }
            else {
                main.getLogger().info("You have to be a player to become a reverse vampire!");
                return true;
            }
        }



        @EventHandler
        public void onEnterDark(PlayerMoveEvent event){
            Block block = event.getTo().getBlock();
            int lightLevel = block.getLightLevel();

            if (lightLevel < 8){
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.CONFUSION, 60, 2));
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 60, 1));
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.WITHER, 60, 1));
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 60, 1));
            }else if (lightLevel == 15){
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.SATURATION, 120, 4));
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 120, 1));
            }
        }

    }
     
     
  18. I see two problems:
    1. You're telling the server to register events to your turnOn object, and you have an event handler method in your DarkEnable class, but your DarkEnable class does not implement Listener (you can have a class implement multiple things by separating them with commas in the first line of the class (public class DarkEnable implements CommandExecutor, Listener))
    2. Your command doesn't actually do anything except send messages even when a player has the appropriate permissions, and your event handler doesn't make any kind of check for if a player has enabled being a vampire.
      If you want vampireenable command to enable the potion effects for all players, just have the command set a boolean outside of the method, and have the listener make sure that the boolean is true before doing anything to players.
      If you want vampireenable command to work on a per-player basis, I think the simplest way would be to use a hashmap with player UUID as the key and boolean as the value, then in the event handler check for the moving player's uuid key in the hashmap, and if it exists check if the value is true, and only then apply any effects.
    Fix the first problem, then test, it should apply your potion effects. Then try the second problem, and come back with any questions.
     
    • Agree Agree x 2
  19. Strahan

    Benefactor

    Ugh. It's best to not glue totally different functionalities together in a class. It may be the easy way out, but it's not best practices. There is no reason to do it either.

    Code (Text):
     System.out.println("The plugin is starting up");
    This is not necessary. The system already sends enable/disable messages.

    Code (Text):
    getServer().getPluginManager().registerEvents((Listener) turnOn, this);
    The class will need to implement Listener, you can't just cast it to make it work.

    Code (Text):
    getCommand("vampireenable").setExecutor(turnOn);
    This would be better as a toggle, otherwise you have to screw around with having two commands; one for enable, one for disable.

    Code (Text):
    if(player.isOp() || player.hasPermission("vampireenable")){
    Two issues. First, if the player is op, checking for it is irrelevant. Just check if they have the permission. You are doing a basic string permission name check, so if they re op it will be true anyway. Second, give perms a hierarchy. Like vampireplugin.enable or whatever.

    Code (Text):
    @EventHandler
        public void onEnterDark(PlayerMoveEvent event){
            Block block = event.getTo().getBlock();
    I would add a check before that block line to ensure they actually moved. No sense in performing the functionality if they are just moving their head around (PlayerMoveEvent fires for that).

    Code (Text):
    if (lightLevel < 8){
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.CONFUSION, 60, 2));
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 60, 1));
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.WITHER, 60, 1));
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 60, 1));
            }else if (lightLevel == 15){
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.SATURATION, 120, 4));
                event.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 120, 1));
            }
    I'm confused; isn't that backwards? Shouldn't a vampire get the good benefits when light is low and be f'ed up when the light is 15?

    PS if I were to implement this, I'd do it as follows:
    Code (Text):
    Main Class {
      Set<UUID> vampires;

      onEnable() {
        getServer().getPluginManager().registerEvents(new PlayerMove(this), this);
        getCommand("vampire").setExecutor(new VampireCmd(this));
        populateVamps(true);
      }

      onDisable() {
        populateVamps(false);
      }

      isVampire(UUID) {
        Return whether or not they exist in the set
      }

      setVampire(UUID, status) {
        if (status) {
          Are they already in the set?  Return
          Add them to the set and return
        }
        Are they not in the set?  Return
        Remove from set
      }

      populateVamps(boolean loading) {
        If loading then load the Set from config and return
        Write the set to the config so you can read it at next restart
      }
    }

    public class PlayerMove implements Listener {
      Create a var to hold instance of your main class

      Create constructor to populate the aforementioned var

      PlayerMoveEvent e {
        Did they not really move?  Return
        Are they not a vampire?  Return

        Do light checks and apply effects.  I'd load effects from config, not hardcode
      }
    }

    public class VampireCmd implements TabExecutor {
      Create a var to hold instance of your main class

      Create constructor to populate the aforementioned var

      onTabComplete {
        Create a List<String>
        Switch on args length
        If it is 1:
          Do they have vampire.toggle permission?  If so, add "tog" to the List
          Do they have vampire.reload permission?  If so, add "reload" to the List
          Return StringUtil.copyPartialMatches for args[0].toLowerCase, the List, new ArrayList
        (Add more arg check/options as you expand plugin)
        }
        Return Collections.emptyList();
      }

      onCommand {
        Were no args passed?  Show help and return
        Switch on first argument, lowercased:
        If it is tog:
          Do they not have perms?  Yell and return
          If no extra args and sender isnt' a player, yell at them and return

          Player p = no extra args ? Cast sender to Player : get Player from server players
          If p is null, yell at them and return

          Call setVampire(p's UUID, !isVampire(p's UUID))
          Send a message letting them know it's enabled/disabled

        If it is reload:
          Do they not have perms?  Yell and return

          Reload the config & let them know

        Default:
          Show help and return
      }
    }
    Now that's just a "shootin' from the hip" layout off the top of my head, but is a general rough idea of how I approach things like this. Just food for thought.
     
    #19 Strahan, Jun 26, 2021
    Last edited: Jun 26, 2021
  20. The goal of the plugin is to create a reverse vampire experience (I know because this user posted a thread about it yesterday for a different question).
     
    • Like Like x 1