Grims Borders
A Paper 26.3 plugin (Java 25) that sets its own world border and enforces it in layers: a visible edge, one warning as a player approaches, a solid wall they cannot cross, a warp to spawn if they get past it, and execution at the wall for the ones who keep trying. Everything a player does at the border goes into that player's own audit file.
The vanilla world border is never read and never written. /worldborder,
/chunky worldborder and anything else that uses it stay yours.
Nothing is enforced out of the box. The border ships off; one command turns it on:
/gborder set 5000
The ladder
Distances are measured from the nearest wall, worst axis first, so a corner breach reads the same as a straight-on one.
| where | what happens | recorded? |
|---|---|---|
| 5 blocks inside | The wall becomes visible: a sparse particle panel on the border plane, drawn for that player only. | no |
| 15 blocks inside | One action-bar warning, then quiet for 30 s. | no |
| at the wall | Solid. The move is refused. Action bar every time, chat line every 5 s. A player already outside is pushed 3 blocks back in. | no |
| 25 past | Warped to spawn, bold title and chat: DO NOT ATTEMPT BORDER BREAKING / You have been warned, told how many attempts are left. | yes |
| 25 past, 4th attempt | Executed at the wall. No warning first. | yes |
| ~500 past (moves every boot) | Same warp on the first attempt, executed on the second — that far out takes a glitch, not a walk. | yes |
Every distance, and the attempt each ring executes at, is configurable per world.
The secondary ring moves. 500 is a base: on every boot and every
/gborder reload it is re-rolled between 425 and 750 blocks, so it cannot be mapped by
walking out until something happens twice. The 25-block breach ring never moves — that is the number
players are told about. /gborder info shows where it landed this boot.
Being fast is not being outside. An elytra at speed can clear 25 — or 500 — blocks in a single move event from inside the border. If the player was still inside a moment ago, that is stopped at the wall and nothing is recorded. Rings only bite for a player who was already outside and kept going, or who chose the destination outright with an ender pearl or a chorus fruit.
The wall is solid
Walking into the border stops a player the way a block face does. The move is refused outright: no crossing and being yanked back, no rubber band.
The barrier stands 0.35 blocks proud of the line (wall.barrier-buffer) so
a player's 0.6-wide hitbox stops against it rather than poking through. Inside the notice band — the
larger of approach.distance and wall.particles.distance — every move is
judged, not only the ones that cross a block boundary, because a barrier you can lean a third of a
block into is not a barrier. Away from the border the cheap block-change filter still discards almost
every move event.
The visible wall
A sparse grid of particles on the border plane: red dust by default, from 5 blocks out, 20 particles a face at 2-block spacing, redrawn at most three times a second. Enough to read as a wall, nowhere near enough to matter to a client.
Sent to that one player, never broadcast, and drawn off the move events already being handled —
there is no scheduler behind it, and a player in the middle of the map costs nothing. A corner puts
both faces in range and draws both. Any particle your server knows works; one that needs extra data
the plugin cannot supply falls back to dust with a warning rather than throwing on every point.
/gborder info reports the particles-per-face for whatever you tune it to.
Portals
A portal whose far end lands outside the border does not send the player to spawn. The journey
stands and only the landing moves: straight in from wherever they came out,
25 blocks inside the wall (portal.pull-inside), with a line explaining
what happened. Nothing is recorded against them.
There is no portal at that landing spot unless one was already there — the player is moved, the world is not.
Where offenders are sent
return-point.mode in config.yml, or set it with /gborder spawn:
| mode | destination | command |
|---|---|---|
auto |
coordinates if set → warp if named → EssentialsX /spawn → world spawn |
/gborder spawn clear |
fixed |
the coordinates in the file | /gborder spawn set (where you stand) |
warp |
an EssentialsX warp, as /warp <name> <player> |
/gborder spawn warp <name> |
essentials |
EssentialsX's own /spawn for that player |
/gborder spawn essentials |
world-spawn |
the vanilla spawn of whatever world they are in | /gborder spawn world |
EssentialsX is never linked against — both handoffs are console commands dispatched by name, so
there is no version to match and the branches are unreachable without it installed. Using its
/spawn and its warps rather than copying their coordinates means spawn groups and warp
moves stay authoritative there.
A mode that cannot work degrades instead of failing. warp with no
name, or anything EssentialsX-shaped with EssentialsX missing, falls back to the fixed coordinates if
there are any and the world spawn otherwise.
A warp or spawn outside the border is caught. It would otherwise loop — returned
there, found outside, returned there again — so every EssentialsX handoff is re-checked a second later
and taken over by the world spawn if it landed outside, with a warning in the console naming the
destination. /gborder spawn test tries it on yourself.
Every landing — a portal pull, a warp to spawn, a fixed return point — loads its chunk
asynchronously first, then checks the exact spot is standable (solid floor, two blocks of room,
nothing that hurts on contact) and only looks for a better one if it is not. A point you set with
/gborder spawn set is used exactly as set while it stays safe.
Admin-flagged repeat offenders
/gborder flag <player> marks someone as a repeat offender. The flag is a
decision, not a count: it does not expire with the attempt window, and /gborder unflag
lifts it without touching their attempts.
What it changes: a flagged player who comes into a bordered world through a portal,
outside the border, is not given a lift home. The portal is allowed to put them down
where it chose, their commands are blocked, and the execution follows 20 seconds later
(portal.flagged-execution-delay-seconds). An unflagged player in the same position is just
placed inside the wall with nothing recorded.
The ceremony
execution.ceremony.enabled, off by default. When it is on, an
execution stops being a kill and becomes a procedure:
- commands cut off — no
/spawn,/homeor/tpaout of it; - infinite levitation, amplifier 50, particles hidden;
- belongings ejected one slot at a time, storage rows first, then hotbar, then off hand, then armor from the boots up. Each item is thrown out of them and deleted from the world — no pickup, nothing left on the ground;
- backpacks and chests are the exception (below);
- the configured pre-commands run —
clear %player%by default; - a whisper and a hotbar line: You were warned...;
- then the kill.
Try the whole thing on yourself with /gborder test. Nothing is recorded against the
volunteer.
Without the ceremony an execution clears the inventory, overrides keepInventory to
false for that death, empties the drops, clears the armor slots and off hand outright, and wipes
levels. Either way the next time that player is seen — on respawn, or on a login three days later —
they get one line: You were warned. Logging out mid-execution is not an escape; it is
finished two seconds after they next join.
Backpacks and chests
Both plugins stamp their containers with a UUID in the item's persistent data —
grimsbackpacks:backpack_id, grimschests:chest_id — and that is what
execution.ceremony.containers matches on, so adding a third plugin is a config line rather
than a code change.
A match is lifted out intact and three things happen: GrimsBorders fires
ContainerLockRequestEvent so the owning plugin can lock it, an optional console command
runs if you set one, and the item itself goes on the admin shelf in
plugins/GrimsBorders/confiscated/.
/gborder confiscated <player> lists it, … claim puts it in the
claiming admin's inventory. Only an admin ever gets it back — release the lock with
the owning plugin, e.g. /backpack release <uuid>.
Commands
All of these need gborders.admin. Aliases: /gborders,
/wborder.
| command | what it does |
|---|---|
/gborder info [world] |
The border, the rings as they rolled this boot, the return point, who is outside right now. |
/gborder set <radius> [world] |
Sets the radius and switches the world on. Written back to config.yml. |
/gborder center <here|x z> [world] |
Moves the centre. |
/gborder spawn <show|set|warp|essentials|world|clear|test> |
Where offenders are returned to. test sends you there to look at it. |
/gborder enforce [world] [confirm] |
The safe pass. Without confirm it lists who is outside and where; with it, they are warped back. Nobody is flagged or executed. |
/gborder attempts <player> |
Attempts on record, whether they are flagged, and whether anything of theirs is on the confiscated shelf. |
/gborder flag <player> [count] |
Marks a repeat offender and adds attempts by hand. |
/gborder unflag <player> |
Lifts the flag, leaves the attempts. |
/gborder clear <player> [audit] |
Wipes attempts and the flag, and the audit file too with audit. |
/gborder audit <player> [lines] |
Tails that player's audit trail in chat. |
/gborder confiscated <player> [claim] |
Backpacks and chests taken at an execution. claim hands them to you. |
/gborder test [player] [confirm] |
Runs the execution ceremony, on yourself by default. |
/gborder chunky [world] |
Prints the Chunky commands that pregenerate exactly this border. |
/gborder reload |
Re-reads config.yml and re-rolls the moving ring. |
Permissions
| permission | default | |
|---|---|---|
gborders.admin |
op | Use /gborder. |
gborders.bypass |
op | Ignored by the border completely — no warnings, no warps, no execution. Worth taking off admins who want to test properly. |
gborders.notify |
op | See a message when someone breaches the border, is executed, or arrives flagged through a portal. |
What lives on disk
plugins/GrimsBorders/
config.yml the border itself: worlds.<world>.radius and .center
offenders.yml attempts, admin flags, owed warnings, owed executions
audit/<uuid>.log one append-only trail per player, + index.txt
confiscated/ backpacks and chests taken at an execution
The border is in config.yml, nowhere else.
/gborder set and /gborder center write straight back to it, so editing the
file by hand and running /gborder reload is exactly equivalent. center: spawn
is stored as the word, not coordinates — it resolves against the world spawn every time the world
loads, so moving spawn moves the border.
The one thing not stored is where the moving ring landed: it is rolled fresh at every boot and every reload and only ever lives in memory.
Chunky
Chunky pregenerates chunks; GrimsBorders only looks at player positions. They do not overlap, and since the vanilla border is untouched, Chunky's own use of it is unaffected.
/gborder chunky prints the plan that matches your border, plus a pad
(chunky.pregen-pad, default 32) because a player at the wall still renders chunks past
it:
/chunky world world
/chunky center 0 0
/chunky shape square
/chunky radius 5032
/chunky start
ChunkyBorder (the addon) enforces borders on players itself. Running both means two plugins teleporting the same player in the same tick, so its presence is called out at boot — pick one.
Audit trail
One append-only file per player in plugins/GrimsBorders/audit/, named by UUID, with
index.txt mapping UUIDs to the last name seen. Writes happen off the main thread. Read it
in game with /gborder audit <player>.
Every warning, warp, execution and admin action lands there with the coordinates Paper reported, so "what was this player doing at the border" is one file, in order, with nothing else interleaved.
Weight
There is no scheduled task and no scanning. The plugin only ever looks at a position Paper has just reported: move events (gated on Paper's own block-change check away from the wall), teleports by cause, the world-change that follows a portal search, logins, and vehicle moves — because a riding player gets no move event of their own, which is the classic way past a border.
The check itself is two subtractions and a max. Stopping a player at the wall refuses
the move rather than teleporting them, so the common case costs nothing and no coordinates are
invented. No chunk is ever loaded on the main thread: executions and landings ask Paper for the chunk
asynchronously and teleport with teleportAsync, so a border action cannot stall a server
that is busy generating terrain.
checks.safety-net-sweep-ticks can add a periodic pass over online players. It is
0 (off) and should stay off unless you specifically want one.