World unloading

Discussion in 'Plugin Development' started by s0undx, Jan 25, 2013.

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

    s0undx

    Hello!
    I'm trying to solve a problem in connection with Bukkit's world loading. I saw a topic on the Bukkit Forums about that, but i still can't unload my world. I'm struggling on that problem for 3 days and i can't figure it out so i would like to request your help.
    We are creating a minecraft PVP server, where players can join pvp matches(battlegrounds, arenas) and these matches can go independently from other matches. Here is the class for a PVP Match:
    Code:
    package hu.battlecraft.PVP;
     
    import hu.battlecraft.BattleCraft;
    import hu.battlecraft.Misc.Helper;
     
    import org.bukkit.Bukkit;
    import org.bukkit.Chunk;
    import org.bukkit.entity.Player;
     
    public class PVPMatch {
        public int ID;
        public MapTemplate template;
        public Integer ElapsedSeconds;
        public boolean Started = false;
        public String world_name;
        public Player[] Players;
     
        public PVPMatch(String world_name, MapTemplate template, Player[] players){
            this.template = template;
            this.Players = players;
            this.Started = false;
            this.world_name = world_name;
     
            if(Bukkit.getWorld(world_name) == null){
                Close();
            }
           
            for(Player p : players){
                p.teleport(Bukkit.getWorld(world_name).getSpawnLocation());
            }
        }
       
        public void Close(){
            if(Bukkit.getWorld(world_name) != null){
                for (Player player : Bukkit.getWorld(world_name).getPlayers()) {
                    player.teleport(Bukkit.getServer().getWorld("lobby").getSpawnLocation());
                    player.sendMessage("A világ amiben voltál többé nem létezik!");
                }
               
                if(Bukkit.getWorld(world_name).getLoadedChunks() != null && Bukkit.getWorld(world_name).getLoadedChunks().length > 0){
                    for(Chunk c : Bukkit.getWorld(world_name).getLoadedChunks()){
                        c.unload(false, true);
                    }   
                }
               
                BattleCraft.access.forceUnloadWorld(Bukkit.getWorld(world_name));
                BattleCraft.access.clearWorldReference(world_name);
                Bukkit.getServer().getScheduler().runTaskLaterAsynchronously(BattleCraft.inst, new WorldDeleter(world_name), 80);
            }
        }
       
        private class WorldDeleter implements Runnable
        {
            String[] worlds;
     
            static final long retryDelay = 30;
            static final int maxRetries = 5;
            int attempt;
     
            public WorldDeleter(String name)
            {
                attempt = 0;
                worlds = new String[1];
                worlds[0] = name;
            }
     
            public void run()
            {
                boolean allGood = true;
                for ( String world : worlds )
                    allGood = allGood && Helper.deleteWorld(world);
     
                if ( !allGood )
                    if ( attempt < maxRetries )
                    {
                        BattleCraft.logger.info("Retrying world data deletion...");
                        attempt++;
                        Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(BattleCraft.inst, this, retryDelay);
                        return;
                    }
                    else
                        BattleCraft.logger.warning("Failed to delete some world information!");
            }
        }
    }
    
    Note: BattleCraft.access is an instance of CraftBukkitAccess class from the plugin "Killer". I think i didn't create any reference to my worlds, but when i try to unload it it says "Failed to delete some world information!" so it still holds a reference somewhere, but i don't know where or what can i do.
    Thanks in advance.
    S0undX

    Anyone?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 31, 2016
  2. s0undx
    Your plugin or another one is probably holding a reference to the World preventing you from deleting it. I suggest you remove plugins one by one until you find the culprit.
     
  3. Offline

    s0undx

    What is a World reference EXACTLY? Any world class intance is a reference?

    PS: (I already removed all the plugins except my plugin and i can't unload the world.)
     
  4. s0undx
    Then maybe your plugin is holding a reference to the world preventing you from unloading it. To give you an idea of scope.

    Player ---> References Location ---> References Chunk ----> References World

    The main problem I'd guess is your Player[] array. Never store a player variable, only the players name as a String and then get the Player object when you need it.
     
  5. Offline

    s0undx

    Ok, thats right, but if you look on the code, you can see this part:
    Code:
        public void Close(){
            if(Bukkit.getWorld(world_name) != null){
                for (Player player : Bukkit.getWorld(world_name).getPlayers()) {
                    player.teleport(Bukkit.getServer().getWorld("lobby").getSpawnLocation());
                    player.sendMessage("A világ amiben voltál többé nem létezik!");
                }
               
                if(Bukkit.getWorld(world_name).getLoadedChunks() != null && Bukkit.getWorld(world_name).getLoadedChunks().length > 0){
                    for(Chunk c : Bukkit.getWorld(world_name).getLoadedChunks()){
                        c.unload(false, true);
                    }   
                }
    Which means that even if i hold a Player[] that reference will be pointing to my main world called "lobby".
    Even after updating my code, i can't unload the world, with the same error.
    Here is the new code of the updated class
     
  6. s0undx
    Ok but you don't know how it is updated behind the scenes. As a matter of principal you should never store a Player object unless you can be 100% sure it will be discarded.

    Just change your array of players to a String[] array. And then loop through it as you have done and just include.

    Player p = Bukkit.getServer().getPlayer(playerName);

    And try unloading your world that way, then if you have problems we know the cause is something else.
     
  7. Offline

    s0undx

  8. s0undx
    Sorry I must have skipped over that last part.

    Sorry I can't see anything else that would cause a problem. Maybe if you try calling Bukkit.unloadWorld(name, save)?
     
  9. Offline

    s0undx

  10. s0undx
    If that invokes the method then yes. Otherwise i'm not sure what the problem could be, sorry.
     
  11. Offline

    s0undx

    Adamki11s
    It does not invoke that method, but it does tha same thing, except its better according to FTWinston.
     
  12. s0undx
    Could you show the method? You may as way try the default Bukkit way to see if it works.
     
  13. Offline

    s0undx

    Adamki11s
    I already tried the default way, it wasn't working, so i was searching for like 2 days when i found this way, none of them works, i am so sad. :(
     
  14. s0undx
    Have you checked other plugins source code which do the same thing?
     
  15. Offline

    s0undx

    Adamki11s
    Yes, the only one i found was "Killer", and part of my code is copied from that plugin, but it still doesn't work.
    If you know any other plugins please tell me. :D
     
  16. s0undx
    I'll let you know if I find anything.
     
  17. Offline

    s0undx

    The problem was with 2 functions:
    1.forceUnloadWorld did not work properly for me.
    Finally here is my new code to unload a world: http://pastebin.com/raw.php?i=0CJWjU51
    2. clearReference could not handle properly a World which is not in the main folder. I am not an expert in IO functions, so i couldn't make a proper solution, but a hacky one:
    http://pastebin.com/raw.php?i=QEaxQqST
    Nevermind the debug messages, they were for me.

    (Solved, with the attached code you can delete the world.)

    Adamki11s
     
  18. Offline

    ZachBora

    I'm also interested in this for a future project.

    Even Multiverse can't delete worlds sometimes.
     
  19. s0undx
    The only thing I can think of now is maybe to force Java GC after you cleared all the world references and hope that it wipes them and maybe then you will be able to delete your world?

    Code:java
    1.  
    2. System.gc();
    3.  
     
  20. Offline

    s0undx

    Adamki11s

    My last post was trying to say its solved.
    With the code i attached i am able to delete my world from a simple IO function.
     
  21. s0undx
    I must've read over that :p.
     
  22. Dicsak egy magyar kezdő Dev :D Jó látni új arcokat :D

    Milenne a probléma?
     
Thread Status:
Not open for further replies.

Share This Page