<!-- https://minecraftdocs.dev/reference/level-data-and-rules — this page as markdown. The book's index: https://minecraftdocs.dev/llms.txt; the whole book in one file: https://minecraftdocs.dev/llms-full.txt -->

# Level data and rules

> Verified against **Minecraft 26.3** · Reference · Who owns the seed, the spawn, the rules, the border and the dimensions, where each is saved, and what tells the client — looked up, not watched.

The facts about a world that are not blocks or entities: its seed and
dimensions, its spawn, its game time, its difficulty, its rules, its
border, its scoreboard and maps. In 26.3 about half of them have left
*level.dat* — `PrimaryLevelData` is a stub and everything else is
a `SavedData` file under a *data/* folder, one server-global and one per
dimension — so the question this page answers is always the same one:
*which file remembers this, and who is allowed to change it.* The table
under [who owns what](#who-owns-what) is the page. Six sections follow it,
one for each datum whose answer is longer than a row — what is left in *level.dat*, with how a save happens inside it, the two saved-data storages, the rules, the border, the dimensions and the seed, and difficulty and weather — and a row with no section below it
is a row the table has already answered in full.

Five parts point here — [III](../systems/server/README) for what a boot
reads, [IV](../systems/world/README) for what the world is made of,
[VIII](../systems/player/README) for the two game rules that decide
whether the server checks your movement,
[IX](../systems/networking/README) for the rule values a server sends a gamemaster's client on request, and [XII](../systems/worldgen/README) for the seed — and [the level
tick](../systems/server/server-level-tick) is where most of them are read.

## Who owns what

In the *saved as* column, *dimensions/…/* stands for
*dimensions/\<namespace\>/\<path\>/*, the folder a dimension's own id names;
everything else is relative to the world folder.

| datum | owner | saved as | told to the client by |
|---|---|---|---|
| seed, structures, bonus chest, dimension list | `WorldGenSettings` (`MinecraftServer.getWorldGenSettings`) | *data/minecraft/world_gen_settings.dat* | the obfuscated seed in `CommonPlayerSpawnInfo`, the dimension list in `ClientboundLoginPacket`; structures and the bonus chest, nothing |
| world spawn | `PrimaryLevelData.respawnData` | *level.dat* | `ClientboundSetDefaultSpawnPositionPacket` — the effective spawn [below](#the-spawn-every-level-reports-is-the-servers-not-each-levels) on join, respawn and dimension change, the stored one when it is set |
| game time | `PrimaryLevelData.gameTime` (shared by every level) | *level.dat* | `ClientboundSetTimePacket` |
| day time | `ServerClockManager` | *data/minecraft/world_clocks.dat* | `ClientboundSetTimePacket` |
| difficulty, lock, hardcore | `LevelSettings.DifficultySettings` | *level.dat* | `ClientboundChangeDifficultyPacket` — hardcore alone rides in `ClientboundLoginPacket` |
| game type, allow-commands, name, data packs | `LevelSettings` | *level.dat* | the game type only as a new player's default, through `CommonPlayerSpawnInfo`; the enabled features at the configuration phase; the name and allow-commands, nothing |
| game rules | `GameRuleMap` via `GameRules` | *data/minecraft/game_rules.dat* | five rules only, plus `ClientboundGameRuleValuesPacket` on request |
| weather | `WeatherData` | *data/minecraft/weather.dat* | `ClientboundGameEventPacket` |
| world border | `WorldBorder`, one per `ServerLevel` | *dimensions/…/data/minecraft/world_border.dat* | `ClientboundInitializeBorderPacket` and the five `ClientboundSetBorder…` packets |
| scoreboard | `ServerScoreboard` (`MinecraftServer.scoreboard`), buffered by `ScoreboardSaveData` at save time | *data/minecraft/scoreboard.dat* | `ClientboundSetObjectivePacket`, `ClientboundSetScorePacket`, `ClientboundSetPlayerTeamPacket` |
| maps | `MapItemSavedData` per `MapId`, `MapIndex` for the counter | *data/minecraft/maps/\<n\>.dat*, *data/minecraft/maps/last_id.dat* | `ClientboundMapItemDataPacket` |
| raids | `Raids` per level | *dimensions/…/data/minecraft/raids.dat* | boss bars |
| chunk tickets | `TicketStorage` per level ([tickets](../systems/world/tickets-and-loading)) | *dimensions/…/data/minecraft/chunk_tickets.dat* | — |
| dragon fight | `EnderDragonFight`, where `DimensionType.hasEnderDragonFight` | *dimensions/…/data/minecraft/ender_dragon_fight.dat* | boss bars |
| boss bars, scheduled functions, random sequences, stopwatches, trader timers, command storage | `CustomBossEvents`, `TimerQueue`, `RandomSequences`, `Stopwatches`, `WanderingTraderData`, `CommandStorage` | *data/minecraft/\<id\>.dat*, and one *data/\<namespace\>/command_storage.dat* per namespace | boss bars only |
| player data | `PlayerDataStorage` | *players/data/\<uuid\>.dat* | — |

## What is left in *level.dat*

`LevelData` is the read-only interface every `Level` exposes, and it is
small: `LevelData.getRespawnData`, `LevelData.getGameTime`,
`LevelData.isHardcore`, `LevelData.getDifficulty` and
`LevelData.isDifficultyLocked`. No day time — that has left level data
entirely for `ServerClockManager` ([who owns the
clock](../systems/world/environment-attributes-and-timelines#who-owns-the-clock)) —
no weather, no rules, no border. `LevelData.RespawnData` is the world
spawn as a `GlobalPos` with yaw *and* pitch — it carries a dimension, so
`/setworldspawn` can point anywhere. `WritableLevelData` adds
`WritableLevelData.setSpawn`; `ServerLevelData` adds eight more — the level
name, the game type and its setter, `ServerLevelData.isInitialized` and its
setter, `ServerLevelData.isAllowCommands` and its setter, and
`ServerLevelData.setGameTime`; `WorldData` is the server-wide view
(`WorldData.getLevelSettings`, `WorldData.getDataConfiguration`,
`WorldData.enabledFeatures`, `WorldData.wasModded`,
`WorldData.getKnownServerBrands`, `WorldData.overworldData`).

`PrimaryLevelData` implements all of them — the overworld's level data and
the whole server's — with twelve fields: `PrimaryLevelData.settings` (a
`LevelSettings`: name, `GameType`, a `LevelSettings.DifficultySettings` of
difficulty, hardcore and lock, allow-commands, `WorldDataConfiguration`),
`PrimaryLevelData.respawnData`, `PrimaryLevelData.gameTime`,
`PrimaryLevelData.initialized`, `PrimaryLevelData.knownServerBrands`,
`PrimaryLevelData.wasModded`, `PrimaryLevelData.removedFeatureFlags`,
`PrimaryLevelData.singlePlayerUUID`, `PrimaryLevelData.version`,
`PrimaryLevelData.specialWorldProperty` (`PrimaryLevelData.SpecialWorldProperty.FLAT`
/ `PrimaryLevelData.SpecialWorldProperty.DEBUG` / none),
`PrimaryLevelData.versionHistory` (every data version that has saved the
world, written as *version_history*), and
`PrimaryLevelData.worldGenSettingsLifecycle`, the DFU `Lifecycle` that makes
the world-select screen warn about experimental settings. That is the whole
stub: seed, dimensions, rules, border, weather, dragon fight, boss bars,
scheduled events and trader timers are all `SavedData` files.
`PrimaryLevelData.createTag` builds the payload — flat, no wrapper — and
it is `LevelStorageSource.LevelStorageAccess.saveDataTag` that nests it
under *Data*; `PrimaryLevelData.parse` reads it back.

`DerivedLevelData` is what every other `ServerLevel` gets, built in
`MinecraftServer.createLevels`: spawn, game time and initialised state
forwarded to the overworld's data, and everything the whole server shares —
name, game type, hardcore, allow-commands, difficulty and its lock — read
straight off the `WorldData`. Only `DerivedLevelData.setSpawn` writes
anything; `DerivedLevelData.setGameTime`, `DerivedLevelData.setGameType`,
`DerivedLevelData.setAllowCommands` and `DerivedLevelData.setInitialized` are
no-ops. That forwarding is how game
time comes to be shared by every level.

The file is written by `LevelStorageSource.LevelStorageAccess.saveDataTag`
→ `LevelStorageSource.LevelStorageAccess.saveLevelData`: a temp file, then
`Util.safeReplaceFile` renames the old *level.dat* to `level.dat_old` and
the temp into place, ten retries per step with a rollback.

### One method saves all three

Nothing in the table above saves itself, and but for player data `MinecraftServer.saveAllChunks` is the single call behind every row. It does four things in order: it flushes
the live `ServerScoreboard` into its `ScoreboardSaveData` (which is what the
scoreboard row means by *buffered at save time* — the scoreboard is a live
object all tick and becomes saved data only here), saves every level's chunks,
writes *level.dat* through `LevelStorageSource.LevelStorageAccess.saveDataTag`, and then either joins the
saved-data storage or schedules it. So the rows with no section below them —
day time, the scoreboard, maps, raids, chunk tickets, the dragon fight and the boss-bar row's six owners — are saved by being `SavedData`, and that one flush is the only special case among them. Player data is the other road: `PlayerDataStorage` is not `SavedData`, and `PlayerList.save` writes a player's file, both from `PlayerList.saveAll` and whenever the player leaves. `MinecraftServer.saveEverything` wraps `MinecraftServer.saveAllChunks` with `PlayerList.saveAll` in front, and that is the pair *autosave* and */save-all* reach; shutdown calls the two itself.

