Who owns a block, who owns a player, and what stops two servers both believing they do
Atlas cuts your world into squares. Each square is run by one Paper server, and only that server is allowed to change anything inside it.That single rule is the whole design. Everything else on this page exists to keep it true while players walk around.
Out of the box Atlas makes four squares of 2048 x 2048 blocks, arranged 2 across and 2 down, centred on the world origin.
The default grid. x increases to the east, z increases to the south. Each square is one Paper server.
Regions are numbered left to right, then top to bottom, starting at the north-west corner:
Region
Runs on
Covers x
Covers z
0
world-r0
-2048 to 0
-2048 to 0
1
world-r1
0 to 2048
-2048 to 0
2
world-r2
-2048 to 0
0 to 2048
3
world-r3
0 to 2048
0 to 2048
A block sitting exactly on a border line belongs to one region and never to both. The square starting at a line owns it, which is why spawn at 0,0 belongs to region 3 and not to region 0.
There is nothing magic about the region numbers. They are just the order the squares are counted in, and they are what you put in each server’s shard.region setting.
How many blocks wide each square is. Default 2048. Minimum 256, and a multiple of 16.
regions-x
How many squares across. Default 2.
regions-z
How many squares down. Default 2.
Multiply them and you get two things at once: how many servers you need, and how big your world is.
servers = regions-x x regions-z
world width = regions-x x region-sizeworld depth = regions-z x region-size
Some setups that people actually run:
Shards
regions-x
regions-z
region-size
World covered
Good for
2
2
1
2048
4096 x 2048
The smallest real test
4
2
2
2048
4096 x 4096
The default. A normal SMP
4
4
1
1024
4096 x 1024
A long east-west map
9
3
3
2048
6144 x 6144
A big survival world
Bigger squares mean fewer borders and fewer crossings, so fewer moving parts. Smaller squares spread load more evenly but put players near a line more often. If you are unsure, leave all three alone.
Outside the grid, nobody owns anything, so nothing may happen there. Players who reach the outer edge are pushed back inside, and entities that wander out are removed. You do not need a vanilla world border to make this work, though setting one to match keeps players from bumping into an invisible wall with no explanation.
A border is not a wall and not a loading screen. For a strip of blocks either side of every line, each server shows you what is happening on the other side.
Looking down on a single border. Not to scale - the band is 64 blocks out of a 2048 block square.
Two measurements drive this, and neither is something you set directly:
How close you are to your own square’s edge decides when the neighbour is warmed up in advance, and which of your blocks are worth copying over.
How close you are to the neighbour’s square decides whether you show up as a ghost on their side.
The band is tuning.ghost-width, 64 blocks by default. It can never be wider than a quarter of a region, because two bands of the same square would overlap and a server would start copying its own copies. Atlas refuses to start rather than let that happen. The details are in Ghosts and blocks.
Which server owns a block is pure arithmetic on its coordinates. Every server and every proxy works it out independently and always gets the same answer. Nothing is looked up, so nothing can go stale or disagree.
Players move constantly
A player cannot be owned by arithmetic, because they walk. Instead each player has one ticket in the database saying which server holds them right now, and handing the ticket over is a single, indivisible step.
Think of it as a numbered baton. There is exactly one per player, and the number goes up by one every time it changes hands.
Ownership of a player over time. The two servers touch but never overlap.
Four rules make that safe. None of them need anything special from your database.
1
Only the holder may save, and only with the current number
Every save says “I am server A and I hold ticket 7”. If the ticket has moved on to 8, the save matches nothing and is thrown away. A server that lagged out and came back cannot overwrite what happened while it was gone.
2
Handing over is one indivisible step
Saving the player’s state, changing the holder and bumping the number all happen in the same single write. There is no instant where the inventory says one thing and the ownership says another.
3
A crashed server loses its grip on its own
The holder has to keep renewing the ticket. A server that dies stops renewing, and after 30 seconds someone else may pick the player up. If the dead server wakes up later, its number is out of date and it is locked out.
4
A handoff can be undone, but only before it lands
If the other side never answers, the first server can take the player back. That undo only works while the number is still exactly what the handoff produced. Once the target has actually claimed the player, the number has moved and the undo fails, so two servers can never both conclude they hold the same person.
The grid must be identical on every shard and every proxy. A single server with a different region-size will route players to a shard that does not own where they are standing, and nothing will detect it for you. Leaving all three settings unset, so everyone takes the same defaults, is the safest way to keep them in step.
Changing the grid later is a full network restart, not a rolling one. Resizing the squares changes which region a standing player belongs to, so every shard and proxy has to come back with the new numbers together.
Region i covers a half-open square [minX, maxX) by [minZ, maxZ), so a block on a border line belongs to exactly one region. Numbering is row-major from the north-west corner:
x=0 x=1 z=0 [ 0 ][ 1 ] z=1 [ 2 ][ 3 ]
Outside the grid the region index is reported as -1. The grid is derived from config and never from Redis, so a topology outage cannot change who owns what.
The two distances
The distance from a point to its own region’s nearest edge decides when to warm up a neighbour and which blocks are worth mirroring. The distance from a point to another region’s rectangle, zero inside it, decides whether something belongs in that neighbour’s ghost band.The ghost band must be no wider than a quarter of a region, or opposite bands of the same region overlap and a shard starts mirroring its own mirrored blocks. The configuration refuses to start otherwise.
The fenced lease document
A player is one document in MongoDB carrying an owner, a fence, a sequence number and an expiry.
{ _id: "<uuid>", owner: "geo:world:region" | null, fence: long, // +1 on every ownership change seq: long, // +1 on every save expiresAt: Date, snapshot: { ... }, transfer: { to, from, token, at } | null}
The “ticket number” above is fence. Every update filters on both owner and fence; a late write from a shard that has lost the player matches nothing, returns empty, and the caller stops rather than clobbering the new owner’s state. The handoff writes the snapshot, moves ownership, bumps the fence and writes the transfer marker in a single atomic update. A revert matches on the exact fence the handoff produced.
Why this needs no transactions
Every one of those is a single-document update, and single-document atomicity is something every MongoDB deployment provides, standalone included. Atlas asks the server what it is on startup and reads with majority on a replica set or local on a standalone, which is the same guarantee on one node rather than a weaker one.The only thing a standalone gives up is the multi-document transaction helper offered to other plugins. Nothing in the crossing path uses it.