Solved Cannot find the source of a null pointer...

Discussion in 'Spigot Plugin Development' started by chmod_777, Jan 11, 2020.

  1. Hi,
    Usually this is a problem I can solve on my own, but for whatever reason, I cannot find out why im getting a null pointer exception. My code has a listener which waits for an entity death and then calls an event which compares the entity type and tool used to kill against challenges that I defined in my config, but whenever I call 'getDesiredChallenge(command)' in 'EntityDeathListener', I get a null pointer. I have tried debugging in various places:
    1. in the EntityDeathEvent listener
    2. Right before the function is called, I print out the command which is not null
    3. When processing data from config into Challenge classes which then go into a list

    The only place I have not been able to debug at is in the function that is called 'getDesiredChallenge(String command)' in the ChallengeHandler class and the function in that function called 'checkConditions(Challenge chal, String command)' in the same class. Ive tried printing variable names to console within these functions, but they don't print which leads me to suspect that the error occurs before these functions are ever called.

    Code (Text):
    [22:02:12] [Server thread/ERROR]: Could not pass event EntityDeathChallengeEvent to Seasons v1.0-R0.1-SNAPSHOT
    org.bukkit.event.EventException: null
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:320) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:529) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:514) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.il0c4l.seasons.listeners.EntityDeathListener.onEntityDeath(EntityDeathListener.java:39) ~[?:?]
            at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
            at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
            at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
            at java.lang.reflect.Method.invoke(Method.java:567) ~[?:?]
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:316) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:529) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:514) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at org.bukkit.craftbukkit.v1_15_R1.event.CraftEventFactory.callEntityDeathEvent(CraftEventFactory.java:720) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.EntityLiving.d(EntityLiving.java:1326) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.EntityLiving.die(EntityLiving.java:1275) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.EntityLiving.damageEntity(EntityLiving.java:1122) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.EntityHuman.attack(EntityHuman.java:1085) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.EntityPlayer.attack(EntityPlayer.java:1519) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.PlayerConnection.a(PlayerConnection.java:1878) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.PacketPlayInUseEntity.a(SourceFile:68) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.PacketPlayInUseEntity.a(SourceFile:13) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.PlayerConnectionUtils.lambda$0(PlayerConnectionUtils.java:19) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.TickTask.run(SourceFile:18) [spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.IAsyncTaskHandler.executeTask(SourceFile:144) [spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.IAsyncTaskHandlerReentrant.executeTask(SourceFile:23) [spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.IAsyncTaskHandler.executeNext(SourceFile:118) [spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.MinecraftServer.aZ(MinecraftServer.java:917) [spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.MinecraftServer.executeNext(MinecraftServer.java:910) [spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.IAsyncTaskHandler.awaitTasks(SourceFile:127) [spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.MinecraftServer.sleepForTick(MinecraftServer.java:894) [spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at net.minecraft.server.v1_15_R1.MinecraftServer.run(MinecraftServer.java:827) [spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            at java.lang.Thread.run(Thread.java:835) [?:?]
    Caused by: java.lang.NullPointerException
            at net.il0c4l.seasons.listeners.EntityDeathListener.onEntityDeathChallengeEvent(EntityDeathListener.java:46) ~[?:?]
            at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
            at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
            at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
            at java.lang.reflect.Method.invoke(Method.java:567) ~[?:?]
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:316) ~[spigot-1.15.1.jar:git-Spigot-492a779-b98e2de]
            ... 32 more
     

    Code (Java):
    public final class EntityDeathListener implements Listener {

        private ChallengeHandler challengeHandler;
        private DataHandler storage;

        public EntityDeathListener(Main plugin){
            Bukkit.getServer().getPluginManager().registerEvents(this, plugin);
            challengeHandler = plugin.getChallengeHandler();
            storage = plugin.getStorage();
        }

        @EventHandler
        public void onEntityDeath(EntityDeathEvent e){
            if(e.getEntity().getKiller() == null){
                return;
            }
            Player player = e.getEntity().getKiller();
            EntityType entityType = e.getEntityType();
            Material tool = e.getEntity().getKiller().getInventory().getItemInMainHand().getType();
            EntityDeathChallengeEvent event = new EntityDeathChallengeEvent(player, entityType, tool);
            Bukkit.getServer().getPluginManager().callEvent(event);
        }

        @EventHandler
        public void onEntityDeathChallengeEvent(EntityDeathChallengeEvent e){
            String command = "EntityDeath.EntityType:" + e.getEntityType().name() + ".Material:" + e.getTool().name();
            Challenge desired = challengeHandler.getDesiredChallenge(command);
            Entry entry = storage.getEntry(e.getPlayer().getUniqueId());
            if(desired == null || entry == null){
                return;
            }
            entry.incrementProgress();
            if(entry.getProgress() == desired.getCount()){
                entry.incrementProgress();
                //do reward stuff here
                e.getPlayer().sendMessage("You've completed the challenge!");
            }
        }

    }

    Code (Java):
    public class ChallengeHandler {

        private FileConfiguration config;
        private static ArrayList<Challenge> availableChallenges;

        public ChallengeHandler(Main plugin){
            config = plugin.getConfig();
            availableChallenges = buildChallengeList();
        }

        public Challenge buildChallenge(ConfigurationSection section){
            ConfigurationSection challengeSection = section.getConfigurationSection("challenge");
            String activationEvent = challengeSection.getString("activationEvent");
            String conditions = challengeSection.getString("conditions");
            int count = challengeSection.getInt("count");

            Challenge challenge = new Challenge(activationEvent, conditions, count);
            return challenge;
        }

        public ArrayList<Challenge> buildChallengeList(){
            ArrayList<Challenge> challengeList = new ArrayList<Challenge>();

            for(String sec : config.getConfigurationSection("Tiers").getKeys(false)){
                ConfigurationSection subSec = config.getConfigurationSection("Tiers." + sec);
                challengeList.add(buildChallenge(subSec));
            }
            return challengeList;
        }

        public boolean checkConditions(Challenge challenge, String command){
            if(ChallengeEvent.class.getName().contains(challenge.getActivationEvent())){
               if(command.contains(challenge.getCondition())){
                   return true;
               }
            }
            return false;
        }

        /*public boolean checkChallengesForCondition(String command){
            for(Challenge chal : availableChallenges){
                if(checkConditions(chal, command)){
                    return true;
                }
            }
            return false;
        }*/


        public Challenge getDesiredChallenge(String command){
            for(Challenge chal : availableChallenges){
                if(checkConditions(chal, command)){
                    return chal;
                }
            }
            return null;
        }

        public static ArrayList<Challenge> getAvailableChallenges(){
            return availableChallenges;
        }
    }

    Note: in 'getDesiredChallenge(String command)', Ive tried printing something to console before the function returns null, and nothing prints.

    Code (Java):
    public class Main extends JavaPlugin {

        private DataHandler storage;
        private ChallengeHandler challengeHandler;

        @Override
        public void onEnable(){
            getLogger().log(Level.INFO, "Enabling seasons plugin!");
            saveDefaultConfig();
            setStorageType();
            new EntityDeathListener(this);
            new PlayerLoginListener(this);
            challengeHandler = new ChallengeHandler(this);

        }

        @Override
        public void onDisable(){
            if(storage.getClass().toString().contains("net.il0c4l.seasons.storage.MySQLDataHandler")){
                ((MySQLDataHandler) storage).closeConnection();
            }
        }


        public void setStorageType(){
            String type = DataHandler.getStorageType(getConfig());
            switch(type){
                case "mysql":
                    Map<String, Object> creds = getConfig().getConfigurationSection("storage.mysql").getValues(false);
                    storage = new MySQLDataHandler(this, (String) creds.get("username"), (String) creds.get("password"), (String) creds.get("host"), (String) creds.get("port"), (String) creds.get("dbname"), (String) creds.get("useSSL"));
                    getLogger().log(Level.INFO, "CONNECTED");
                    break;
                case "sqlite":
                    storage = new SQLiteDataHandler(this);
                    break;
                case "default":
                    getLogger().log(Level.WARNING, "No storage type chosen. Defaulting to flat file storage!");
                    getConfig().set("storage.yaml.use", true);
                case "yaml":
                    storage = new FlatDataHandler(this, "data.yml");
                    break;

            }
            getLogger().log(Level.INFO, "Set storage type to " + type);
        }

        public ChallengeHandler getChallengeHandler(){
            return challengeHandler;
        }

        public DataHandler getStorage(){
            return storage;
        }

    Code (Java):
    public class Challenge {

        private String activationEvent;
        private String condition;
        private int count;

        public static final String[] VALID_REWARD_TYPES = {"ITEM", "MONEY"};
        public static final String[] VALID_CHALLENGE_TYPES = {"EntityDeathChallengeEvent"};

        public Challenge(String activationEvent, String condition, int count){
            this.activationEvent = activationEvent;
            this.condition = condition;
            this.count = count;
        }

        public boolean isRewardType(String rewardType){
            int check = 0;
            for(int i=0; i<VALID_REWARD_TYPES.length; i++){
                if(rewardType.equals(VALID_REWARD_TYPES[i])){
                    check++;
                }
            }
            if(check != 1){
                return false;
            } return true;
        }

        public boolean isChallengeType(String challengeType){
            int check = 0;
            for(int i = 0; i< VALID_CHALLENGE_TYPES.length; i++){
                if(challengeType.equals(VALID_CHALLENGE_TYPES[i])) {
                    check++;
                }
            }
            if(check != 1){
                return false;
            } return true;
        }

        public String getActivationEvent(){
            return activationEvent;
        }

        public String getCondition(){
            return condition;
        }

        public int getCount(){ return count; }

    Code (YAML):
    prefix: '&8[&6&lSeasons&8]'

    Tiers
    :
      0
    :
        challenge
    :
          activationEvent
    : 'EntityDeath'
          conditions
    : 'EntityType:PIG'
          count
    : 1
        reward
    :
          type
    : 'material:STONE'
          amount
    : 10
         
      1
    :
        challenge
    :
          activationEvent
    : 'EntityDeath'
          conditions
    : 'EntityType:COW'
          count
    : 1
        reward
    :
          type
    : 'material:STONE'
          amount
    : 10


    storage
    :
      type
    :
        mysql
    : false
        sqlite
    : false
        yaml
    : true

      mysql
    :
        host
    : 'localhost'
        port
    : '3306'
        username
    : 'dbworker'
        password
    : '*****'
        dbname
    : 'seasons'
        useSSL
    : 'false'

    Any help Is appreciated thanks!

    Note: knowing me, its probably something stupid that someone will find in seconds...
     
  2. md_5

    Administrator Developer

    I mean its on line 46, can't help you further because you've cut out the imports so the lines don't match
     
  3. The line is:
    Code (Java):
    Challenge desired = challengeHandler.getDesiredChallenge(command)
     
  4. md_5

    Administrator Developer

    ChallengeHandler is null because you construct the EntityDeathListener before you set the challenge handler in onEnable
     
  5. ugh I knew it was something stupid. Thanks anyways.