1.16.5 Adding Potion Effects help

Discussion in 'Spigot Plugin Development' started by LvC0x, Jun 14, 2021.

  1. Hey everyone, I am trying to execute a method that adds potion effects to any spider, it's pretty much working out perfectly, the problem is that for some reason it is returning a NullPointerException, here's my code:
    Code (Java):
    public void addMobEffects(Spider spider, int times) {
            try {
                HashMap<Integer, PotionEffect> potionEffects = new HashMap<>();
                potionEffects.put(1, new PotionEffect(PotionEffectType.GLOWING, Integer.MAX_VALUE, 0));
                potionEffects.put(2, new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0));
                potionEffects.put(3, new PotionEffect(PotionEffectType.JUMP, Integer.MAX_VALUE, 4));
                potionEffects.put(4, new PotionEffect(PotionEffectType.REGENERATION, Integer.MAX_VALUE, 3));
                potionEffects.put(5, new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, Integer.MAX_VALUE, 2));
                potionEffects.put(6, new PotionEffect(PotionEffectType.SLOW_FALLING, Integer.MAX_VALUE, 0));
                potionEffects.put(7, new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 2));
                potionEffects.put(8, new PotionEffect(PotionEffectType.INCREASE_DAMAGE, Integer.MAX_VALUE, 5));

                PotionEffect potionEffectToApply = potionEffects.get(ThreadLocalRandom.current().nextInt((8) + 1));

                if (spider.getActivePotionEffects().size() < times) {
                    if (!(spider.getActivePotionEffects().contains(potionEffectToApply))) {
                        spider.addPotionEffect(potionEffectToApply);
                    }
                    addMobEffects(spider, times);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    And here's the line I'm using to execute it:
    Code (Java):
    @EventHandler
        public void onCreatureSpawn(CreatureSpawnEvent e) {
            Entity ent = e.getEntity();
            if (ent instanceof Spider) {
                ((Spider) ent).getActivePotionEffects().clear();
                this.addMobEffects((Spider) ent, 5);
            }
        }
    Also here's the stack trace:
    Code (Java):
    [09:06:39 WARN]: java.lang.NullPointerException
    [09:06:39 WARN]:        at org.bukkit.craftbukkit.v1_16_R3.entity.CraftLivingEntity.addPotionEffect(CraftLivingEntity.java:423)
    [09:06:39 WARN]:        at org.bukkit.craftbukkit.v1_16_R3.entity.CraftLivingEntity.addPotionEffect(CraftLivingEntity.java:418)
    [09:06:39 WARN]:        at me.tlvcox.eternaldeathcore.EternalDeathCore.addMobEffects(EternalDeathCore.java:71)
    [09:06:39 WARN]:        at me.tlvcox.eternaldeathcore.EternalDeathCore.addMobEffects(EternalDeathCore.java:73)
    [09:06:39 WARN]:        at me.tlvcox.eternaldeathcore.EternalDeathCore.addMobEffects(EternalDeathCore.java:73)
    [09:06:39 WARN]:        at me.tlvcox.eternaldeathcore.EternalDeathCore.onCreatureSpawn(EternalDeathCore.java:155)
    [09:06:39 WARN]:        at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor19.execute(Unknown Source)
    [09:06:39 WARN]:        at org.bukkit.plugin.EventExecutor.lambda$create$1(EventExecutor.java:69)
    [09:06:39 WARN]:        at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:80)
    [09:06:39 WARN]:        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70)
    [09:06:39 WARN]:        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:624)
    [09:06:39 WARN]:        at org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory.callCreatureSpawnEvent(CraftEventFactory.java:722)
    [09:06:39 WARN]:        at org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory.doEntityAddEventCalling(CraftEventFactory.java:640)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.WorldServer.addEntity0(WorldServer.java:1302)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.WorldServer.addEntity(WorldServer.java:1203)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.WorldAccess.lambda$addAllEntities$0(WorldAccess.java:16)
    [09:06:39 WARN]:        at java.util.stream.Streams$StreamBuilderImpl.forEachRemaining(Streams.java:419)
    [09:06:39 WARN]:        at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742)
    [09:06:39 WARN]:        at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.WorldAccess.addAllEntities(WorldAccess.java:16)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.SpawnerCreature.spawnMobsInternal(SpawnerCreature.java:286)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.SpawnerCreature.spawnMobs(SpawnerCreature.java:212)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.SpawnerCreature.a(SpawnerCreature.java:188)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.ChunkProviderServer.lambda$tickChunks$14(ChunkProviderServer.java:868)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.PlayerChunkMap.forEachVisibleChunk(PlayerChunkMap.java:683)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.ChunkProviderServer.tickChunks(ChunkProviderServer.java:850)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.ChunkProviderServer.tick(ChunkProviderServer.java:767)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.WorldServer.doTick(WorldServer.java:576)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.MinecraftServer.b(MinecraftServer.java:1490)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.DedicatedServer.b(DedicatedServer.java:436)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.MinecraftServer.a(MinecraftServer.java:1342)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.MinecraftServer.w(MinecraftServer.java:1130)
    [09:06:39 WARN]:        at net.minecraft.server.v1_16_R3.MinecraftServer.lambda$a$0(MinecraftServer.java:291)
    [09:06:39 WARN]:        at java.lang.Thread.run(Thread.java:748)
    Any ideas on how to solve this?
     
  2. What's the line 71 ?

    Code (Text):
    [09:06:39 WARN]:        at me.tlvcox.eternaldeathcore.EternalDeathCore.addMobEffects(EternalDeathCore.java:71)
    [09:06:39 WARN]:        at me.tlvcox.eternaldeathcore.EternalDeathCore.addMobEffects(EternalDeathCore.java:73)
    [09:06:39 WARN]:        at me.tlvcox.eternaldeathcore.EternalDeathCore.addMobEffects(EternalDeathCore.java:73)
    [09:06:39 WARN]:        at me.tlvcox.eternaldeathcore.EternalDeathCore.onCreatureSpawn(EternalDeathCore.java:155)
     
  3. You clear the spider's effects even though he might not have any - I guess that causes the NPE, since getActivePotionEffects will return null, and you clear a null. But you better show us lines 71 and 155.
     
  4. Line 71:
    Code (Java):
    spider.addPotionEffect(potionEffectToApply);
    Line 73:
    Code (Java):
    addMobEffects(spider, times);
    Line 155:
    Code (Java):
    this.addMobEffects((Spider) ent, 5);
     
  5. I don't know the solution yet but I HIGHLY recommend moving the HashMap somewhere out of this function. Maybe put it in main class and make it static, but don't create it every time when you run the function.
     
  6. Well, I read the code and there is... some really bad pratices.
    1. When you need help, try to read the stack trace and give informations of where the error happens. You can also send the full code, so we can get the line manually with the stack trace, here you only a part of the EternalDeathCore class, we cannot see where are lines 73 and 71. Give partial informations is a waste of time :/
    2. Since there is two line 73 in the stack trace, it's probably with recursivity with addMobEffects(spider, times);. So, line 71 is two lines above with spider.addPotionEffect(potionEffectToApply);. The only null pointer you can get is with potionEffectToApply. The javadoc says this cannot be null. If you're not looking at the javadoc regularly, you should set your IDE to detect potential null pointer. Where this object can be null ? -> You are trying to get a non-existing key in the hashmap. Why ? Method nextInt from ThreadLocalRandom gives you a random integer between 0 (inclusive) and your bound (exclusive), it's said in the javadoc. But the hashmap has no key "0", it starts at 1. So when you get the random value 0, your PotionEffectToApply is null because there is no value associated with key 0 in the hashmap.
    3. Why do you build the hashmap everytime you call this method ? When spiders spawns, if you're unlucky, your code can build this hashmap more than 20 times per seconds (since recursivity create this again, for each spider, and if the random number is always the same, you will theorically get a infinite loop).
    4. Do not put a giant try catch with your entire code and a single e.printStackTrace(), ever. Let errors happens and try to fix them, do not hide that, it's really dangerous and you can easily get error spamming then crash if you do not pay attention.
    - Well, to fix your initial issue, you can set your potion effects in a ArrayList, then get a random index. If the list size is e.g. 10, you want to get a random index between 0 and 9 (inclusive), so nextInt(10) will works, since the bound 10 is exclusive.
    - To improve performances, you can create that potion effect list once, outside the method and get it everytime you need it.
    - Please remove this useless try catch.
    - You can also try to generate five random number in one time instead of using recursivity, theorically you can get an infinite loop if nextInt returns the same number everytime.


    No, look at the javadoc, it is said the return value is not null !
     
  7. Thanks for the advice! Your second suggestion made the trick, i removed the try catch and built the HashMap outside of the method.