Entity Chunk Issue

Discussion in 'Spigot Plugin Development' started by bman7842, May 12, 2015.

  1. I am currently working on a NPC command plugin. Basically you can spawn in multiple NPC that you can right click to run a command. The NPC you create is saved in the config file onDisable and then loaded onEnable. The problem is, users cannot see the NPC when they are loaded onEnable. If I type /reload the NPC spawns just fine but I have to be online and in the area for the Entity to spawn. I'm assuming this is Minecraft's typical Chunk loading system which is why I want a suggestion on how to fix it. If you have any advice please tell me!

    If you have any suggestions to add that may not involve my general question, please feel free to tell me what that suggestion is! There are no errors in output, like I said above, it appears to work. Minecraft's chunk loading system just isn't allowing for the Entity to be visible.

    The following are 2 classes, one is the Main class and the other is a class called spawnMob which handles most spawning of the entities. These classes are the only real necessary parts for finding a solution, if you need more info just ask!

    Main class:
    Code (Text):
    package me.bman7842.eclipsenpccommand;

    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.configuration.file.FileConfiguration;
    import org.bukkit.entity.Entity;
    import org.bukkit.event.EventHandler;
    import org.bukkit.plugin.PluginManager;
    import org.bukkit.plugin.java.JavaPlugin;

    import java.util.HashMap;

    /**
    * Created by brand_000 on 5/11/2015.
    */
    public class Main extends JavaPlugin {

        Commands cmds;
        EntityEvents entityevents;

        @EventHandler
        public void onEnable()
        {

            loadData();

            PluginManager pm = this.getServer().getPluginManager();

            //Load classes
            cmds = new Commands();
            entityevents = new EntityEvents();

            //Get Commands
            getCommand("spawnnpc").setExecutor(cmds);
            getCommand("removecustomentities").setExecutor(cmds);

            //Register Events
            pm.registerEvents(entityevents, this);
        }

        @EventHandler
        public void onDisable()
        {
            saveData();
            deleteCustomEntity();
        }

        public void saveData()
        {
            FileConfiguration config = getConfig();
            HashMap<Entity, String> pointCMDS = Utils.returnEntitiesCMDS();
            HashMap<Entity, String> pointNames = Utils.returnEntitiesName();
            HashMap<Integer, Entity> entities = Utils.returnEntities();
            if (pointNames.size() == 0) return;
            for (int i = 1; i <= entities.size(); i++)
            {
                String name = pointNames.get(entities.get(i));
                String command = pointCMDS.get(entities.get(i));

                Location l = entities.get(i).getLocation();
                String sep = ":";
                String location = (l.getX() + sep + l.getY() + sep + l.getZ() + sep + l.getPitch() + sep + l.getYaw() + sep + l.getWorld().getName());
                if (!config.contains("npc_list." + i))
                {
                    config.addDefault("npc_list." + name + ".command", command);
                    config.addDefault("npc_list." + name + ".location", location);
                    config.addDefault("npc_list." + name + ".type", entities.get(i).getType().toString());
                } else {
                    config.set("npc_list." + name + ".command", command);
                    config.set("npc_list." + name + ".location", location);
                    config.addDefault("npc_list." + name + ".type", entities.get(i).getType().toString());
                }
            }
            config.options().copyDefaults(true);
            saveConfig();
        }

        public void loadData()
        {
            FileConfiguration config = getConfig();

            if (config.contains("npc_list"))
            {
                for (String key : config.getConfigurationSection("npc_list").getKeys(false))
                {
                    String[] arg = (config.getString("npc_list." + key + ".location")).split(":");
                    Location location = new Location(Bukkit.getWorld(arg[5]), Double.parseDouble(arg[0]), Double.parseDouble(arg[1]), Double.parseDouble(arg[2]));
                    location.setPitch(Float.parseFloat(arg[3]));
                    location.setYaw(Float.parseFloat(arg[4]));

                    String type = config.getString("npc_list." + key + ".type");
                    String command = config.getString("npc_list." + key + ".command");

                    Entity spawnedMob = spawnMob.createNPC(location, type, key);
                    Utils.addSpawnedEntity(spawnedMob, command, key);
                }
            }
        }

        public void deleteCustomEntity()
        {
            Utils.removeAllCustomEntity();
        }
    }
    spawnMob class:
    Code (Text):
    package me.bman7842.eclipsenpccommand;

    import net.md_5.bungee.api.ChatColor;
    import net.minecraft.server.v1_8_R2.NBTTagCompound;

    import org.bukkit.Location;
    import org.bukkit.World;
    import org.bukkit.craftbukkit.v1_8_R2.entity.CraftEntity;
    import org.bukkit.entity.Entity;
    import org.bukkit.entity.EntityType;

    public class spawnMob {

        //TODO: Make the mob the given name
        public static Entity createNPC(Location l, String type, String name)
        {
            World world = l.getWorld();
            EntityType entitytype;
            if (type.equalsIgnoreCase("villager"))
            {
                entitytype = EntityType.VILLAGER;
                //world.spawnCreature(l, entity);
            } else if (type.equalsIgnoreCase("slime")) {
                entitytype = EntityType.SLIME;
            } else {
                entitytype = null;
            }
            if (entitytype != null)
            {
                Entity entityIjustSpawned = world.spawnCreature(l, entitytype);
                freezeEntity(entityIjustSpawned);
                String finalname = ChatColor.translateAlternateColorCodes('&', name);
                entityIjustSpawned.setCustomName(finalname);
                entityIjustSpawned.setCustomNameVisible(true);
                return entityIjustSpawned;
            }
            return null;
        }

        public static void freezeEntity(Entity en)
        {
              net.minecraft.server.v1_8_R2.Entity nmsEn = ((CraftEntity) en).getHandle();
              NBTTagCompound compound = new NBTTagCompound();
              nmsEn.c(compound);
              compound.setByte("NoAI", (byte) 1);
              nmsEn.f(compound);
          }
    }
     
     
  2. Listen for the ChunkLoadEvent, check for all entities in your file that are within the bounds of the chunk and spawn them. onEnable you then need to check getWorld().getLoadedChunks() and do the same.

    Keep in mind: The entities may not despawn when you unload the plugin or the chunk. So you should verify the entity is not already spawned (Use the UUIDs for that).
     
  3. Okay I'll try something like this. Thanks for the advice.
     
  4. Update,

    I tried @Possible idea and the code I work appears to be working. The client, on the other hand, is not working. The entity does still not appear to spawn and I don't know what could be the issue.

    Here is the code for the class I just wrote detecting ChunkLoadEvent
    Code (Text):
    package me.bman7842.eclipsenpccommand;

    import org.bukkit.World;
    import org.bukkit.entity.Entity;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.world.ChunkLoadEvent;

    /**
    * Created by brand_000 on 5/12/2015.
    */
    public class ChunkLoading implements Listener {

        @EventHandler
        public void chunkLoadEvent(ChunkLoadEvent e)
        {
            for (Entity en : Utils.returnEntities().values())
            {
                if (en.getLocation().getChunk() == e.getChunk() && (en.isDead() == true))
                {
                    World world = en.getWorld();
                    Entity fixedit = world.spawnEntity(en.getLocation(), en.getType());
                    fixedit.setCustomNameVisible(true);
                    fixedit.setCustomName(en.getCustomName());
    //                if (fixedit.isDead() == true)
    //                {
    //                    System.out.println(fixedit.getLastDamageCause().toString());
    //                    System.out.println("Entity you made is dead" );
    //                }
                }
            }
        }

    }
     
     
  5. I'm not sure if an entity can be dead before it is even spawned. Can you verify that?
     
  6. I can, tested it a minute it ago and the never spawned Entity returns true on the method isDead()