Solved Unknown World and Bukkit.getWorld(String) returns null

Discussion in 'Plugin Development' started by SmileOfDeath130, May 23, 2021.

  1. Offline

    SmileOfDeath130

    This was also posted on Spigot
    Hey guys, I've been trying to code a world management mod allowing users to separate different worlds into groups of worlds such as overworld, nether, and end. I've been recently running into errors where Bukkit seems to not recognize other worlds even though they are present within the server folder. The first error that happens is when getConfig() is called. The first time this happens, if there is a last known location for a player in any world other than the "main" world, then an error is thrown saying that the method failed to deserialize the location object because of an unknown world. It then erases the location object. To me, it seems that Bukkit is not recognizing any world other than the main world because all of the location objects are erased other than that of the main world. The second error that has recently started happening seems to be similar. When the tpworld command is entered, an exception is thrown saying that Bukkit.getWorld(String) returns null. This doesn't make any sense because I've verified that the string being passed is the correct name of the world. I need some help here. It seems like these errors are very similar, because both deal with Bukkit being unable to correctly load or recognize worlds. Any help would be appreciated. I've also included all the necessary files.
     

    Attached Files:

  2. Offline

    xpaintall

    @SmileOfDeath130 In your onCommand boolean, you shouldn't be using
    Code:
    Player player = Bukkit.getPlayerExact(sender);
    A better alternative is to use the
    Code:
    Player player = (Player) sender;
    and also you want to check if the sender is a player (because you are teleporting the player, not the console). Also, what is the 115th line in your WorldMod class?
     
  3. Offline

    SmileOfDeath130

    I will do the first suggestion for sure. I didn't even know that it was possible. My WorldMod class is contained in WorldMod.txt. The 115th line is "Location playerDestination = Bukkit.getWorld(mainWorld).getSpawnLocation();"
    The error code is saying that Bukkit.getWorld(mainWorld) is returning null and therefore cannot have the getSpawnLocation method called. However, I've made sure that mainWorld is a string and is the proper name of the world that I want to get.
     
  4. Offline

    davidclue

    @SmileOfDeath130 Use a try-catch statement to avoid the error but anyways your problem is that you just dragged and dropped world files in the folder expecting them to work however Minecraft servers can't register new worlds that are dropped in I'm not sure why, you need to use another plugin to create your worlds in your server or just add a command to create new worlds to your plugin it's really easy to do and is like 3 lines.
    Code:
    WorldCreator wc = new WorldCreator("MyWorldName");
    wc.environment(Environment.NORMAL);
    wc.createWorld();
    Then just go inside the newly created world folder which will be in your server folder and swap out the data folder with your custom world's data folder. It's weird and will take some time since you have so many worlds but that's the only way I believe you can do this.
     
  5. Offline

    SmileOfDeath130

    Yes I thought of that, but the problem with that is that the server originally managed to teleport me to the worlds and allowed me to play on it. It was only after a couple of changes to code that this problem started happening. I don't remember changing any significant piece of code that could change this functionality though. I can still try your suggestion, however, it seems a little bit weird if that is the problem. How do I fix the problem with deserialization? If it is necessary, I can always change and create my own functions for serialization and deserialization. I did some research before posting this help question, and other people have seemed to have the same problem. However, nobody seems to have come to a conclusive answer that would work for me. Additionally, my main world for the server - "World Selector" works just fine, even though the world folder is from a vanilla Minecraft 1.16.5 version. It seems that the problem is with the server loading worlds other than the main one defined by the server.

    I also looked through the source code for bukkit but couldn't find an answer there. Maybe I just can't follow advanced code like that.

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

    Shqep

    @davidclue got a good point that you may not have Bukkit recognize your worlds without directly creating it. One thing he didn't mention is that you could put the world folder in the server directory then just some checking:
    Code:Java
    1. public final void getWorld(final String name) {
    2. if(Bukkit.getWorld(name) == null)
    3. return WorldCreator(name).environment(Environment.NORMAL).createWorld();
    4. else return Bukkit.getWorld(name);
    5. }


    If the directory "name" already exists, it just loads the world with those files instead of creating an entirely new world. If the directory doesn't exist, only then will it create a default world.

    EDIT: Semicolons ;-;
     
    davidclue likes this.
  7. Offline

    SmileOfDeath130

    Thank you @Shqep. That suggestion for some reason worked perfectly, and I'm now able to teleport to other worlds again. However, I've still got the problem with deserializing the location object in the config. You can see the error message now that I can teleport to worlds again. However, I'm going to reiterate that the underlying problem seems to be with Bukkit itself recognizing worlds. However, I will try the solution you guys suggested and see if it works: using Bukkit to create its own worlds and then moving the world data.
     

    Attached Files:

  8. Offline

    Shqep

    @SmileOfDeath130
    About your problem, the thing is its error message says "unknown world". Are you sure you have created the world before calling this Location object?

    Not really related but if this helps in the future, then I'm fine, so here is what I'd do if my plugin needs to work with custom worlds:

    Weird steps (open)

    S1: Take example of a SkyBlock plugin, you would need 1 thing for the worlds is the template world (the world with the island and chest). I'd put the map in the folder "skyblock_template" in the server directory. Or you can create the world programmatically, then replace the contents with the skyblock map.

    S2: On plugin load, I'd try to call the world using the suggested method, as that also makes Bukkit recognize the template world.

    S3: If I ever need to create a new SkyBlock world, it would be very inefficient to tell the user that "Hey, my plugin created the folder, now it's your job to shut down the server, put the map in and reload." So I'd copy all the files from the template world into another folder, say "skyblock1" (remove the uid.dat if exists for simplicity sake, since that would stop duplicate worlds from being created).

    S4: Now I know that the folder "skyblock1" exists now, and it has the world data in it. All I need to do now is tell Bukkit to load and recognize the world.

    This example is very specific and maybe not even the best practices as this defeats the purpose of World UUIDs.


    But if you want to work with randomly generated worlds, your best bet is this as this creates a random world like your New Game button in Singleplayer:
    PHP:
    new WorldCreator(name).createWorld()
    All you need to do next is store the names in configuration files, then call the worlds again the next time the plugin loads.

    For custom world generators, chunk loaders or block populators, see this or just look them up. I'm not very good at this part so I can't recommend any good resources.
     
  9. Offline

    SmileOfDeath130

    This reply makes sense but it gets me stuck in a catch 22. To be able to store the worlds in the config, I have to be able to call getConfig, but to call getConfig throws the error you see. To fix the error I need a list of words in the config... So I'm not sure what I can do. I want to call attention to the fact that Bukkit is throwing the exception "unknown world" instead of "world not loaded." It would be useful to know what exactly in a directory bukkit is looking for when it attempts to load all worlds. This server isn't about working with randomly generated worlds, as that is pretty easy to do. My plugin attempts to load and store worlds such that a player is able to teleport to a group of worlds (mostly used as a group for the overworld, nether, and end.) This allows players on my server to have a saved location on each group of worlds and each group of words acts as a separate server. I think that I'll try just deserialization and serialization by myself independent of bukkit if I have to, unless anybody has an alternate suggestion.

    Update: I got it working, but not in the best way. I've used Sheqep's solution to be able to use the getWorld() command, but this solution in itself is a little weird -- having to .create the world, instead of bukkit recognizing that it was simply unloaded. Additionally, I've had to deserialize and serialize locations on my own. This one is a little less bad, but both problems would have been solved if bukkit could just recognize normal worlds. I've gotten no closer to the proper solution, but at least it works right now. Is there any way for me to ask for a bug fix? This seems to be pretty major.
     
    Last edited: May 25, 2021
  10. Offline

    Shqep

    I really don't think there is an alternative way. To put it simply, when you call
    Code:
    .createWorld -> It checks if that world directory exists -> If exists, go path 1, else, path 2.
    path 1 -> check if the directory has valid world files (regions, data,...) -> if yes, load it and recognize it, else, error?
    path 2 -> create the world with the provided generator
    
    Locations are serializable as long as the worlds are already called and loaded beforehand (I think, never really serialized a Location using Bukkit's system). Save a list of necessary worlds in another file or so, load them, then deserialize the Location.
    Or, you know,... just (de-)serialize stuff your way. That works too.
     
  11. Offline

    davidclue

    @SmileOfDeath130 As I said way earlier before,
    Step 1: Create a new world using a WorldCreator in your plugin with the name of the world
    Step 2: Shut down server
    Step 3: Go to server folder and open the new world folder you just created and replace its data with your custom worlds data folder
    Step 4: Bukkit will now recognize your world folder every time you run the server (Its a one time thing to do this)
     
  12. Offline

    SmileOfDeath130

    Conclusion:
    I'm working on a good way to manage world options and create worlds properly with Bukkit. It's a shame that Bukkit isn't able to properly recognize worlds that have been generated by itself on a different server. My advice if you get an unknown world error is to take at Shqep's way of making a getWorld() method, and serializing location objects and other objects by yourself. Here is a resource for that: https://bukkit.org/threads/serializing-locations.367466/
    Sorry if I don't have a better solution for this. Have a nice day!
     

Share This Page