Feature Shared Carriages - bh679/dungeon-train-mc GitHub Wiki
Home > Features > Shared Carriages
A shared carriage is a carriage-template slot marked as a community-authored space. Instead of
spawning a fixed built-in interior, a shared slot either leases an existing player-built carriage
from the mod's relay pool (its blocks placed back verbatim, chests exactly as they were left) or drops
a fresh blank shared template that only enters the pool once someone actually builds in it. A leased
carriage is locked to one world until it's returned or the holder goes quiet for ~1 hour β so a
build is only ever edited by one player at a time, then travels on to the next world.
See also: Build Profiles β how a player's own Train Builder creations reach this pool, and the profile they live in until they're submitted.
Status: in testing β off by default. The master switch
sharedCarriagesEnabled(dungeontrain-server.toml) stays off until text-scan moderation and the report/takedown tools are proven. Distinct from Community Books: books are handed out as loot, shared carriages hand out an editable space that carries your changes back to the pool.
- Some carriages are subtly different β stepping onto one shows a faint dark-grey hint: a fresh carriage invites you to change it; a leased-from-the-pool one hints that someone has been here before you; and one you built yourself says so outright.
- Your own builds come back to you. Roughly a third of shared slots hand back a room you made β travelled out to other worlds and returned, exactly as you last left it. A carriage you've already met never turns up twice in the same world.
- Anything you build, place, or store inside a shared carriage is captured and travels with it β the next world to lease that carriage sees your changes, verbatim.
- Furnishings travel too. Armor stands, item frames, paintings, end crystals and the animals or villagers standing in a shared carriage are saved with the build and placed back when another world receives it β and they ride the moving train with it, rather than being left on the tracks. Players are never captured, and neither are echoes (they carry a real person's name and skin) or bosses.
-
What you leave shapes your echo. Leaving items of worth in storage in someone else's drifting
carriage makes your echo a little friendlier, scaled by the items' value (
LootValue.stackScore, 0.05 kindness per point, capped at 1.0 per chest visit). Only deposits beyond the most you have ever left in that container count, so putting the same item back in earns nothing, and a carriage you authored doesn't count. Bringing TNT aboard does the opposite and makes the echo angrier. Both are silent and local, and nothing is sent to the relay (event/DriftGenerosity,event/DriftingCarriageSabotageEvents). - If you find a carriage with offensive or broken content, stand on it and run
/reportcarriage [reason]; enough independent reports auto-withhold it from the pool pending review.
The full lifecycle is a straight NBT round-trip over the relay (blocks are an opaque gzip+base64 blob the relay never parses):
-
Fresh β a shared slot with no pool match spawns the blank
sharedtemplate. Nothing is uploaded until a real edit happens. -
Submit β the first genuine block change marks the carriage dirty; a ~30 s sweep captures its
blocks and its entities and uploads them (
/carriages/submit). The relay stores the build and immediately leases it back to the submitter so their in-progress work isn't handed to someone else mid-edit. -
Lease β another world's shared slot pulls a build from the pool (
/carriages/lease), places it verbatim, and holds the lock alive with periodic heartbeats. -
Save β further edits by the lease holder are saved back (
/carriages/save, which doubles as a heartbeat). -
Return β on world exit the held leases are returned (
/carriages/return) so the carriage frees up immediately; the ~1 h silence TTL is the backstop for anything not returned.
Edits normally reach the relay as sub-second deltas of just the changed cells. Entities ride along with those: every delta carries the carriage's whole current entity list, since an entity moves or appears without touching a block. Placing an armor stand therefore changes nothing a delta would notice, so a 30 s sweep also compares a decor fingerprint (armor stands, item frames, paintings, end crystals β deliberately not mobs, or a pacing villager would re-upload the build forever) and uploads when a builder has changed it.
Each shared slot rolls one of three outcomes, deterministically per carriage β walking back over the same stretch of track re-decides identically:
| outcome | default share | what you get |
|---|---|---|
| Pool | 65% (sharedCarriagePoolChance) |
a build by any player |
| Own | 30% (sharedCarriageOwnChance) |
a build by someone currently in this world |
| Fresh | the remainder, 5% | a blank shared template |
An own build is only reused when nobody else holds it, this world hasn't already placed it, and it belongs to the stage the slot sits in. If a bucket can't be served β nothing buffered, or the relay is unreachable β the slot falls through to the other kind of build, and then to a fresh template. The fresh share never falls through, which is what keeps new blank canvases entering the pool.
A build made in a Free Play session (creative or spectator mode, a known cheat mod, or deviated Adventure Item Stats settings) only ever travels to other Free Play worlds, and a normal-play build only to normal worlds. The two pools never serve each other, so a creative-mode room can't turn up as loot-bearing content in a survival run.
A world counts as Free Play if any player in it is running that way. Switching to creative mid-run hands back every carriage the world was holding: they stay standing and playable, they just stop uploading β edits made since the last save are not kept, which is the cost of never writing Free Play work into the normal pool.
The pool is a ring: past a ceiling, the oldest available build is deleted outright, with its history, its stage assignments and its reports. A build under an active lease is never evicted out from under whoever is holding it, and Free Play builds count against the same ceiling as normal ones (they are separate pools to serve from, not separate ring bounds).
The ceiling is an operator setting, live-editable from the relay dashboard's Storage β Data caps card ("Shared carriages"). It used to be a fixed 2,000, which at the pool's real arrival rate β around a thousand builds a day β meant a build survived roughly two days. It is now 100,000, and the dashboard shows the fill against it so the ceiling can be raised again before it starts biting.
Builds evicted before that change are recoverable only from a full-database backup snapshot, using the
relay's tools/carriages-restore.js. That is a repair tool, not a safety net: it can only reach back
as far as the snapshots go.
Shared carriages are served immediately and moderated in three layers:
- Automatic text scan. On submit/save the mod scrapes the authored text out of the carriage's block-entities and its entities β sign lines, lectern and chest books (title + pages), item custom names, and an entity's own name, worn/held gear and container contents (default item names are ignored) β and sends it with the upload. The relay runs that text through the same moderation reviewer the community books use; a real content signal stores the carriage flagged (withheld from the pool) instead of approved. A carriage with no player text spends no reviewer call. Editing offensive text away flips it back to approved on the next save; an admin reject is never overridden by a later edit.
-
In-game report.
/reportcarriage [reason](also/dungeontrain reportcarriage) files a report against the carriage underfoot; past a threshold it auto-flags out of the pool. - Admin review. A Carriages page in the relay's data explorer lists every stored carriage with its flag, report count, lease state, dimensions, owner, the scraped text, the moderation reason, and a full edit history (when + who), with Approve / Flag / Reject actions.
A sealed (Bedrock) dimensional carriage can take part in the
same loop. When a pair rolls its room, and that room's walls are Bedrock, the pair has a
1 in 15 chance (sharedRoomChance) of being a drifting room; the other fourteen are the plain
template and never touch the relay. A drifting room then rolls the same pool / yours / fresh split a
shared slot does β and it will only ever be handed a copy of exactly the same room: the resolved
sub-variant by name (an evilhouse never receives a house) at the same size, in the same stage. If
nothing matching is buffered, the room is fresh: the template, registered so the first block a player
places or breaks inside it uploads it as a portal_room build, with later edits streaming as deltas.
Walking into one gives the usual gray line ("β¦drifting dimensional carriageβ¦"), and a leased copy
adds the credit and death lines a leased carriage does.
Only Bedrock rooms qualify because a sealed box is one thing a single blob describes; Endless,
Void and Chunk Dimension rooms are never drifted. Authors can keep any room out of it with the
room's Drift setting (a row on the plot panel, or /dt editor portals <room> drift off); it
defaults to on. Two differences from a carriage worth knowing: edits made by redstone, pistons or
explosions inside a room are not captured (only a player's place/break), and a room re-laid after the
train drifts keeps its blocks but not its authored mobs. Relay side, the lease names the build kind
and only ever serves play captures of rooms β a room submitted from the Train Builder stays in its
author's profile.
A Group carriage (one carriage spanning the whole group, drawn by the layout weights) has a
1 in 50 chance (sharedGroupChance) of being a drifting group. It is rolled deterministically
per group, apart from the room and slot rolls. A drifting group then rolls the same pool / yours / fresh
split as a shared slot, on its first carriage:
- Leased: another world's group-long build is stamped verbatim across every carriage of the run, under the group's stage. It is only ever handed a build with exactly the same box (group length Γ height Γ width) in the same stage, so a world with a different group size never sees it.
-
Fresh: the ordinary Group carriage, contents and all. It is registered once, over the whole box,
so the first block a player places or breaks anywhere in it uploads the whole group as one
carriage_groupbuild, and later edits stream as deltas.
Entities in a leased group are put back into the carriage they stand in, so decor in the third carriage
stays with the third carriage as the train moves. The on-enter lines, death log, report command and
advancements all resolve by footprint and work anywhere in the group. On the relay side, carriage_group
is a lease kind (relay β₯ 0.239.0) and is play captures only: a Whole Group built in the Train Builder
stays in its author's profile, whatever LEASE_BUILDER_BUILDS says. Against an older relay the mod hands
back any non-group answer, so drifting groups simply stay fresh. Implementation: SharedGroupDrift (roll +
pick), SharedGroupPool (lease buffer keyed by stage + box, which prefetches only once a group has drifted
here).
config/dungeontrain-server.toml:
| Key | Default | Meaning |
|---|---|---|
sharedCarriagesEnabled |
false |
Master switch β leasing, contributing, and the on-enter hint |
sharedCarriagePoolChance |
0.65 |
Per shared slot, chance to lease a build by any player |
sharedCarriageOwnChance |
0.30 |
Per shared slot, chance to lease back a build by a player in this world. Whatever pool + own leave over is the fresh-template share; if the two are set past 1.0 together, the own share is trimmed to fit |
sharedCarriageMaxEntities |
64 |
How many entities a shared carriage may carry into and out of the pool. 0 disables entity capture entirely β builds then travel as bare blocks |
sharedRoomChance |
0.0667 |
Per Bedrock dimensional carriage, chance that it drifts at all (1 in 15). A drifting room then uses the pool / own chances above |
sharedGroupChance |
0.02 |
Per Group carriage, chance that it drifts as one group-long build (1 in 50). A drifting group then uses the pool / own chances above |
Contributing (uploading your edits) needs network consent, like signing a book; leasing and placing a pooled build need only the server master switch.
| Piece | Role |
|---|---|
SharedCarriageFlags |
which variant ids are shared (shared-carriages.json) |
TrainAssembler.spawnGroup |
the pool-vs-fresh branch that leases + places or drops a blank slot |
SharedCarriageRegistry |
in-memory subLevelId β instance map of resident shared carriages |
CarriageBlockSnapshot |
capture/place of a carriage's blocks + block-entities as portable NBT |
CarriageEntitySnapshot |
capture/respawn of the carriage's free entities (blob ents), and the decor fingerprint |
PendingRelayEntitySpawn |
a leased build's entities, spawned once the group settles (never at placement) |
CarriageTextScan |
scrapes sign / book / named-item / entity text for moderation |
SharedCarriagePool |
async prefetch buffer of leases for the spawn path |
SharedGroupDrift / SharedGroupPool
|
drifting Group carriages: the per-group roll + lease pick, and their own lease buffer |
SharedCarriageEvents |
the throttled tick: prefetch, submit-fresh, save-leased, heartbeat, return |
SharedCarriageClient |
HTTP client for the relay /carriages/* endpoints |
ReportCarriageCommand |
/reportcarriage + /dungeontrain reportcarriage
|
relay carriages.js
|
the single-holder lease pool, moderation verdict, and edit trail (SQLite) |
TemplateLootPrefabs |
the loot prefabs a builder template's chests link to, carried with the build and installed (or asked about) on download β see Editor-Container-Variants |
relay carriage-loot-prefabs.js
|
the per-builder loot_prefabs library those land in; LOOT_PREFABS_MAX_PER_OWNER (default 500) caps it by skipping new ids, never evicting |
- Stage-aware leasing β record the carriage's stage + cart position at first capture and only lease a build back into a same-stage slot. (The 3D preview listed here previously has shipped β see below.)
The relay's admin Carriages page renders each stored build in 3D from the blob itself: textured voxels for the blocks (procedurally painted β no Mojang textures ship with the web app), a Peel control that hides the one to three bounding faces nearest the camera so a closed build can be seen inside, and a history scrubber across every recorded save and delta.
Entities appear as flat camera-facing cards labelled with the entity's type and custom name, tinted per type β a card, not a likeness, since the web app has no entity models. An Entities toggle hides them for a look at the blockwork, a peeled-away wall takes its item frames with it, and the detail header reports the entity count.
- Feature: Community Books β the relay-backed loot analog this sits alongside
- Feature: Carriage Editor β authoring carriage variants offline
- Compatibility β why capture/place must read the Sable sub-level's plot chunks