unloadworld returning false

Discussion in 'Plugin Development' started by Rockslide, Aug 10, 2012.

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

    Rockslide

    What can cause this to return false? (meaning it failed)

    getServer().unloadWorld(world, false);

    I perform the following checks before calling it, yet it still returns false sometimes:

    - world is not the main world
    - world is not null
    - amount of players on the world = 0
    - amount of livingentities on the world = 0
    - amount of entities on the world = 0
    - amount of loaded chunks = 0

    What else can cause it to fail?

    (It does not produce any console errors.)
     
  2. Offline

    Builder4Free

    Try
    Code:
    Bukkit.unloadWorld(world, false);
     
  3. Offline

    Rockslide

    Ok I tried, but that doesn't help :/

    Any other tips?
     
  4. Offline

    Njol

    This is CraftBukkit's source of CraftServer.unloadWorld():
    Code:
        public boolean unloadWorld(World world, boolean save) {
            if (world == null) {
                return false;
            }
    
            WorldServer handle = ((CraftWorld) world).getHandle();
    
            if (!(console.worlds.contains(handle))) {
                return false;
            }
    
            if (!(handle.dimension > 1)) {
                return false;
            }
    
            if (handle.players.size() > 0) {
                return false;
            }
    
            WorldUnloadEvent e = new WorldUnloadEvent(handle.getWorld());
            pluginManager.callEvent(e);
    
            if (e.isCancelled()) {
                return false;
            }
    
            if (save) {
                handle.save(true, (IProgressUpdate) null);
                handle.saveLevel();
                WorldSaveEvent event = new WorldSaveEvent(handle.getWorld());
                getPluginManager().callEvent(event);
            }
    
            worlds.remove(world.getName().toLowerCase());
            console.worlds.remove(console.worlds.indexOf(handle));
    
            return true;
        }
    
    There are 5 cases in which this method returns false:
    • The given world is null
    • The world is not loaded
    • 'dimension' is <= 1 (no clue)
    • There are players in the world
    • The WorldUnlaodEvent is cancelled
    My best guess is that the event is cancelled by some other plugin.
     
  5. Offline

    Rockslide

    Thanks Njol, I haven't solved the problem yet, but your info gives me something to work with.

    I will let everyone know when and how I solve it.

    I'm still having trouble figuring this out.

    How can I test the 5 causes?
    1) is easy
    2) how do I check this one?
    3) how do I check this one?
    4) I check this with world.getPlayers().size()
    5) I tried disabling most of the other plugins. And I added the following listener:
    Code:
        @EventHandler(priority = EventPriority.HIGHEST)
        public void onWorldUnload(WorldUnloadEvent event) {
            event.setCancelled(false);
        }
    It still fails at specific moments. I added this to diagnose the problem:
    Code:
                if (Bukkit.unloadWorld(plugin.activeWorld, false)) {
                    plugin.console.sendMessage(ChatColor.GREEN+ "CastleSiege: Success.");
                    plugin.activeWorld = null;
                }
                else {
                    plugin.console.sendMessage(ChatColor.DARK_RED + "CastleSiege: Failed.");
                    plugin.console.sendMessage(ChatColor.DARK_RED + "CastleSiege: WorldName: " + plugin.activeWorld.getName());
                    plugin.console.sendMessage(ChatColor.DARK_RED + "CastleSiege: WorldNull: " + (plugin.activeWorld == null));
                    plugin.console.sendMessage(ChatColor.DARK_RED + "CastleSiege: WorldOnList: " + (plugin.getServer().getWorlds().contains(plugin.activeWorld)));
                    plugin.console.sendMessage(ChatColor.DARK_RED + "CastleSiege: Players: " + plugin.activeWorld.getPlayers().size());
                    plugin.console.sendMessage(ChatColor.DARK_RED + "CastleSiege: LivingEntities: " + plugin.activeWorld.getLivingEntities().size());
                    plugin.console.sendMessage(ChatColor.DARK_RED + "CastleSiege: Entities: " + plugin.activeWorld.getEntities().size());
                    plugin.console.sendMessage(ChatColor.DARK_RED + "CastleSiege: LoadedChunks: " + plugin.activeWorld.getLoadedChunks().length);
                    plugin.getServer().shutdown();
                }
    
    The result:

    CastleSiege: Failed.
    CastleSiege: WorldName: Conwy
    CastleSiege: WorldNull: false
    CastleSiege: WorldOnList: true
    CastleSiege: Players: 0
    CastleSiege: LivingEntities: 0
    CastleSiege: Entities: 0
    CastleSiege: LoadedChunks: 0


    What else can I do?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 27, 2016
  6. Offline

    Njol

    I guess we can rule out #1, #2, #4 and #5. Remains the 'handle.dimension <= 1' check.
    Weird thing is that I can't find any field 'dimension' in either World nor WorldServer...
     
  7. Offline

    travja

    I think the problem is, the world file is still there in the server directory, it hasn't been deleted.. I was messing around with Multiverse the other day and couldn't make a new world because the name was already taken by a unloaded world...
     
  8. Offline

    Rockslide

    Can you elaborate on that travja?
    What exactly do you mean by "world file"? I don't want to delete the world, just unload it and then load a different one, and later load the first one again.

    If you say you couldn't make the new world, shouldn't the problem be with createWorld()?
    It is unloadWorld() that fails.

    About the !(dimension > 1) failing,
    I took this from the CraftBukkit source:
    Code:
            int dimension = 10 + console.worlds.size();
            boolean used = false;
            do {
                for (WorldServer server : console.worlds) {
                    used = server.dimension == dimension;
                    if (used) {
                        dimension++;
                        break;
                    }
                }
            } while(used);
    
    It looks like some sort of ID or index. It seems to search for the lowest integer (above 10 + console.worlds.size()) that is not taken yet.

    I don't understand it much... do you guys?
     
  9. Offline

    travja

    Nope... completely confused..
     
  10. Offline

    Njol

    IIRC you can't unload the main world which might have 'dimension' 0.
     
  11. Offline

    Rockslide

    It's not the main world :/
     
  12. Offline

    Njol

    Can you please try to delay the unloading of the world by one tick? There might still be some nms players in the world even though there are no Bukkit players in it.
     
  13. Offline

    Rockslide

    I already do.

    I have a syncrepeatingtask that looks like this:

    Code:
    run () {
        if (player.size > 0) {
            remove players.
            return;
        }
        if (livingentities.size > 0) {
            remove livingentities.
            return;
        }
        if (entities.size > 0) {
            remove entities.
            return;
        }
     
        unload all chunks;
     
        unloadWorld;
        if (succes) {
            stop repeating task;
        } else {
            print error;
        }
    }
    Note the returns; If anything is found left in the world, the repeating task starts over (skipping 2 ticks)


    Another thing that may be relevant:
    I have been getting some "failed to add Player errors". Sometimes I see glitched players floating in the lobby world (main), where people spawn. They show up as floating players and stay there but the user isn't actually online. When that player tries to join the server, I get that "failed to add Player" error. It says player is already in chunk.

    I remove those manually with a command I made just for that purpose.

    I have so far been unable to fix the cause.

    I don't know whether or not this affects the world failing to unload.
     
  14. Offline

    Njol

    Are you using a sync or async repeating task?
     
  15. Offline

    Rockslide

    sync

    without the "a".

    What does Player.isValid() do? The documents don't describe it.

    I added a Player.isValid() check before teleporting people to the lobby, and it returns false very often.

    Njol

    Small bump :)

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 27, 2016
  16. Offline

    Njol

    CarftEntity.isValid() is one line: isAlive() && entity.valid
    So either most of your players are dead very often or their entity is not 'valid' which basically doesn't help much =P

    You could try to copy the unloadWorld() code into your code and instead of returning false print an error so that we'll at least exactly know why it returns false.
     
    Rockslide likes this.
  17. To get 100% sure that no other plugin is interferring try this:
    Code:java
    1. @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
    2. public void onWorldUnload(WorldUnloadEvent event)
    3. {
    4. String result;
    5. if(event.isCancelled())
    6. result = "cancelled by another plugin!";
    7. else
    8. result = "not cancelled!";
    9. System.out.print("World unloading was "+result);
    10. }
     
  18. Offline

    Rockslide

    unloadWorld() needs access to CraftServer's private LinkedHashMap worlds. I can't just copy it into my plugin.
    Or is there a way I don't know about?

    V10lator
    Thanks, my server is running that code now, I will report back when it fails again :)
     
  19. Reflections. ;)
     
    Rockslide likes this.
  20. Offline

    Rockslide

    V10lator

    Ok when an unload is successful, it said "World unloading was not cancelled!"
    So your monitoring code works.

    But when an unload fails, nothing is displayed. That means the event is never fired. And that means unloadWorld() returns false before it gets to the event firing.

    So it has to be one of these:
    Code:
            if (world == null) {
                return false;
            }
     
            WorldServer handle = ((CraftWorld) world).getHandle();
     
            if (!(console.worlds.contains(handle))) {
                return false;
            }
     
            if (!(handle.dimension > 1)) {
                return false;
            }
     
            if (handle.players.size() > 0) {
                return false;
            }
    world is not null, so it's down to 3 possible causes.

    Maybe I can use those 'reflections' to test the world handle values? I'll see if I can figure out how to do that.
    Thank you both so far :)
     
  21. Offline

    Firefly

    I'm guessing handle.dimension is how The End/Nether/Normal World are differentiated? :confused: You seem to have a weird issue here, have you tried adding a few second delay between the code before the unload and the actual unload? That may cause a problem.
     
  22. Offline

    Rockslide

    I figured out what makes it fail.

    When unloadWorld() fails, it is because this:

    CraftWorld cw = (CraftWorld)plugin.activeWorld;
    WorldServer handle = cw.getHandle();
    handle.players.size();

    returns 1

    eventhough this:

    plugin.activeWorld.getPlayers().size();

    returns 0


    So my guess is Minecraft thinks there is 1 player still in the world, but Bukkit doesn't see it.

    I will try to do
    handle.players.clear();
    before I call unloadWorld.

    Nonetheless, this is a bug that should be addressed, isn't it?
     
  23. ehm...
    Did you really schedule it?
     
  24. Offline

    Rockslide

    V10lator

    Yes, I do this:

    Code:
    Teleport everyone to lobby world;
     
    TaskUnloadWorld unloadTask = new TaskUnloadWorld(this, map, start);
    unloadTask.taskId = getServer().getScheduler().scheduleSyncRepeatingTask(this, unloadTask, 100, 20);
    
    I really think this has to with it:
    [​IMG]

    As I explained above, I've been getting these errors a lot.
     
  25. Offline

    Njol

    These errors are common in 1.3.1-R1, you likely have to wait for Bukkit to fix them.
     
  26. Offline

    ensirius

    Confirm same bug on 1.2.5.

    return dimension -1 on Nether.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 27, 2016
  27. Offline

    the_merciless

    Have a search for 'multiverse adventures' This plugin seems to do exactly what your trying to do. Could help you out, but even the multiverse devs cant get it working perfect, its known to crash the server on occasions.
     
  28. Offline

    DerFlash


    Same here, thanks for the hint, so I could find out that we're in fact having the same problem.

    Unloading arena world
    Failed!
    Players on world: 0
    HandlePlayers on world: 1
    Sounds a bug (in MC Core?!) to me too, since Multiverse is clearly teleporting users out of the world before within its unloadWorld() function we're using here.
     
  29. Offline

    Pr07o7yp3

    Yes, I know.. This is very old thread but I have this problem too.

    So, anyone knows how to fix it? Bukkit can't unload the world and my plugin stop works.
    I think to try something. To check who is the player in handle.players and kick him.. I'm not sure if it will works but I don't have other ideas..

    Haha, I think I found my problem. :D
    I use CombatTag plugin and it leaves NPC in that world. :D

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 27, 2016
Thread Status:
Not open for further replies.

Share This Page