Solved Load/process all generated chunks

Discussion in 'Plugin Development' started by Bone008, May 13, 2013.

Thread Status:
Not open for further replies.
  1. Hey there,
    Time for me to ask a question again (it's been a while since I've been sitting on this side of the thread).

    Basically my objective is to convert an entire world into another format. The conversion and all is working nicely, the only problem is that it currently only works with 2 settings:
    • Convert all loaded chunks of the world
    • Convert all chunks in a cuboid area, loading (generating) the ones that aren't loaded yet
    While this works in many cases, I want to be able to handle a world save of arbitrary size and completely get all the data out of it without creating all the unrequired chunks.

    (Think of minigame-maps for example. They are often full of empty space with relevant stuff here and there, possibly very far away.)

    Does anyone have an idea how this could be accomplished elegantly? Oh and the world I'm converting is temporary, so I load it manually in the plugin and unload it afterwards.

    If at all reasonably possible, I'd like to go without NMS code, but it probably won't be. Manually reading all the existing "r.x.z.mca" files requires NMS or you'll get insane.
    Just taking all their filenames and trying to load all 1024 chunks that they could possible contain also seems overkill. Any ideas? :)

    Thanks in advance!

    Okay, more digging through NMS code brought me back to RegionFileCache and RegionFile. I still can't wrap my head around how chunk saving and indexing is done with Java's RandomAccessFile, though.
    It looks like there could be a way to detect whether a chunk exists or not with some method in RegionFile.

    Anyone experience with it by any chance? ;)

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


    o.o ... what... this can't be! Bones is asking a question? !
  3. Haha, strange, isn't it? ;)

    Anyways, I figured it out. It's neither elegant nor efficient, but I imagined worse :p
    I basically did end up looping over every possible chunk in every region file. First I found a neat native method "net.minecraft.server.RegionFile#chunkExists" that worked.

    Then I saw that bukkit's loadChunk method actually takes a parameter that allows you not to generate new chunks. :eek:
    So basically, exactly what I needed, how could I miss that ^^

    Yay for no native code! Here's my solution:
    Solution ... (open)

    1. private static void loadAllChunks(World world) {
    2. final Pattern regionPattern = Pattern.compile("r\\.([0-9-]+)\\.([0-9-]+)\\.mca");
    4. File worldDir = new File(Bukkit.getWorldContainer(), world.getName());
    5. File regionDir = new File(worldDir, "region");
    7. File[] regionFiles = regionDir.listFiles(new FilenameFilter() {
    8. @Override
    9. public boolean accept(File dir, String name) {
    10. return regionPattern.matcher(name).matches();
    11. }
    12. });
    14. pluginthingy.getLogger().info("Found " + (regionFiles.length * 1024) + " chunk candidates in " + regionFiles.length + " files to check for loading ...");
    16. for (File f : regionFiles) {
    17. // extract coordinates from filename
    18. Matcher matcher = regionPattern.matcher(f.getName());
    19. if (!matcher.matches()) {
    20. pluginthingy.getLogger().warning("FilenameFilter accepted unmatched filename: " + f.getName());
    21. continue;
    22. }
    24. int mcaX = Integer.parseInt(;
    25. int mcaZ = Integer.parseInt(;
    27. int loadedCount = 0;
    29. for (int cx = 0; cx < 32; cx++) {
    30. for (int cz = 0; cz < 32; cz++) {
    31. // local chunk coordinates need to be transformed into global ones
    32. boolean didLoad = world.loadChunk((mcaX << 5) + cx, (mcaZ << 5) + cz, false);
    33. if(didLoad)
    34. loadedCount++;
    35. }
    36. }
    39. pluginthingy.getLogger().info("Actually loaded " + Utilities.pluralNum(loadedCount, "chunk") + " from " + f.getName() + ".");
    40. }
    41. }

    ndgriffeth likes this.
  4. this can help us:
    The first 4095 bytes (or 1024 integers) contains the location where the chunks are stored in the file, if they are stored
    from, the wiki page, I got the pastebin: that reads the file

    You need the parts:
    1. //line 192 (reads the chunk from the file:
    2. int offset = getOffset(x, z);
    3. if (offset == 0) {
    4. // debugln("READ", x, z, "miss");
    5. return null;
    6. }

    1. //line 351:
    2. private int getOffset(int x, int z) {
    3. return offsets[x + z * 32];
    4. }

    1. // <init>
    2. // line 80
    3. offsets = new int[SECTOR_INTS];
    4. /* ... */
    5. // line 130
    6. for (int i = 0; i < SECTOR_INTS; ++i) {
    7. int offset = file.readInt();
    8. offsets[i] = offset;
    9. /* ... */
    10. }
    11. [/i]

    hoping you can generate code to get all chunks from the file, else I can do it for you
  5. I already figured out a solution without having to read the contents of the file (see my above post). But thanks for clearing that up, having an "index of chunks" at the beginning of the file explains a lot.

    On to the next thing: I completely neglected the "data" folder containing village data and more importantly map data. Should be easy to add to my map format, though ;)
  6. Offline


    I don't want to be the one waking up dead threads but the solution Bone008 added no longer works. Any ideas?
  7. I haven't been keeping up with bukkit lately and the solution is quite old, but what no longer works? It's using the official API and I don't think Minecraft's region file format has changed recently.
Thread Status:
Not open for further replies.

Share This Page