Opening a World

Before we get into chunks, entities and blocks, let's start with the basics: opening a world folder and reading the data that sits right at its root, like level.dat.

1. What is a world?

If you looked at the Introduction guide already, you know a world is not just a single file. It's a whole folder full of .dat files, region files and player data. Most of that data only matters once you start looking at a specific dimension or a specific chunk, which we'll cover in later guides.

For now, think of a world as two things:

  1. A handful of files that describe the world itself: its name, its difficulty, its spawn point, whether it's hardcore, and so on. This lives in level.dat.
  2. A session.lock file that Minecraft uses to make sure only one thing is writing to the world at a time.

minified-worlds wraps both of these in one class: WorldSave.

2. Add the dependency

repositories {
    mavenCentral()
}

dependencies {
    // Replace 3.3.0 with your preferred version
    implementation 'io.github.dervarex.minified:minified-worlds:3.3.0'
}

3. Opening a world

All you need is a path to the world folder, the same folder that contains the level.dat.

Path worldDirectory = Path.of("saves/My World");
WorldSave world = new WorldSave(worldDirectory);

When you construct WorldSave, it immediately reads level.dat and a couple of other small .dat files from the data/ folder, so the constructor can throw if something is wrong. Two things it checks:

  • The given path has to be an existing directory. If it isn't, you'll get a RuntimeException saying the world directory doesn't exist.
  • That directory has to contain a level.dat file. Without it, minified-worlds has no idea what world it's even looking at, so it throws too.

Both of these are unchecked exceptions, so you don't need a try/catch just to open a world, but it's worth catching them if you're opening a folder the user picked or one that might not be a real world.

4. Reading level.dat

Once you have a WorldSave, its getLevel() method gives you a Level object with the world's core settings already parsed for you.

Level level = world.getLevel();

System.out.println(level.getLevelName());
System.out.println(level.getDifficulty());
System.out.println(level.isHardcore());
System.out.println(level.getSpawn().getPos());

A few of the fields you'll find on Level:

Level fields The most commonly used ones
levelName String

The world's name, as shown on the "Select World" screen.

difficulty Difficulty

The world's difficulty: peaceful, easy, normal or hard.

hardcore boolean

Whether hardcore mode is on. This is separate from difficulty, a hardcore world still reports hard there.

spawn Spawn

The world spawn point: dimension, position, pitch and yaw.

version Version

The Minecraft version this world was last saved with.

gameType int

The default game mode: 0 survival, 1 creative, 2 adventure, 3 spectator.

enabledDatapacks String[]

Which datapacks are turned on for this world. disabledDatapacks lists the rest.

allowCommands boolean

Whether cheats are enabled.

time int

The current world time, in ticks.

Level is a plain data class with getters and setters for everything, so if you want to change something, like renaming the world or nudging the spawn point, just call the matching setter.

Difficulty

Difficulty

peaceful No hostile mobs spawn, and hunger doesn't drain.
easy Hostile mobs deal less damage, hunger drains slowly.
normal The default, balanced difficulty.
hard Hostile mobs deal more damage, hunger drains faster. Also what hardcore worlds report here.

5. Saving your changes

WorldSave has a save() method that writes everything you changed back to disk: level.dat, the files in data/minecraft and the players, including their advancements and stats.

level.setLevelName("My Renamed World");
world.save();

A few things save() takes care of for you:

  • Only files whose data actually changed get written, everything else stays exactly as it is.
  • Each file is written to a temporary file first and then swapped in, so a crash or a full disk can't leave half a level.dat behind. Like Minecraft, it keeps the previous level.dat as level.dat_old, and the previous player files as <uuid>.dat_old.
  • Whatever minified-worlds doesn't know about (data added by mods, version_history, a player's ender chest, ...) is written back untouched.
  • It refuses to write while Minecraft has the world open and throws an IOException instead, more on that below.

save() doesn't touch chunks, entities or point of interest data, since those live in their own region files per dimension. We'll get to saving those in the next guide.

6. Checking the session lock

Minecraft uses session.lock to prevent two processes (say, a running server and your tool) from writing to the same world at the same time. WorldSave reads this for you through getLock().

if (world.getLock().isLocked()) {
    System.out.println("This world is currently open somewhere else!");
}

It's a good habit to check this before writing to a world your tool didn't open itself, editing a world while Minecraft has it loaded is a great way to lose progress.

Everything in minified-worlds that writes to a world takes the lock on its own, so writing while Minecraft has the world open fails with an IOException instead of corrupting it. isLocked() is just a snapshot though, Minecraft could still open the world right after you checked. If your tool keeps a world open for a while (an editor, for example), take the lock yourself for that time, Minecraft then refuses to open the world until you let go of it:

try (SessionLock.Handle lock = SessionLock.acquire(worldDirectory)) {
    // load, edit and save in peace
}

Saving while you hold it works just fine, save() sees that this program already has the lock.

7. Optional data

A couple of files in the data/ folder aren't always there, since Minecraft only creates them once they're actually used. WorldSave exposes those as Optional:

world.getGameRules().ifPresent(rules -> {
    // do something with the game rules
});

world.getCustomBossEvents().ifPresent(bossEvents -> {
    // do something with the boss bars
});

Next steps

Now that you can open a world and read its top level settings, it's time to look at the actual terrain.