How to spawn entity on server enable?

Discussion in 'Plugin Development' started by MrRoboMan, May 8, 2016.

Thread Status:
Not open for further replies.
  1. Offline

    MrRoboMan

    Hello guys.
    Show Spoiler

    Im not English-speaking, so sorry for all errors in my message)
    I not got help in my language speaking forum =(

    I want to do this:
    1. On server enable spawn some number of LivingEntities.
    2. Disable any actions with them.
    3. Kill all LivingEntities on disable server.
    Bots IS spawning on server enable.
    Bots IS`NOT protected from any actions.
    Bots IS`NOT killing on server disable..
    BUT, if I manually Load/Kill bots (writing LOAD/KILL) they is Loading and protected from any acrions/Killing..
    Bot.class (open)

    Code:
    package ua.gwm.BukkitPlugin.NEVENDAAR;
    
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.Location;
    import org.bukkit.entity.EntityType;
    import org.bukkit.entity.LivingEntity;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.entity.EntityCombustEvent;
    import org.bukkit.event.entity.EntityDamageByEntityEvent;
    import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
    import org.bukkit.event.player.AsyncPlayerChatEvent;
    
    import java.util.HashSet;
    import java.util.logging.Level;
    
    public class Bot implements Listener {
    
        private Bot() {
    
        }
    
        private static Bot instance = new Bot();
    
        public static Bot getInstance() {
            return instance;
        }
    
        public static HashSet<LivingEntity> botsEntity = new HashSet();
    
        @EventHandler
        public void testPlant(AsyncPlayerChatEvent event) {
            if (event.getMessage().equalsIgnoreCase("LOAD")) LoadAllBots();
            if (event.getMessage().equalsIgnoreCase("KILL")) KillAllBots();
        }
    
        public static void LoadAllBots() {
            try {
                long timeBefore = System.currentTimeMillis();
                int BFs = 0;
                for (ServerFile botFile : ServerFile.allSF.get(ServerFile.ServerFileType.BOT)) {
                    if (IsAllParamsSet(botFile)) {
                        Main.bot.spawn(botFile.name);
                        Main.JP.getLogger().log(Level.INFO, "Бот " + botFile.name + " загружен! UI=" + botFile.UI);
                        BFs++;
                    }
                }
                Main.JP.getLogger().log(Level.INFO, "Активация " + BFs + " ботов заняла (" + ((System.currentTimeMillis()-timeBefore)*1.0D)/1000 + "s).");
            } catch (Exception e) {
                Main.standardCatchException(e);
            }
        }
    
        public static void KillAllBots() {
            try {
                long timeBefore = System.currentTimeMillis();
                int botsDeleted = 0;
                for (LivingEntity entity : botsEntity) {
                    entity.remove();
                    Main.JP.getLogger().log(Level.INFO, "Бот " + entity.getName() + " удален!");
                    botsDeleted++;
                }
                Bukkit.getLogger().log(Level.INFO, "Удаление " + botsDeleted + " ботов заняло (" + ((System.currentTimeMillis()-timeBefore)*1.0D)/1000 + "s).");
            } catch (Exception e) {
                Main.standardCatchException(e);
            }
        }
    
        static boolean IsAllParamsSet(ServerFile bF) {
            return bF.isSet("DISPLAY_NAME") && bF.isSet("LOCATION") && bF.isSet("ENTITY_TYPE");
        }
    
        public void addBot(String name) {
            ServerFile.getInstance(name, ServerFile.ServerFileType.BOT);
        }
    
        public void setDisplayName(String name, String displayName) {
            if (ServerFile.IsCreated(name, ServerFile.ServerFileType.BOT)) {
                ServerFile botFile = ServerFile.getInstance(name, ServerFile.ServerFileType.BOT);
                botFile.set("DISPLAY_NAME", displayName);
            }
        }
    
        public void setLocation(String name, Location location) {
            if (ServerFile.IsCreated(name, ServerFile.ServerFileType.BOT)) {
                ServerFile botFile = ServerFile.getInstance(name, ServerFile.ServerFileType.BOT);
                botFile.set("LOCATION", Main.textLocation.format(location, false, false));
            }
        }
    
        public void setType(String name, EntityType type) {
            if (ServerFile.IsCreated(name, ServerFile.ServerFileType.BOT)) {
                ServerFile botFile = ServerFile.getInstance(name, ServerFile.ServerFileType.BOT);
                botFile.set("ENTITY_TYPE", type.toString());
            }
        }
    
        public void spawn(String name) {
            if (ServerFile.IsCreated(name, ServerFile.ServerFileType.BOT)) {
                Bukkit.getScheduler().runTask(Main.JP, () -> {
                    ServerFile botFile = ServerFile.getInstance(name, ServerFile.ServerFileType.BOT);
                    Location location = Main.textLocation.parse(botFile.getString("LOCATION"));
                    location.getChunk().load();
                    EntityType type = EntityType.valueOf(botFile.getString("ENTITY_TYPE"));
                    LivingEntity entity = (LivingEntity) location.getWorld().spawnEntity(location, type);
                    String displayName = botFile.getString("DISPLAY_NAME");
                    entity.setCustomName(ChatColor.translateAlternateColorCodes('&', displayName));
                    entity.setCustomNameVisible(true);
                    entity.setCollidable(false);
                    entity.setAI(false);
                    entity.setCanPickupItems(false);
                    entity.setRemoveWhenFarAway(false);
                    botsEntity.add(entity);
                    Main.JP.getLogger().log(Level.INFO, "Бот " + name + " заспавнен!");
                });
            }
        }
    
        @EventHandler
        public void onDamage(EntityDamageByEntityEvent event) {
            if (botsEntity.contains(event.getEntity()))
                event.setCancelled(true);
        }
    
        @EventHandler
        public void onTarget(EntityTargetLivingEntityEvent event) {
            if (event.getTarget() != null && botsEntity.contains(event.getTarget()))
                event.setCancelled(true);
        }
    
        @EventHandler
        public void onCombust(EntityCombustEvent event) {
            if (botsEntity.contains(event.getEntity()))
                event.setCancelled(true);
        }
    }
    
    ServerFile - config.
    ServerFile.allSF.get(ServerFile.ServerFileType.BOT) - returns configs with entity information to spawn.


    General Class Code (open)

    Code:
    @Override
        public void onEnable() {
            createPackages();
            saveConfigs();
            activateVariables();
            getServer().getPluginManager().registerEvents(listener, JP);
            getServer().getPluginManager().registerEvents(auth, JP);
            getServer().getPluginManager().registerEvents(chatManager, JP);
            getServer().getPluginManager().registerEvents(raceManager, JP);
            getServer().getPluginManager().registerEvents(gameManager, JP);
            getServer().getPluginManager().registerEvents(playerInfoKeeper, JP);
            getServer().getPluginManager().registerEvents(bot, JP);
            getLogger().info("NEVENDAAR включен!");
        }
    Code:
    @Override
        public void onDisable() {
            Bot.KillAllBots();
            getLogger().info("NEVENDAAR выключен!");
        }
    Code:
    private void activateVariables() {
            JP = this;
            listener = this;
            raceManager.activate();
            ServerFile.LoadAllSF();
            Bot.LoadAllBots();
            try {
                config = ServerFile.getInstance("config", ServerFile.ServerFileType.OUTSIDE);
            } catch (Exception e) {
                Main.standardCatchException(e);
            }
        }

    Can someone help me? :-(
     
    Last edited: May 8, 2016
  2. @MrRoboMan
    Maybe there's an exception in the spawning method, so the bot is being spawned but not added to the bots list.
    Check bot list's contents and debug all the spawning and creation methods.
     
  3. Offline

    MrRoboMan

    I made something ugly.. I go test it :D
    Something really UGLY (open)

    Code:
    public void spawn(String name) {
            if (ServerFile.IsCreated(name, ServerFile.ServerFileType.BOT)) {
                Bukkit.getScheduler().runTask(Main.JP, () -> {
                    try {
                        System.out.println(1);
                        ServerFile botFile = ServerFile.getInstance(name, ServerFile.ServerFileType.BOT);
                        System.out.println(2);
                        Location location = Main.textLocation.parse(botFile.getString("LOCATION"));
                        System.out.println(3);
                        location.getChunk().load();
                        System.out.println(4);
                        EntityType type = EntityType.valueOf(botFile.getString("ENTITY_TYPE"));
                        System.out.println(5);
                        LivingEntity entity = (LivingEntity) location.getWorld().spawnEntity(location, type);
                        System.out.println(6);
                        String displayName = botFile.getString("DISPLAY_NAME");
                        System.out.println(7);
                        entity.setCustomName(ChatColor.translateAlternateColorCodes('&', displayName));
                        System.out.println(8);
                        entity.setCustomNameVisible(true);
                        System.out.println(9);
                        entity.setCollidable(false);
                        System.out.println(10);
                        entity.setAI(false);
                        System.out.println(11);
                        entity.setCanPickupItems(false);
                        System.out.println(12);
                        entity.setRemoveWhenFarAway(false);
                        System.out.println(13);
                        botsEntity.add(entity);
                        System.out.println(14);
                        Main.JP.getLogger().log(Level.INFO, "Бот " + name + " заспавнен!");
                        System.out.println(15);
                        for (LivingEntity ent : botsEntity) {
                            System.out.println(ent.getName());
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }
        }
     
  4. @MrRoboMan Remember to tag, otherwise I could not to see your post.
     
  5. Offline

    MrRoboMan

    @Juancomaster1998 (is it "tag"? I firstly at this forum))
    Okey, i tested it, no one error, and entity is adding to bots list..
    But, entity can burn, and i can "collide" with entities... So setCollidable(), etc., events, not works too..
    Ugly console (open)

    [​IMG]


    And I got exception on server disabling, because i try delete Entity, but Entity is null (maybe died..).
    Code:
    [18:32:35] [Server thread/WARN]: [NEVENDAAR] null
    [18:32:35] [Server thread/WARN]: java.util.ConcurrentModificationException
    [18:32:35] [Server thread/WARN]:     at java.util.HashMap$HashIterator.nextNode(Unknown Source)
    [18:32:35] [Server thread/WARN]:     at java.util.HashMap$KeyIterator.next(Unknown Source)
    [18:32:35] [Server thread/WARN]:     at ua.gwm.BukkitPlugin.NEVENDAAR.Bot.KillAllBots(Bot.java:60)
    [18:32:35] [Server thread/WARN]:     at ua.gwm.BukkitPlugin.NEVENDAAR.Main.onDisable(Main.java:60)
    [18:32:35] [Server thread/WARN]:     at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:294)
    [18:32:35] [Server thread/WARN]:     at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin(JavaPluginLoader.java:364)
    [18:32:35] [Server thread/WARN]:     at org.bukkit.plugin.SimplePluginManager.disablePlugin(SimplePluginManager.java:424)
    [18:32:35] [Server thread/WARN]:     at org.bukkit.plugin.SimplePluginManager.disablePlugins(SimplePluginManager.java:417)
    [18:32:35] [Server thread/WARN]:     at org.bukkit.craftbukkit.v1_9_R1.CraftServer.disablePlugins(CraftServer.java:340)
    [18:32:35] [Server thread/WARN]:     at net.minecraft.server.v1_9_R1.MinecraftServer.stop(MinecraftServer.java:454)
    [18:32:35] [Server thread/WARN]:     at net.minecraft.server.v1_9_R1.MinecraftServer.run(MinecraftServer.java:595)
    [18:32:35] [Server thread/WARN]:     at java.lang.Thread.run(Unknown Source)
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 8, 2016
  6. @MrRoboMan
    Ohh xD, it's an concurrent exception.
    They are annoying... :mad:, caused because the way normal lists manages data.
    To fix them: Simply change your ArrayList to a ConcurrentSet.
     
  7. Offline

    I Al Istannen

    @Juancomaster1998
    @MrRoboMan
    Nah, better to use the Java way of dealing with it. An iterator. Call Set#iterator() and then you can call Iterator#remove() to remove the element without a concurrent modification exception. Pretty sweet.

    EDIT: There are different causes for a ConcurrentModification. I just have explained to deal with one, removing elements from a Collection while iterating over it. If you access a data structure from multiple Threads, you will need to use one, that provides support for it. There are multiple of these, like CopyOnWriteArrayList and ConcurrentHashMap or similar. Just google if you really need them.
     
    Last edited: May 8, 2016
  8. @I Al Istannen
    Yeah, but I don't think he is accustom to use iterators. Also, if he's accessing it from multiple threads that will not work, so the best way to simply globaly fix all concurrentModification exceptions in lists is using a concurrent set.
     
  9. Offline

    MrRoboMan

    @Juancomaster1998
    @I Al Istannen
    I replaced my HashSet to io.netty.util.internal.ConcurrentSet, and replaced for-each cycle to iterator cycle (but iterators - really dont comfortable for me.. =():
    Killing Method & new Set (open)

    Code:
        static ConcurrentSet<LivingEntity> botsEntity = new ConcurrentSet();
    
    Code:
    public static void KillAllBots() {
            try {
                long timeBefore = System.currentTimeMillis();
                int botsDeleted = 0;
                Iterator<LivingEntity> iterator = botsEntity.iterator();
                while (iterator.hasNext()) {
                    LivingEntity nextEntity = iterator.next();
                    nextEntity.remove();
                    Main.JP.getLogger().log(Level.INFO, "Бот " + nextEntity.getName() + " удален!");
                    iterator.remove();
                    botsDeleted++;
                }
                Bukkit.getLogger().log(Level.INFO, "Удаление " + botsDeleted + " ботов заняло (" + ((System.currentTimeMillis()-timeBefore)*1.0D)/1000 + "s).");
            } catch (Exception e) {
                Main.standardCatchException(e);
            }
        }

    And now i have`not exceptions on disabling server(on bots killing), thanks both of you :D
    But anyway, bots dont works now.. They`re spawning, but I can interact with bots..
    And when I spawn them by hand (writing "LOAD") they are spawning and i cant interact with them..
     
  10. Offline

    I Al Istannen

    @MrRoboMan
    I don't think you need a Concurrent Set there at all. And it is from io.netty, so not a normal Java class. This is no problem, but it adds a dependency. You could create a ConcurrentSet like this. But a concurrent set is only needed if you access an object from multiple threads at the same time. I don't believe you do this. This means a normal Set like HashSet should be enough.

    But the iterator is right. It might look strange, but is your best bet in this case as far as I know.

    The error you describe has nothing to do with removing them, but rather with how you create them. I would guess you never add the loaded bots to bot list. I can't tell and I don't understand every part of your code, so it might be wrong.

    You also seem to like static a lot, I am not sure if you need it in every case. I haven't seen your whole code, but it looks quite cryptic at parts. You may consider documenting it (if you haven't already) to be able to debug/change this in a few weeks/months.

    Also I would encourage you to follow Naming conventions (a bit old, but still valid). It makes the code much more readable.
     
  11. @MrRoboMan
    ConcurrentSet is a set, not a map, like hashmap. Try with ConcurrentHashMap.
     
  12. Offline

    MrRoboMan

    But what for? I dont need map.. I need list/set to keep entities..
     
Thread Status:
Not open for further replies.

Share This Page