`LevelSummary` — the world-select row — is read without opening the world at
all, by `LevelStorageSource.readLevelSummary`, and it is where the numbers on
that screen come from: a `LevelVersion` (`LevelVersion.levelDataVersion`,
`LevelVersion.lastPlayed`, `LevelVersion.minecraftVersionName`,
`LevelVersion.minecraftVersion` — the `DataVersion` the *needs upgrading* and
*from a newer version* warnings compare — and `LevelVersion.snapshot`) plus the
`LevelSettings`. Two subclasses stand for worlds it could not read:
`LevelSummary.CorruptedLevelSummary`, and `LevelSummary.SymlinkLevelSummary` for a world whose *level.dat* is a link to a place the allow list refuses.

### Every path a world folder has a name for

`LevelResource` names thirteen paths under a world folder, and the per-player
files are three separate ones rather than one *player data* row:

| `LevelResource` | the path | what is in it |
|---|---|---|
| `LevelResource.LEVEL_DATA_FILE` | *level.dat* | what this page's table calls level data |
| `LevelResource.OLD_LEVEL_DATA_FILE` | *level.dat_old* | the previous one, kept by the rename dance above |
| `LevelResource.LOCK_FILE` | *session.lock* | held for as long as the world is open ([starting a server](../systems/server/starting-a-server#taking-the-lock-and-fixing-leveldat-twice)) |
| `LevelResource.DATA` | *data/* | the server-global `SavedData` files: the scoreboard, the game rules, the world-gen settings, the boss bars |
| `LevelResource.PLAYER_DATA_DIR` | *players/data/* | one *.dat* per player, read twice on join ([players and sessions](../systems/server/players-and-sessions#the-save-file-is-read-twice-and-both-reads-are-the-whole-file)) |
| `LevelResource.PLAYER_ADVANCEMENTS_DIR` | *players/advancements/* | one JSON per player, the progress half of every advancement ([advancements](../systems/commands/advancements)) |
| `LevelResource.PLAYER_STATS_DIR` | *players/stats/* | one JSON per player, and every statistic is also a scoreboard criterion ([scores, teams and stored data](../systems/commands/scoreboard-and-data)) |
| `LevelResource.PLAYER_OLD_DATA_DIR` | *players/* | the parent of the three, and where the oldest worlds' name-keyed player files sit until a dedicated server's boot moves them, through `OldUsersConverter`, into *players/data/* |
| `LevelResource.ROOT` · `LevelResource.ICON_FILE` · `LevelResource.GENERATED_DIR` · `LevelResource.DATAPACK_DIR` · `LevelResource.MAP_RESOURCE_FILE` | *.* , *icon.png*, *generated/*, *datapacks/*, *resourcepacks/resources.zip* | the world folder itself, its world-select thumbnail, what a structure block saves ([jigsaw and templates](../systems/worldgen/jigsaw-and-templates)), the world's own packs, and the world's own resource pack, which the client loads when it opens the world |

Thirteen constants, and nothing else in a world folder has a name here: the *dimensions/* tree is named by `DimensionType.getStorageFolder`, and the region files inside it by `ChunkPos` arithmetic ([chunk storage](../systems/world/chunk-storage)).

### The spawn every level reports is the server's, not each level's

`ServerLevel.getRespawnData` forwards to `MinecraftServer.getRespawnData`,
which returns `MinecraftServer.effectiveRespawnData` — recomputed by
`MinecraftServer.updateEffectiveRespawnData` through
`Level.getWorldBorderAdjustedRespawnData`, which **relocates a spawn that
has fallen outside the border** to the border centre's surface, and by
`MinecraftServer.findRespawnDimension`, which falls back to the overworld
when the stored dimension no longer exists. So every level reports the same
spawn, and it need not be the one *level.dat* holds: it is the stored one wherever that is inside the border it is tested against — the overworld's, when the stored dimension no longer exists — and a relocated one where it is not.

## Two saved-data storages, neither of them the overworld's

`MinecraftServer.savedDataStorage` (`MinecraftServer.getDataStorage`) is
server-global at *\<world\>/data/*; maps, scoreboard, rules, weather and
clocks are server-wide. `ServerChunkCache.savedDataStorage`
(`ServerChunkCache.getDataStorage`, forwarded by
`ServerLevel.getDataStorage`) is per dimension at
*dimensions/\<namespace\>/\<path\>/data/* — the overworld included
([chunk storage](../systems/world/chunk-storage)); raids, tickets, the
border and the dragon fight are per dimension. The overworld's per-dimension
files sit under *dimensions/* like everyone else's, so neither storage is
"the overworld's": one is the server's and one is each dimension's.

### What a saved-data file is

`SavedData` is one flag, `SavedData.dirty` (`SavedData.setDirty`); a
`SavedDataType` is an id, a constructor, a `Codec` and a `DataFixTypes`.
`SavedDataStorage` caches them per folder
(`SavedDataStorage.computeIfAbsent`, `SavedDataStorage.get`,
`SavedDataStorage.set`) and writes each as *{ data, DataVersion }*,
gzip-compressed. How a dirty entry reaches the disk — encoded straight from the live object on the caller's thread, with no copy first, written on the IO pool, and joined by a flush save, shutdown or the world upgrader — is half the bargain a chunk makes, and [chunk storage](../systems/world/chunk-storage#the-other-store-under-data) is where that bargain is explained.

The id is an `Identifier`, so every saved-data file lives under a namespace
folder — the path is *data/\<namespace\>/\<path\>.dat* — and vanilla's are
all under *data/minecraft/*. Command storage is the one place the namespace
is not *minecraft*: each gets its own *data/\<namespace\>/command_storage.dat*.

## Game rules are a registry

`GameRule` is a registry entry in `Registries.GAME_RULE` /
`BuiltInRegistries.GAME_RULE`, bootstrapped by `GameRules.bootstrap`:
`GameRule.category` (a `GameRuleCategory` — `GameRuleCategory.PLAYER`,
`GameRuleCategory.MOBS`, `GameRuleCategory.SPAWNING`, `GameRuleCategory.DROPS`,
`GameRuleCategory.UPDATES`, `GameRuleCategory.CHAT`, `GameRuleCategory.MISC`),
`GameRule.gameRuleType` (`GameRuleType.INT` or `GameRuleType.BOOL`),
`GameRule.argument` (a Brigadier type), `GameRule.valueCodec`,
`GameRule.defaultValue` and `GameRule.requiredFeatures`. Ids are
snake_case and namespaceable — `GameRules.ADVANCE_TIME`, `GameRules.SPAWN_MOBS`,
`GameRules.SPAWN_MONSTERS`, `GameRules.KEEP_INVENTORY`,
`GameRules.RANDOM_TICK_SPEED`, `GameRules.PLAYERS_SLEEPING_PERCENTAGE`,
`GameRules.RESPAWN_RADIUS`, `GameRules.MAX_ENTITY_CRAMMING`,
`GameRules.MAX_SNOW_ACCUMULATION_HEIGHT`,
`GameRules.MAX_MINECART_SPEED` (feature-gated) … fifty-nine of them, with
their defaults, in [the generated table](gamerules); the old names and the
nested value classes have rows in [naming drift](naming-drift).

The values are saved data, not level data: a `GameRuleMap` — `SavedData`,
*game_rules.dat*, server-global — wrapped by the `GameRules` instance in
`MinecraftServer.gameRules`. `ServerLevel.getGameRules` returns the
server's: **one set for every dimension**, and `Level` has no rules
accessor at all, so no `ClientLevel` can read a rule — the client's `GameRules` objects belong to the two `AbstractGameRulesScreen`s, `WorldCreationGameRulesScreen` and `InWorldGameRulesScreen`, and to `WorldCreationUiState`, whose rules become the new world's when it is created. The accessors are
`GameRules.get`, `GameRules.set` (which calls
`MinecraftServer.onGameRuleChanged`) and `GameRules.visitGameRuleTypes`
(how `GameRuleCommand.register` builds **two** literals per rule — the
bare id and the namespaced one).

### What the client hears

Five rules are pushed, and the rest reach a client only when a gamemaster asks — as data through the editor below, or as the chat feedback of */gamerule*. All three of
`GameRules.REDUCED_DEBUG_INFO`, `GameRules.LIMITED_CRAFTING` and
`GameRules.IMMEDIATE_RESPAWN` ride in `ClientboundLoginPacket` at join (the
last inverted, as *showDeathScreen*); a change afterwards goes as a
`ClientboundEntityEventPacket` for the first and a `ClientboundGameEventPacket`
for the other two (`ClientboundGameEventPacket.LIMITED_CRAFTING`,
`ClientboundGameEventPacket.IMMEDIATE_RESPAWN`); `GameRules.LOCATOR_BAR` through
`ServerWaypointManager`; and `GameRules.ADVANCE_TIME`, which broadcasts a
full clock sync because a paused clock is expressed on the wire as rate 0
([environment attributes](../systems/world/environment-attributes-and-timelines)).
One mechanism in this area sends the client nothing at all:
`MinecraftServer.updateMobSpawningFlags`, which pushes a flag down the
server's own chain instead ([below](#difficulty-and-weather)).

There is an in-game editor: `ServerboundClientCommandPacket.Action.REQUEST_GAMERULE_VALUES`
→ `ServerGamePacketListenerImpl.sendGameRuleValues` →
`ClientboundGameRuleValuesPacket` → `InWorldGameRulesScreen`, and edits
back as `ServerboundSetGameRulePacket` → `ServerGamePacketListenerImpl.handleSetGameRule`
(gated on `Permissions.COMMANDS_GAMEMASTER`).

## The border is per dimension

*The border has no lecture.* It is the one mechanism in Part IV's packages whose home is this page: it sits on no
conveyor, it belongs to none of the four side-systems, and what a reader needs
of it is a set of numbers, a pair of extents and a list of packets — which is
what a Reference page is for. Part IV's landing page declares it as such.

`WorldBorder` is `SavedData` — *world_border.dat*, **per dimension**,
fetched by `ServerLevel.getWorldBorder` through the cache on every call.
Nothing scales the Nether's border by `DimensionType.coordinateScale` —
each dimension's file has its own values, so the Nether has the same
numbers unless someone sets them.

`WorldBorder.settings` (`WorldBorder.Settings`: centre, damage per block,
safe zone, warning blocks and time, size, lerp time and target;
`WorldBorder.Settings.DEFAULT` is 0,0 / 0.2 / 5 / 5 / 300 / `WorldBorder.MAX_SIZE`)
is the *loaded* snapshot, never written again;
`WorldBorder.applyInitialSettings` pushes it into the live fields once, resuming a lerp in progress from where the save left it, and saving reads the live fields back out.
The live defaults are not the persisted ones — a fresh `WorldBorder`
starts with a warning time of 15, not 300.

The live extent is a `WorldBorder.BorderExtent` — `WorldBorder.StaticBorderExtent`
or `WorldBorder.MovingBorderExtent`, which `WorldBorder.tick` advances
([the level tick](../systems/server/server-level-tick)). A moving border marks itself for saving every tick: `WorldBorder.MovingBorderExtent` marks the
saved data dirty on every advance, and a stationary one never does.
`WorldBorder.MAX_SIZE` is 59,999,968; `MinecraftServer.getAbsoluteMaxWorldSize`
is applied to every level's border in `MinecraftServer.createLevels` —
29,999,984, which is `MinecraftServer`'s own answer and so the integrated
server's, while `DedicatedServer` overrides it with *max-world-size*. `WorldBorder.isWithinBounds`, `WorldBorder.clampToBounds`,
`WorldBorder.getDistanceToBorder`, `WorldBorder.getCollisionShape` are
the readers; `BorderStatus` colours the client's wall.

For sync, `PlayerList.addWorldborderListener` registers a `BorderChangeListener`
per level that broadcasts, dimension-scoped, `ClientboundSetBorderSizePacket`,
`ClientboundSetBorderLerpSizePacket`, `ClientboundSetBorderCenterPacket`,
`ClientboundSetBorderWarningDelayPacket` and `ClientboundSetBorderWarningDistancePacket`;
`PlayerList.sendLevelInfo` sends `ClientboundInitializeBorderPacket` on
join and dimension change. `ClientLevel.worldBorder` is a plain
`WorldBorder` ticked in `ClientLevel.tick`.

## Dimensions and the seed

`DimensionType` is a record of sixteen components, and they fall into four
kinds:

| kind | components | |
|---|---|---|
| **the shape of the space** | `DimensionType.minY`, `DimensionType.height`, `DimensionType.logicalHeight`, `DimensionType.coordinateScale` | how tall, how deep, how high a portal or a chorus fruit may reach, and what a coordinate becomes when you step through a portal |
| **what the sky does** | `DimensionType.hasSkyLight`, `DimensionType.hasCeiling`, `DimensionType.hasFixedTime`, `DimensionType.ambientLight`, `DimensionType.skybox` (a `DimensionType.Skybox`), `DimensionType.cardinalLightType` | the six that decide whether there is daylight, a roof over it, whether it ever counts as day or night, and what is drawn where the blocks stop |
| **what may live here** | `DimensionType.monsterSettings`, `DimensionType.infiniburn`, `DimensionType.hasEnderDragonFight` | the two monster-spawn light tests (`DimensionType.MonsterSettings.monsterSpawnLightTest` and `DimensionType.MonsterSettings.monsterSpawnBlockLightLimit`), the block tag that burns for ever, and the dragon fight as a flag rather than hard-wired to `Level.END` |
| **the three that are a system of their own** | `DimensionType.attributes` (an `EnvironmentAttributeMap`), `DimensionType.timelines`, `DimensionType.defaultClock` (a `WorldClock` holder; `WorldClocks.OVERWORLD`, `WorldClocks.THE_END`) | where the gameplay booleans a 1.21-era reader will look for on this record have gone ([the stack a value falls through](../systems/world/environment-attributes-and-timelines#the-stack-a-value-falls-through)); [naming drift](naming-drift) has the row for each |

`DimensionType.getStorageFolder` names the on-disk folder.
Defaults are `DimensionDefaults` (`DimensionDefaults.OVERWORLD_MIN_Y` −64,
`DimensionDefaults.OVERWORLD_LEVEL_HEIGHT` 384,
`DimensionDefaults.NETHER_LOGICAL_HEIGHT` 128); the built-in keys are
`BuiltinDimensionTypes.OVERWORLD`, `BuiltinDimensionTypes.NETHER`,
`BuiltinDimensionTypes.END`, `BuiltinDimensionTypes.OVERWORLD_CAVES`.

`LevelStem` is a `DimensionType` holder plus a `ChunkGenerator`
(`LevelStem.OVERWORLD`, `LevelStem.NETHER`, `LevelStem.END`).
`Registries.LEVEL_STEM` and `Registries.DIMENSION` share the id
*dimension* ([identifiers and registries](../systems/foundations/identifiers-and-registries));
`Level.OVERWORLD`, `Level.NETHER`, `Level.END` are `ResourceKey`s under
the latter, and `Level.dimension` / `Level.dimensionType` are the
accessors. `Level.canHaveWeather` is sky light, no ceiling, not the End.

The seed and the dimension list are `WorldGenSettings` — `SavedData`,
*world_gen_settings.dat*, server-global, and written not at world creation but
by the server's first save, the `MinecraftServer` constructor having pushed it
into the storage, as it does on every boot ([creating a world](../systems/worldgen/creating-a-world) is where it
comes from) — holding
`WorldOptions`
(`WorldOptions.seed`, `WorldOptions.generateStructures`,
`WorldOptions.generateBonusChest`) and `WorldDimensions` (the stem map;
`WorldDimensions.bake` produces the registry). It is read before the
server exists by `LevelStorageSource.getLevelDataAndDimensions` and
pushed in with `SavedDataStorage.set`; if the file is missing or
unreadable the loader logs an error and substitutes a whole default
`WorldGenSettings` — a random seed, structures on, no bonus chest, and the
data packs' dimension list in place of the saved one — then carries on loading
the world. `MinecraftServer.createLevels` makes one
`ServerLevel` per stem; `MinecraftServer.levelKeys` go out in
`ClientboundLoginPacket`, the dimension type via registry sync, and the
biome-zoom-obfuscated seed in `CommonPlayerSpawnInfo`.

## Difficulty and weather

`Difficulty` (`Difficulty.PEACEFUL` … `Difficulty.HARD`) sits in
`LevelSettings.DifficultySettings`. `MinecraftServer.setDifficulty` writes
it, then calls `MinecraftServer.updateMobSpawningFlags` and
`MinecraftServer.sendDifficultyUpdate` → `ClientboundChangeDifficultyPacket`.

**Peaceful does not turn the spawner off.** The flag
`MinecraftServer.updateMobSpawningFlags` pushes down — `Level.setSpawnSettings`, forwarded to
`ServerChunkCache.setSpawnSettings`, one boolean per level — is
`ServerLevel.isSpawningMonsters`, and that reads two *game rules*,
`GameRules.SPAWN_MOBS` and `GameRules.SPAWN_MONSTERS`, and never the
difficulty. Difficulty is spent on the mobs themselves instead:
`EntityType.isAllowedInPeaceful` gates each spawn attempt, and
`Mob.checkDespawn` discards a mob that is not allowed in peaceful on its next
despawn check. So the two paths are independent — `GameRules.SPAWN_MOBS` empties the spawner and `GameRules.SPAWN_MONSTERS` its hostile half, while peaceful empties the world — and `MinecraftServer.setDifficulty` calls
`MinecraftServer.updateMobSpawningFlags` only because a rule may have changed under it since
the last call.
`DedicatedServer.forceDifficulty` applies *server.properties* at boot
with the lock ignored; there is no *getForcedDifficulty*.
`DifficultyInstance` — local difficulty — is built by
`ServerLevel.getCurrentDifficultyAt` from `ChunkAccess.getInhabitedTime`,
`Level.getOverworldClockTime` and the moon phase (an environment
attribute, `EnvironmentAttributes.MOON_PHASE`, indexed into
`DimensionType.MOON_BRIGHTNESS_PER_PHASE` — the one piece of the old moon
logic still on `DimensionType`; see
[environment attributes](../systems/world/environment-attributes-and-timelines)).
What reads it is Part VI: every `Mob.finalizeSpawn` is handed one
([entity lifecycle](../systems/entities/entity-lifecycle#a-spawn-attempt-is-a-filter-not-a-conversation)),
which is why a zombie that can break doors is a roll made once, at spawn, in
the chunk you have been standing in
([AI](../systems/entities/ai-goals-and-brains)).

`WeatherData` — server-global `SavedData`, `MinecraftServer.getWeatherData`
— was covered in [the level tick](../systems/server/server-level-tick).
`PrimaryLevelData` stores no rain fields.

## Where to look

`PrimaryLevelData.setTagData` · `DerivedLevelData` · `LevelSettings` ·
`LevelStorageSource.getLevelDataAndDimensions` ·
`LevelStorageSource.LevelStorageAccess.saveDataTag` · `SavedDataStorage.scheduleSave` ·
`SavedDataType` · `MinecraftServer.createLevels` · `MinecraftServer.getDataStorage` ·
`ServerChunkCache.getDataStorage` · `GameRules.bootstrap` · `GameRules.set` ·
`MinecraftServer.onGameRuleChanged` · `GameRuleMap` · `GameRuleCommand.register` ·
`WorldBorder.applyInitialSettings` · `WorldBorder.tick` ·
`PlayerList.addWorldborderListener` · `DimensionType` · `LevelStem` ·
`WorldGenSettings` · `WorldDimensions.bake` · `MinecraftServer.setDifficulty` ·
`ServerLevel.getCurrentDifficultyAt`

---

*Rules: names, never code · how the system works, not how the code reads ·
newest version only · every backticked name passes `tools/verify_names.py`.*
