Feature Command Menu - bh679/dungeon-train-mc GitHub Wiki
Since: v0.39.0 Β· latest: v0.116.0
v0.1312.0 β Mobs come alive in Test the Carriage β PR #2055 β the Settings tab gains a Test Mobs | Frozen | Live row under Mobs (default Frozen). Under Live, mobs placed frozen with the Mobs setting come alive inside a Test the Carriage copy, for every template type a test can stand up. See Test Mobs setting.
v0.903.0 β Place mobs like blocks β PR #1442 β the Settings tab gains a Mobs | Blocks | Live row (default Blocks). Under Blocks a spawn egg used in an editor plot stands the mob frozen on the cell you clicked, facing you, and one left-click removes it; variant cells whose pool can roll a mob show that mob standing on the cell, taking its turn in the preview cycle. Live is the vanilla egg. See Mobs setting.
v0.882.0 β Observers stay quiet while you build β PR #1407 β observers in an editor plot no longer fire on their own while the editor shows you things (the variant preview cycle, a row click in the variant menu, a plot reset), and the Settings tab gains an Observers | On | Off row: Off keeps every observer inside a plot quiet even for blocks you place and break by hand, so a contraption can be wired without setting it off. See Observers setting.
v0.840.0 β PR #1361 β the editor screen's right pane shows every setting of whichever room is selected β Walls and its sub-options, Contents, Books, Sky, the new Fog row β without standing in it, and contents templates their Flip axes; the body under the icon row is paged: the 3D model and its sheet first, the rows on the pages after. See Paged room settings.
v0.869.0 β Nav tab β PR #1395 β the editor screen gains a fourth tab, Nav, between Layout and Settings: the four picture tiles from the title-screen picker (Train Outside Β· Inside Carriage Β· Tracks & Tunnels Β· Dimensional Carriages), 2Γ2 in the left column, with a green dot on the area the plots are stamped with. Picking a tile swaps the right column's rotating model for that area's picture, a short description of what the area is for, and a red Go here along the bottom (greyed You're here when already there). Go here asks first β it runs the same in-world /dungeontrain editor <id> switch as Enter, which re-stamps every plot and drops unsaved edits β then closes the screen. The same descriptions are the hover tooltips on the Train Editor / Train Builder picker tiles. Renamed alongside: the picker's Train Dimensions is now Dimensional Carriages, and the in-editor category label Portals is now Dimensions (ids and commands unchanged). Behind it, the editor status packet now carries the category id rather than its label, since every reader compared that string to command tokens; the HUD bar maps id β label when drawing.
v0.963.0 β PR #1557 β Ctrl+R (βR on macOS) re-rolls the test copy you are standing in without opening the menu. See Reseed.
v0.1056.0 β PR #1698 β the same Ctrl+R (βR) outside a test now runs Test the Carriage for the plot you are standing in (or, with the editor screen open, the selected template), through the usual save check: straight in when the plot is clean, Save and test / Test without saving / Back when it isn't. The binding is relabelled Test / Reseed Carriage. See Reseed.
v0.1045.0 β PR #1685 β Test the Carriage works for every Tracks template: track tiles, pillar sections, stairs, stairs entrances, tunnel sections and portals. See Testing track pieces.
v0.1035.0 β PR #1673 β Test the Carriage starts you on a flatbed facing two rolls of the template (same template, different seed). A whole group stands between two flatbeds. See Testing carriages and contents.
v0.959.0 β PR #1553 β Test the Carriage now works for carriage and contents templates, not only dimensional carriages. See Testing carriages and contents.
v0.837.0 β PR #1355 β the editor screen's Test the Carriage button becomes Exit Test Mode while you stand in a test copy, and a Reseed cell beside it either makes every test roll fresh contents (a world switch) or, inside a test, re-rolls the copy around you. See Exit Test Mode and Reseed.
v0.833.0 β PR #1353 β the inventory-style editor screen (the X menu in screen space) is rebuilt around three tabs β Templates Β· Layout Β· Settings β with category and type as filters instead of tabs, a collapsible filter bar shared by Templates and Layout, and a new Layout spawn table. It now opens anywhere in the editor world, not only inside a plot. See Editor screen tabs, filters and Layout.
v0.116.0 β PR #157 β adds a + New footer row to every floating template-type menu β the worldspace panels (added in v0.115.0 / PR #156) that float at the start of each variant row in the active editor category, listing every variant of that type with click-to-teleport name cells and ΓN weight cells. Clicking the new row opens the keyboard X menu rooted directly at the source picker for that menu's category, so authoring a new variant of the type the player is looking at is one click away. The picker pops up self-contained: a new CommandMenuState.openAt(MenuScreen) opens the keyboard menu with one screen on the navigation stack, so clicking < Back inside the picker closes the menu cleanly instead of falling through to MainMenu / EditorMenu β the picker reads as a transient pop-up rather than a deep drilldown. Each of the four supported categories routes to the same picker shell: carriages and contents drill into Blank / Current / Standard, parts use the variant's modelId as the kind tag, and tracks β which have no source choice today β collapse to a single name TypeArg row plus Back via a new NewSourcePickerScreen.Category.TRACKS entry that mirrors EditorMenuScreen.newEntryFor for tracks. The footer row uses a faint-green backdrop (0x4055FF55) at lower alpha than the active-row tint so the two never read as the same row, with the standard yellow hover overlay on top. The existing open() was refactored to share anchor / basis / crosshair-clobber setup with openAt() via a private openInternal(List<MenuScreen>). Pure additive client-side wiring on top of existing slash commands (dungeontrain editor [new|contents new|part new|tracks new]) β no packet, command, registration, or Sable / VS behavior change.
v0.112.0 β PR #153 β clicking a cross-category row in Enter βΈ (e.g. switching from Carriages to Tracks) no longer fires /dt editor <cat> directly. The destructive switch β which calls EditorCategory.clearAllPlots and silently wipes every in-world edit β is now gated behind an unsaved-changes confirmation screen that surfaces dirty templates so the player can save (or knowingly discard) before proceeding. The screen lists one row per dirty template with three columns: name (clickable, teleports to the plot via /dt editor view <cat> <id> and keeps the menu open), green Save (runs /dt save model <cat> <id> for carriages/contents; chains a view teleport before the save for track-side rows whose editors resolve plots from player position; greys out after click), and View (drills into a per-position diff list β (x,y,z) expected > live rows up to a soft cap of 12, with a ... N more tail). Below the list is a Continue button whose label flips between Don't save - continue (any rows still dirty) and Continue (all saved); clicking it dispatches the original category-switch command. A clean state β no dirty rows β auto-bypasses the screen and dispatches immediately, so the no-edits path stays one click. Same-category clicks keep the v0.109.0 templates picker behaviour. Detection uses post-stamp snapshots in a new EditorPlotSnapshots singleton, captured when each editor's stampPlot/save runs and dropped on clearPlot β comparing live to the stamped baseline (rather than the saved NBT) is what makes the check stable against parts-overlay drift, variant-sidecar changes, and the VariantEditorPreviewTicker's 1β3s preview cycling at variant cells (those positions are also explicitly skipped in the compare). Carriages, contents, track tile, pillar sections, adjuncts, and tunnels are all scanned; ID format is <kind>.<name> (dot, not colon β Brigadier's unquoted word() parser doesn't accept colons). Two new packet pairs (EditorUnsavedRequest/List, EditorChangesRequest/List) carry the lists; protocol bumped to 16. The contents capture path also discards ItemEntity instances before fillFromWorld so phantom item drops left over from door-overlay re-stamps don't bake into the saved template.
v0.109.0 β PR #149 β the Enter βΈ category picker now distinguishes the active category (the one the player is currently inside) from the others. The active row drills into a new Templates screen listing every template in that category β pick any row to teleport directly to that template's plot via the existing per-template enter command (/dt editor enter <variant> for carriages, /dt editor contents enter <id> for contents, kind-specific commands for the track-side models). The active row in both lists β the active category in Enter βΈ and the active template in the drilldown β is painted with a soft amber backdrop (0x80FFAA33) so the player can see at a glance where they are. Cross-category clicks keep the existing one-click "switch + jump to first" behaviour, since switching categories also clears every plot from the previous category. Implemented via a new optional highlighted boolean on the Run and DrillIn records (compact 2-arg ctors keep all 26 existing call sites unchanged); the renderer's baseTintFor() picks up the flag and paints the backdrop, mirroring the existing Toggle ON pattern.
v0.107.0 β PR #145 β plain X now opens the menu only in creative. In any other game mode (survival / adventure / spectator) plain X is a no-op; Shift+X is the universal override and opens the menu regardless of mode. Closing always works on plain X from any mode, so a player who toggled out of creative with the menu open can still dismiss it. Pairs with the editor auto-creative behavior added in the same PR β entering any editor switches the player to creative (and exit restores their prior mode), so editor users get the menu unlocked without changing keys. See Editor Β§ The command menu for the editor-side detail.
v0.107.0 β PR #147 β adds an Options βΈ sub-menu on the main menu (sibling of Editor / Train βΈ / Debug βΈ) with three independent display-scale steppers β All Displays, Worldspace, HUD β each rendered as a [-] / Label (value) / [+] Triple row. Values snap to multiples of 0.1 over [0.2, 2.0] and persist to a new client-scoped config at <minecraft>/config/dungeontrain-client.toml. Worldspace scales the X menu, every editor menu (block-variant, parts position, container contents), the lock-id badges, and debug labels uniformly β renderers apply poseStack.scale(ws, ws, ws); raycasts divide hitX/hitY by the same factor so click targets stay aligned. HUD scales the version overlay and editor status bar via a new HudText helper that wraps GuiGraphics.drawString with a PoseStack scale plus matching width / line-height accessors for backdrop math. All Displays is a master multiplier applied on top: effective scale = channel Γ allScale, so adjusting HUD never moves the All slider. New defaults β All 1.0, Worldspace 0.7, HUD 0.4 β ship a more compact UI out of the box; existing users can step up via the menu. Introduces a new CommandMenuEntry.ClientAction(label, Runnable) primitive so menu rows can mutate pure-client state without round-tripping through a slash command.
v0.103.0 β PR #141 β adds a Chat Logs βΈ sub-menu under the Debug βΈ drill-in, mirroring the Wireframes pattern: two per-category toggles (Train Spawn, Collision) plus an All On / All Off master. All chat-debug flags default off β the previously-always-on [DungeonTrain] Carriage collision: new pIdx=β¦ overlapping pIdx=β¦ β redstone marker placed on roof broadcast is now silenced unless chatCollision is opted in. The auto-spawn confirmation chat ([DungeonTrain] Spawned group anchorPIdx=N) is decoupled from the nextSpawn wireframe flag and now gated on chatTrainSpawn instead β wireframes control visuals, chat-logs control chat. Manual spawn still confirms in chat (deliberate user action). Brigadier: /dt debug chatlogs <train-spawn|collision|all> on|off.
v0.93.0 β PR #130 β the panel now translates with the player instead of pinning to a fixed world point at open time. A constant world-space offset (anchorPos β eye) is captured in open(), then CommandMenuRenderer calls a new CommandMenuState.refreshAnchorForFrame(partialTick) every frame β so the panel tracks the player at frame rate using the same partial-tick interpolated eye position the camera renders against, instead of jittering at the 20 Hz tick rate. The basis axes (right/up/normal) are still captured once at open time, so camera rotation never spins the panel. Auto-close-on-walk-away (>20 blocks from the anchor) is now effectively dead code since the anchor follows the player; left in place as a defensive guard.
v0.90.0 β PR #128 β promotes Debug Scan on the main menu to a Debug βΈ drill-in and adds a Wireframes βΈ sub-menu under it. The five debug overlays previously collapsed behind a single Wireframes toggle (gap cubes, gap line, next-spawn preview, post-spawn collision box, HUD Ξx line) are now individually toggleable, with an All On / All Off Split master at the top of the sub-menu. The post-spawn collision wireframe β always-on since v0.89.0 β now respects its own collision toggle and defaults off like the others; recovery is two clicks (X β Debug β Wireframes β All On). The Brigadier command tree gains explicit type literals (/dt debug wireframes <gap-cubes|gap-line|next-spawn|collision|hud-distance|all> on|off) with the legacy /dt debug wireframes on|off form kept as an alias for wireframes all on|off.
v0.66.0 β PR #82 β fixes the Remove button for carriages, contents, and parts. Confirming Remove previously deleted the on-disk template and unregistered the variant but left the in-world editor plot β both the carriage-shaped block region AND the surrounding bedrock outline cage β sitting in the world. The three reset handlers now call the existing clearPlot helpers (already used by category-switch and editor-exit), wiping footprint + cage in one shot. Brings carriages/contents/parts in line with the tracks Remove path that already did this since v0.48.0.
v0.54.0 β PR #68 β fixes the [-] Weight (N) [+] row over adjunct plots (the only adjunct kind today is pillars/adjunct_stairs). VariantOverlayRenderer.modelNameFor() had cases for every other EditorModel kind but fell through to model.id() for AdjunctModel, so the menu spliced the kind tag (adjunct_stairs) as the variant name and persisted entries like {"adjunct_stairs": 20} to pillars/adjunct_stairs/weights.json β entries that never matched any real variant at runtime. The added case mirrors the existing weightFor() pattern for adjuncts. Existing bogus weights.json entries in per-install configs will simply be ignored after the upgrade; deleting them is safe.
v0.51.0 β PR #65 β the [-] Weight (N) [+] row now also appears in the Tracks category (track tile, pillar sections, tunnel sections/portals) and the Contents category, with full parity to carriages. EditorStatusPacket gains a modelName field so the menu can splice the bare variant name into tracks weight commands without parsing the friendly path string. Existing carriages weight row also switched from model (display path) to modelId for command splicing β was harmless because they were equal for carriages, but ensures consistency now that other categories diverge.
v0.48.0 β PR #62 β fixes the New β Remove row for track-side plots. The buttons were previously building commands from the HUD path string (track / track2), which the parser rejected; they now use the bare command-token id (track, pillar_bottom, tunnel_section). Remove for tracks / pillars / tunnels also wipes the variant's plot blocks before deregistering, so the orphaned plot doesn't sit in the world after the player teleports back to default.
v0.41.0 β PR #52 β adds a Parts editor branch (synthetic status Parts | <kind>:<name> opens the same Save/All + New/Remove splits as carriages) and a transparent MenuTypingScreen that suppresses vanilla keybindings while the user types a name into the menu.
v0.42.0 β PR #55 β adds a Clear button to the editor menu (carriages / contents / parts) that wipes every interior block of the current plot to air, gated behind a ConfirmScreen. Distinct from Reset (which deletes the on-disk template); Clear only mutates the world. The barrier cage survives, and contents-plot Clear preserves the carriage shell stamped as visual context.
v0.43.0 β PR #56 β New now drills into a source picker (Blank / Current / Standard) before naming, so authors can start an empty plot, copy what they're standing in, or copy the canonical baseline. After naming, the player is teleported into the new plot. Menu activation now fires on mouse release, not press β a click that started off-target can be cancelled by sliding off before release.
v0.45.0 β PR #58 β pairs Reset | Clear on a single 50:50 row (was two stacked rows), adds a [-] Weight (N) [+] nudge row for carriage variants that adjusts by 1 server-side and keeps the menu open, and introduces two reusable menu primitives β Stay (run command, leave menu open) and Triple (three-cell row with two boundary fractions).
v0.45.0 β PR #59 β adds a Rename button for parts, carriages, and contents (pre-fills the typing field with the current id; hidden for protected built-ins), and moves the typing field inline at the clicked button row instead of at the top of the panel β the user types into the same spot they just clicked.
A toggleable worldspace menu that mirrors a curated slice of the /dungeontrain command tree. No need to type β walk up to a carriage plot, press X, and point-and-click through Save, Reset, New, Remove, DevMode, category switching, and train spawn/speed controls.
| Key | Action |
|---|---|
X (creative only, since v0.107.0)
|
Open the menu. Plain X is gated on creative mode β survival / adventure / spectator do nothing on plain X. |
Shift+X (any mode, since v0.107.0)
|
Universal open β works regardless of game mode. Pressing it in creative also opens, so the rule simplifies to "Shift+X always opens, plain X only in creative."
|
X (while menu open)
|
Close. Closing is always allowed regardless of mode. |
| ESC (while menu open) | Closes the menu (via Minecraft's screen layer). |
The keybinding uses KeyConflictContext.IN_GAME, so pressing X in chat or an inventory will not toggle. Rebind under Options β Controls β Dungeon Train β Toggle Command Menu.
The creative gate exists because the menu is a creative/dev tool β gating it prevents accidental opens during survival play. The Shift+X override gives admins quick access from any mode without rebinding. Editor users don't need to think about this: entering an editor auto-switches the player to creative (see Editor Β§ Entering and exiting).
The menu is a flat, camera-billboarded quad drawn in world space, not a 2D HUD. When you open it:
- Anchor is placed 2.5 blocks in front of your eye at the moment of opening, facing back toward you.
- The world continues to tick β train keeps moving, mobs keep walking, chat stays readable.
- Since v0.93.0: the panel translates with the player. Walking forward / strafing / jumping all carry the menu along by the same delta β it stays in the same world-axes-relative spot in front of you. Camera rotation does not rotate the panel: the orientation captured at open time is fixed, so you can look away and look back to find the menu where you left it. The translation runs in the renderer using a partial-tick interpolated eye, so the panel tracks at frame rate (smooth) rather than at the 20 Hz tick rate (would jitter).
- Before v0.93.0: anchor stayed pinned to the world position computed at open time, so walking a few blocks left it behind. Auto-close-on-walk-away triggered if you got >20 blocks from the anchor; that guard is now dead code since the anchor follows you.
Rendering uses a custom RenderType with POSITION_COLOR vertices, TRANSLUCENT_TRANSPARENCY, and no depth write. Text uses Font.DisplayMode.SEE_THROUGH so labels stay readable even against thin translucent blocks.
Shown when you open the menu outside any editor plot.
| Entry | Action |
|---|---|
| Editor | Runs /dt editor β drops you into the Carriages category editor, loading all carriage variant plots. |
| Train βΈ | Opens the Train submenu (see below). |
| Options βΈ (v0.107.0) | Opens the Options submenu β three display-scale steppers (All Displays, Worldspace, HUD). |
| Debug βΈ (v0.90.0) | Opens the Debug submenu β Wireframes βΈ, Manual Spawn (J) toggle, Debug Scan. Was a flat Debug Scan row before v0.90.0. |
| Entry | Action |
|---|---|
| Spawn |
/dt spawn (uses the configured carriage count). |
| Carriages βΈ (v0.76.0) | Preset buttons: 1, 3, 5, 10, 20, 50 β each runs /dt carriages <count>. Persists to config and live-resizes any active train (rolling window grows or shrinks on the next tick), same code path as the Mods β Settings screen. See Carriages submenu. |
| Speed βΈ | Preset buttons: Stop (0), Slow (2), Medium (5), Fast (10), Max (20) β each runs /dt speed <value>. |
| < Back | Pops to the main menu. |
A second drill-in alongside Speed for adjusting the rolling-window carriage count without leaving the world. Mirrors the Speed submenu pattern β config write + live update.
| Entry | Command |
|---|---|
| 1 carriage | /dt carriages 1 |
| 3 carriages | /dt carriages 3 |
| 5 carriages | /dt carriages 5 |
| 10 carriages | /dt carriages 10 |
| 20 carriages | /dt carriages 20 |
| 50 carriages | /dt carriages 50 |
| < Back | Pops to the Train submenu. |
Range is [1, 50] per DungeonTrainConfig.MIN_CARRIAGES / MAX_CARRIAGES. Picking a preset:
- Persists the new value to
dungeontrain-server.tomlviaDungeonTrainConfig.setNumCarriages. - Iterates every active
TrainTransformProvideracross all loaded levels and callssetCount(N). -
TrainWindowManagerreads the new count next tick β extra carriages stream in at the front, surplus carriages get erased from behind, around each player.
The same [1, 50] validation also gates /dt carriages <count> directly. See Train Β§ Usage for the raw command form.
Drilled into from the main menu's Options βΈ row. Three independent display-scale steppers, each rendered as a [-] / Label (value) / [+] Triple row β the side cells use a new ClientAction entry type that runs a Java Runnable directly instead of dispatching a slash command, so adjusting a slider doesn't round-trip through the server.
| Entry | Effective scale | Default |
|---|---|---|
[-] All Displays (X.X) [+] |
Master multiplier, applied on top of both channels. Pressing Β± only mutates allScale β neither the Worldspace nor the HUD slider follows. |
1.0 |
[-] Worldspace (X.X) [+] |
worldspaceChannel Γ allScale β applied to the X menu, every editor menu (block-variant, parts position, container contents), the lock-id badges, and debug worldspace labels. |
0.7 |
[-] HUD (X.X) [+] |
hudChannel Γ allScale β applied to the version overlay and editor status bar. |
0.4 |
| < Back | Pops to the main menu. | β |
Range is [0.2, 2.0] and values snap to the nearest 0.1 on every read and write β no 0.55 drift from float math, no half-step values lurking from a stale config file. Persists to <minecraft>/config/dungeontrain-client.toml (ModConfig.Type.CLIENT, distinct from the per-world server config) under three fields:
[display]
allScale = 1.0
worldspaceChannel = 0.7
hudChannel = 0.4Every worldspace renderer in the mod applies a uniform poseStack.scale(ws, ws, ws) after rotating into panel space, where ws = ClientDisplayConfig.getWorldspaceScale(). Each renderer's matching raycast divides hitX/hitY by the same factor so click targets remain accurate at any scale:
| Renderer | Raycast | Notes |
|---|---|---|
CommandMenuRenderer |
CommandMenuRaycast |
The X menu itself β adjusts live as you click Β±. |
BlockVariantMenuRenderer |
BlockVariantMenuRaycast |
The Block Variant Menu. |
PartPositionMenuRenderer |
PartPositionMenuRaycast |
The carriage parts editor menu. |
ContainerContentsMenuRenderer |
ContainerContentsMenuRaycast |
The Container Contents Menu. |
BlockVariantLockIdRenderer |
β | Floating lock-id badges; visual only, no hit-testing. |
CarriageGroupGapDebugRenderer |
β | Multiplies its baked TEXT_SCALE = 0.15f by ws. |
The two HUD overlays β VersionHudOverlay and EditorStatusHudOverlay β route every drawString, font.width, and font.lineHeight reference through a new HudText helper. The helper wraps pose().pushPose() / scale(s, s, 1.0f) / drawString(font, label, x/s, y/s, β¦) / popPose() so the visual on-screen position equals the caller's (x, y) despite the scale, and exposes scaledWidth(font, label) / scaledLineHeight(font) so backdrop rectangles and [DEV] badge offsets shrink consistently with the smaller text.
Adds a third row-action primitive to CommandMenuEntry alongside Run and Stay:
| Primitive | Closes menu? | Dispatches | Use case |
|---|---|---|---|
Run(label, command) |
yes | slash command | one-shot server actions |
Stay(label, command) |
no | slash command | nudge buttons that mutate server state |
ClientAction(label, action) |
no | Java Runnable
|
nudge buttons that mutate client-only state (e.g. display preferences) β no slash-command round-trip |
The Options menu's six Β± cells and three middle labels are all ClientAction entries. Dispatch lives in CommandMenuState.dispatchEntry β same shape as the Stay branch, but invokes the runnable instead of CommandRunner.run.
Drilled into from the main menu's Debug βΈ row. Surfaces the per-overlay wireframe toggles (one drill-in deeper) and the auto/manual spawn switch β both flags live in DebugFlags server-side and are mirrored on the client by DebugFlagsState (synced via DebugFlagsPacket on join + on every change). The menu rebuilds entries each tick, so toggle states reflect server truth without an extra refresh hook.
| Entry | Action |
|---|---|
| Wireframes βΈ | Opens the Wireframes submenu β five individual overlay toggles plus an All On / All Off master. |
| Chat Logs βΈ (v0.103.0) | Opens the Chat Logs submenu β two per-category chat-debug toggles plus an All On / All Off master. All flags default off. |
Manual Spawn (J) [ON/OFF] |
Toggle. When on, the carriage appender stops auto-spawning ahead of the player and instead waits for a manual J keypress (mirrors TrainCarriageAppender.MANUAL_MODE). Useful for visualising the planned-next-spawn wireframe before each step. Runs /dt debug spawnmode manual|auto. |
| Debug Scan | Runs /dt debug scan β diagnostic dump that walks every active carriage of every loaded train and reports sliver candidates (non-air blocks outside the canonical footprint). Output goes to chat + server log. |
(server only) /dt debug contents-entities on|off (v0.139.0)
|
No menu entry yet β server command only. Enables verbose lifecycle logging for carriage-contents entities: per-entity JOIN/LEAVE log lines with stack trace at LEAVE time, plus per-entity spawn lines with UUID + tag. Off by default. Use when investigating entity-disappearance regressions. See ContentsEntityDiagnostics and Compatibility Β§ Carriage-contents entities live at shipyard-absolute coords. |
| < Back | Pops to the main menu. |
Each of the five debug overlays previously collapsed behind a single Wireframes toggle is now individually toggleable. All five default off, including the post-spawn collision box that was always-on between v0.89.0 and v0.90.0. The top row is an All On / All Off Split with both halves using Stay so the menu remains open after a master flip β the player immediately sees all five Toggle rows update on the next per-tick rebuild. Toggle rows are kept full-width (not nested in the Split) so they receive the green/grey row tint applied to top-level Toggle entries.
| Entry | Visual element gated | Command |
|---|---|---|
| All On β All Off | All five flags at once | /dt debug wireframes all on|off |
Gap Cubes [ON/OFF] |
Yellow-green 1Γ1 cubes between adjacent carriage groups (one per integer block of gap distance) | /dt debug wireframes gap-cubes on|off |
Gap Line [ON/OFF] |
Cyan thin precise-length bar + "X.XX blocks" billboard label, drawn one block above the cube row |
/dt debug wireframes gap-line on|off |
Next Spawn [ON/OFF] |
Orange wireframe at the carriage-shaped box where the appender's planned next group will land (rides the reference carriage's render-pose) | /dt debug wireframes next-spawn on|off |
Collision [ON/OFF] |
Per-carriage 1Γ3Γ5 ship-space box at the back-pad corner β green when clear, red when overlapping a sibling. Disappears once the carriage transitions to placedSuccessfully (60 clean ticks). See Train Β§ Diagnostic wireframe overlay. |
/dt debug wireframes collision on|off |
HUD Distance [ON/OFF] |
Top-left HUD second line Ξx to next group: X.XX blocks β only renders when the player is in a non-leading carriage of a train. |
/dt debug wireframes hud-distance on|off |
| < Back | Pops to the Debug submenu. | β |
Bandwidth optimisation: server-side broadcasts are gated per-flag in CarriageGroupGapTicker β collision compute skips when collision is off, gap broadcast triggers on gapCubes || gapLine || hudDistance, next-spawn broadcast on nextSpawn. Client-side gating in CarriageGroupGapDebugRenderer is the correctness mechanism β flag flips take effect on the next frame regardless of broadcast timing.
Since v0.103.0, the in-chat broadcasts that previously piggy-backed on the wireframe flags are independently controlled by the Chat Logs submenu β the wireframe collision overlay no longer drags the red collision chat warning along with it, and vice versa.
Two chat-debug categories that previously appeared in chat unconditionally (or piggy-backed on a wireframe flag) are now individually toggleable, with an All On / All Off Split master at the top β same structural pattern as the Wireframes submenu. All flags default off, including the formerly always-on post-spawn collision broadcast at TrainCarriageAppender; recovery is two clicks (X β Debug β Chat Logs β All On).
| Entry | Chat broadcast gated | Command |
|---|---|---|
| All On β All Off | Both flags at once | /dt debug chatlogs all on|off |
Train Spawn [ON/OFF] |
[DungeonTrain] Spawned group anchorPIdx=N action-bar line emitted by TrainCarriageAppender.announceSpawn on every auto-spawn. Manual-spawn (J keypress) confirmation always shows regardless of this flag β the J press is a deliberate user action. |
/dt debug chatlogs train-spawn on|off |
Collision [ON/OFF] |
Two red chat lines that fire when a newly-spawned carriage's AABB overlaps a sibling: the once-per-carriage Collision detected: carriage pIdx=β¦ ticks since spawn=β¦ from CarriageGroupGapTicker and the per-overlap Carriage collision: new pIdx=β¦ overlapping pIdx=β¦ β redstone marker placed on roof from TrainCarriageAppender. The LOGGER.warn and the redstone roof marker stay unconditional β only the chat broadcasts are silenced. |
/dt debug chatlogs collision on|off |
| < Back | Pops to the Debug submenu. | β |
Server-side flags live in DebugFlags (chatTrainSpawn, chatCollision) and are mirrored on the client by DebugFlagsState β same DebugFlagsPacket snapshot that carries the wireframe flags (8 booleans total since v0.103.0; the two chat-log flags are appended at the end of the wire format so existing clients see a consistent prefix). The chatCollision once-per-carriage dedup set persists across OFFβON toggles by design, so already-warned carriages won't re-fire if you flip the toggle back on later.
Opens automatically when you press X while standing inside any editor plot. Detection comes from the server's EditorStatusPacket (the same signal that drives the "Editor: β¦" status HUD bar).
| Entry | Action |
|---|---|
| DevMode [ON/OFF] | Toggle switch with live state. Green fill when on, grey when off. Clicking runs /dt editor devmode on or /dt editor devmode off β the menu stays open so you see the state flip after the server ack. |
| Enter βΈ | Category picker: Tracks, Carriages, Contents (see Contents category below). The row for the player's current category is highlighted (soft amber) and drills into a Templates list (v0.109.0) β pick any template to teleport directly. The active template in that list is also highlighted. Other category rows keep the one-click /dt editor <cat> switch behaviour. |
| Save β All | 80 / 20 split. Left runs /dt save (current plot). Right runs /dt save all (every plot in the current category). |
| Reset β Clear (v0.45.0) | 50 / 50 split. Left runs /dt reset (re-stamps the current plot from the saved template β discards unsaved edits). Right drills into a confirmation, then runs /dt editor clear (wipes every interior block to air without touching the template). Only visible in carriages / contents / parts; falls back to a solo Reset row in tracks / pillars / tunnels / architecture. See Reset β Clear paired row and Clear β wipe interior blocks. |
| New β Remove | 50 / 50 split. Visible in carriages, contents, and the track-side categories (tracks / pillars / tunnels). Architecture has no addressable model id, so the row is hidden there. The buttons dispatch to the right subcommand per category β see New and Remove. |
| Rename (v0.45.0) | Drops into typing mode with the field pre-filled with the current model id. On submit, runs the category's true-rename command β /dt editor save <new> (carriages), /dt editor contents save <new> (contents), or /dt editor part rename <new> (parts). Hidden for protected built-ins (standard, flatbed, default). See Rename. |
| [-] Weight (N) [+] (v0.45.0, expanded v0.51.0) | 10 / 80 / 10 triple row. Side cells nudge the weight by Β±1 and keep the menu open so the player can spam-click while watching the HUD weight line update. Middle cell drops into typing mode for an exact value (0β100). v0.45.0: carriage variants. v0.51.0: also tracks (kind + name) and contents. See Weight nudge row. |
| Exit (v0.57.0) | Runs /dt editor exit β unwinds the active editor session, clears every editor plot, and teleports the player back to where they entered the editor from. Replaces the prior < Back row, which only popped the menu stack to the main menu and left the player stranded inside the editor plot. |
- Click New. The menu drills into the source picker: Blank / Current / Standard /
< Back. Entries are conditionally hidden when not applicable (e.g. Current hides when the player isn't standing in a model). - Click a source. The menu enters typing mode β letters, digits, and underscore are accepted (matches
CarriageVariant.NAME_PATTERN = [a-z0-9_]{1,32}). ESC cancels, Enter submits. - On submit the server registers the new model, allocates a plot, stamps it according to the chosen seed, saves the template, and teleports the player into the new plot ready to edit. No need to manually
enterafter creation.
- Click Remove. The menu drills into a confirmation screen β "Remove ''?" for carriages/contents, "Remove the current variant for ''?" for the track-side categories (the prompt shows the friendly path like
track / track2so the player can verify they're removing the right thing). - Click Yes, confirm. The dispatched command varies by category:
-
Carriages β
/dt editor reset <id>β config-dir.nbtdeleted, custom variant unregistered. Plot blocks + bedrock cage wiped viaCarriageEditor.clearPlot(v0.66.0). -
Contents β
/dt editor contents reset <id>β same shape, contents store. Plot blocks + bedrock cage wiped viaCarriageContentsEditor.clearPlot(v0.66.0). -
Parts β
/dt editor part reset <kind> <name>β config-dir.nbtdeleted; registry entry removed only if no bundled fallback remains. Plot blocks + bedrock cage wiped viaCarriagePartEditor.clearPlot(v0.66.0). -
Tracks / pillars / tunnels (v0.48.0) β
/dt editor tracks reset <kind>β the<kind>token is the bare command id (track,pillar_bottom,tunnel_section, β¦), not the HUD path. The variant's plot blocks are wiped to air before the JSON is deleted and the registry entry is unregistered, so the orphaned plot doesn't remain visible. The player is teleported back to the kind'sdefaultplot. Errors with a friendly message if the active variant is the syntheticdefault(you can't remove the built-in fallback).
-
Carriages β
- Click Cancel (or
< Back) to pop back to the editor menu without changes.
Behind the scenes, the menu reads two fields from EditorStatusPacket: model (HUD-friendly path, used for confirm-prompt labels) and modelId (bare command-token id, used for the dispatched command). For carriages and contents the two are identical; for the track-side categories they diverge. Splicing model into the command β as the menu did before v0.48.0 β produced strings like dungeontrain editor tracks reset track / track2 which the brigadier parser rejected with Incorrect argument for command.
Before v0.39.0, /dt editor contents enter <id> could only teleport you to one contents plot at a time. The Contents category now behaves like Carriages / Tracks:
-
/dt editor contentsstamps every registeredCarriageContentsplot in world (at z = 80) and teleports you to the first. -
/dt save,/dt save all, and/dt resetdispatch onContentsModelβ standing in a contents plot and running/dt save alliterates every content variant and writes each one to the config dir. -
EditorCategory.locate()recognises contents plots, so the editor status HUD ("Editor: Contents / default") and the menu's editor screen both activate inside them.
When the player stands inside a carriage part plot, the editor status HUD synthesises Editor: Carriages / Parts | <kind>:<name> and the menu opens to the same editor screen as carriages β but the Save/Reset/New/Remove actions dispatch to the part subtree:
| Entry | Action |
|---|---|
| Save β All | Left runs /dt editor part save (position-aware). Right runs /dt editor part save all (iterates every registered (kind, name) plot). |
| New β Remove | Left drills into the v0.43.0 source picker (Blank / Current / Standard) before naming, then runs /dt editor part new <kind> <source> <typed>. The new part is registered immediately and the player is teleported into its plot, ready to edit. Right deletes the .nbt, the variants sidecar, and unregisters the name. |
| Rename (v0.45.0) | Drops into typing mode pre-filled with the current part name. On submit runs /dt editor part rename <new_name> β a true rename (vs save <new_name>'s save-as behaviour): captures the current plot, writes under the new name, deletes the old config + source-tree file (devmode), unregisters the old name unless it's bundled, relocates the rendered plot, and teleports the player into it. See Rename. |
| Reset | Re-stamps the current part plot from the saved template β same semantics as carriage Reset. |
The picker drills into a NewSourcePickerScreen parameterised with the parts category and the current plot's kind, so the same UI handles all three categories with kind-aware availability gating.
When the menu enters typing mode (after pressing New in either the carriages, contents, or parts editor branch), it now opens a transparent MenuTypingScreen β a Screen with no widgets and no rendering of its own.
Why: before v0.41.0, typing the letters w, a, s, or d while in typing mode also moved the player; pressing e opened the inventory; pressing a number key swapped the hotbar selection. The keybindings fired because no Screen was up to suspend them. Pressing letters intended for the input buffer triggered the underlying keybindings as side effects.
Vanilla suspends KeyMapping.consumeClick() whenever any Screen is open, so opening any transparent screen for the duration of typing mode pauses every keybinding without the menu having to enumerate them. MenuTypingScreen.removed() calls cancelTyping if the screen closes through any path other than Submit / Cancel (e.g. ESC, clicking out, mc.setScreen(null) from elsewhere) so typing state can never desync from the menu state.
CommandMenuToggleHandler exempts MenuTypingScreen from its auto-close-on-any-screen-opens guard, so opening it doesn't dismiss the worldspace panel β the panel stays visible behind the (transparent) screen for the duration of typing.
CommandMenuInputHandler.onKey early-returns when any Screen is up so keystrokes don't double-process: with the screen captured, vanilla's keyPressed / charTyped go to MenuTypingScreen only, and the Forge InputEvent.Key handler stops trying to drive the buffer in parallel.
A Clear button in the editor menu wipes every interior block of the plot the player is standing in to air, without touching the on-disk template. Useful when an author wants to start a model over from scratch β manually breaking every block of a 9Γ7Γ7 carriage is tedious, and Reset can't be used because it deletes the template file rather than just the world geometry.
The button drills into a ConfirmScreen titled Clear all blocks in '<model>'? (Yes, confirm / Cancel) β same gating as Remove so a misclick does nothing. On confirm the menu closes and the server runs /dt editor clear, which dispatches based on which plot the player is in:
| Plot | What's erased | What's preserved |
|---|---|---|
| Carriage | Whole footprint (length Γ height Γ width) |
Bedrock cage |
| Contents | Interior volume only (length-2 Γ height-2 Γ width-2) |
Bedrock cage + carriage shell context |
| Part | Part footprint per kind (FLOOR / WALLS / ROOF / DOORS) | Bedrock cage |
The contents-plot behaviour is the important one: contents plots stamp a carriage shell as visual context around the editable interior, so Clear has to be interior-only β the floor, walls, ceiling stay so the author keeps building inside the same shell. This is delegated to CarriageContentsTemplate.eraseAt, which iterates interiorOrigin / interiorSize, not the full plot.
The button is omitted in tracks / pillars / tunnels / architecture β those categories have no per-model id from the menu's perspective. See the editor wiki page for the full reset-vs-clear comparison and the underlying command.
Before v0.43.0 the New button jumped straight into typing mode and silently duplicated whichever model the player was standing in. Authors who wanted an empty plot, or a copy of the canonical baseline, had no UI to ask for it β they had to either edit the duplicate down to nothing or use the underlying command tree directly.
The button now drills into a NewSourcePickerScreen with three options:
| Option | Seed | Notes |
|---|---|---|
| Blank | Empty plot β no NBT stamped (parts get the existing stone-brick starter so the floor is visible) | Always available |
| Current | Copy of whatever model the player is currently standing in | Hidden when the player is not in a model. For parts, also hidden if the current plot's kind doesn't match (e.g. opening New floor while standing in a walls plot) |
| Standard | Copy of the canonical baseline β for carriages / contents the literal standard / default; for parts the part literally named standard, falling back to the first registered name for the kind |
Hidden for kinds with no registered fallback (e.g. roof on a fresh install with no bundled NBT) |
After picking a source the menu enters typing mode for the new id. On submit the server runs one of:
/dt editor new <name> <source>
/dt editor contents new <name> <source>
/dt editor part new <kind> <source> <name>
where <source> is the literal token blank / current / standard (parts) or blank plus an existing variant id (carriages / contents β the picker passes the chosen variant for Current / Standard).
The player is then teleported into the new plot. For carriages / contents this is a fresh call to CarriageEditor.enter / CarriageContentsEditor.enter after the duplicate completes; for parts it's wrapped into the same CarriagePartEditor.createFrom call that does the registration and stamping.
Before v0.45.0 the editor menu rendered Reset and Clear on two separate full-width rows, which (1) wasted vertical space and (2) read as two unrelated actions even though they both target the same plot's destructive state. v0.45.0 pairs them on a single 50 / 50 split row that mirrors the visual rhythm of the New β Remove row directly below it:
Save β All 80 / 20
Reset β Clear 50 / 50 β the new pairing
New β Remove 50 / 50
The pairing is conditional: categories with no Clear (tracks / pillars / tunnels / architecture, where the menu has no per-model id to clear) fall back to a solo Reset row. The order is deliberate β Reset (the broader-blast-radius action: deletes the on-disk template) sits left, matching the convention used by New | Remove.
Clear's confirm screen and underlying command are unchanged from v0.42.0.
Carriage variants have a per-variant integer weight (0β100, default 1) that biases the weighted random pick. Before v0.45.0 the only way to change it from in-world was either typing /dungeontrain editor weight <variant> <n> by hand or waiting until v0.44.0's edit-by-hand gymnastics. The menu now exposes a dedicated row for it:
[-] Weight (N) [+] β single row, 10 / 80 / 10
| Cell | Action | Closes menu? |
|---|---|---|
- (10%) |
Runs /dt editor weight <model> dec β server reads the current value, subtracts 1, clamps to [0, 100], persists. |
No β stays open so the author can tap repeatedly. |
Weight (N) (80%) |
TypeArg. Drops into typing mode; on Enter runs /dt editor weight <model> <typed> and Brigadier validates the integer server-side. |
Yes (closes on submit, like every other TypeArg flow). |
+ (10%) |
Runs /dt editor weight <model> inc β same as - with +1. |
No. |
Behavioural details:
- The middle cell's label includes the live value (e.g.
Weight (5)) read fromEditorStatusHudOverlay.weight(). Because the menu rebuilds entries every client tick (onClientTick β rebuildEntries β entries()), the label refreshes automatically after each+/-click as soon as the server's nextEditorStatusPacketpush lands. No manual refresh, no menu-reopen. -
Saturation is silent. Clicking
-at 0 just rewrites 0; clicking+at 100 just rewrites 100. The unchanged HUD line (and the unchanged label) is the feedback. The HUD's existing orange tint at weight 0 ("excluded from the random pool") is what tells you you've hit the bottom. - v0.45.0: visible in the carriages category only.
-
v0.51.0: also visible in the Tracks category (over track tile / pillar section / tunnel section plots) and the Contents category. Tracks splice both
<kind>and<name>into the command (/dt editor tracks weight <kind> <name> ...); contents splice the contents id (/dt editor contents weight <id> ...); carriages stay on/dt editor weight <variant> .... Parts and architecture still get no Weight row β they have no weight pool. See Feature-Track-Variants Β§ HUD and Feature-Carriage-Contents Β§ Weighted contents pick (v0.51.0). - The row is rendered using the new
Tripleprimitive and the side cells use the newStayentry type.
The two new server subcommands resolve as siblings to the existing weight <variant> <int> setter β Brigadier dispatches literals before integer parsing, so:
/dt editor weight standard inc # +1
/dt editor weight standard dec # -1
/dt editor weight standard 50 # set to 50, unchanged behaviour
both forms tab-complete and the existing JSON-overlay loader (config/dungeontrain/weights.json) is unaffected.
Two new entry types in CommandMenuEntry generalise the patterns used by the Weight nudge row:
| Primitive | Shape | Closes menu? | Notes |
|---|---|---|---|
Run(label, command) |
one button | yes | the original β every existing menu row that runs a command. |
Stay(label, command) |
one button | no | for incremental adjustments (nudge buttons, anything where the user wants to click again while watching live feedback). The next tick's rebuildEntries picks up any label change driven by server state. |
Toggle(label, state, on, off) |
one button, stateful | no | unchanged. |
TypeArg(label, argName, prefix[, suffix]) |
one button β typing mode | yes (on submit) | unchanged. |
DrillIn(label, target) |
one button | n/a | unchanged. |
Back(label) |
one button | pops one level | unchanged. |
Split(left, right, leftFraction) |
two cells | depends on cell | unchanged. |
Triple(left, middle, right, leftFraction, middleEnd) |
three cells | depends on cell |
leftFraction is the panel-relative x of the boundary between left and middle (0..1); middleEnd is the boundary between middle and right. The raycast emits subIdx 0 / 1 / 2 to identify which cell was hit, dispatched the same way Split's 0 / 1 is. |
Split and Triple cannot currently be nested β the renderer, raycast, and dispatch all stop at one level deep. If a future row needs a fourth cell, generalise Triple rather than nesting.
Before v0.45.0 the only in-world way to rename a model was to retype the full new name into /dt editor save <new> (carriages / contents) β discoverable only if you remembered the rename-on-save shortcut. Parts had no rename UI at all; /dt editor part save <new> left the old file behind as a duplicate. v0.45.0 promotes rename to a first-class menu button and gives parts a true rename command.
The Rename button drops into typing mode with the current model id pre-filled so the user can edit instead of retype:
- Carriages β submits
/dt editor save <new>(existing rename-on-save inCarriageEditor.saveAsβ write new template, delete old, swap registry entry, propagate variant-block sidecar viaCarriageVariantBlocks.rename). - Contents β submits
/dt editor contents save <new>(existing rename-on-save inCarriageContentsEditor.saveAs). - Parts β submits the new
/dt editor part rename <new>(see Carriage Editor#Parts rename). Distinct from/dt editor part save <new>, which is a save-as / duplicate.
The button is hidden when the player is in a protected built-in plot (standard, flatbed for carriages; default for contents) β the server would reject the rename anyway, so the menu just doesn't offer it. Custom variants and bundled-but-renamable parts are always renamable.
The pre-fill is plumbed through a new initialBuffer field on CommandMenuEntry.TypeArg and a corresponding 4-arg overload of CommandMenuState.beginTyping. Existing call sites stay unchanged through backwards-compatible constructors.
Before v0.45.0 the typing buffer rendered as a green line just under the breadcrumb header at the top of the panel. The user clicks New or Rename near the bottom of the menu, then has to flick their eyes up to see what they're typing. v0.45.0 moves the field to the originating button row:
- The button's label is replaced with
<typed_buffer>_(underscore cursor at the end). - The row's backdrop tints green (
0xB033FF99) so the typing state is unambiguous. - For
Splitrows, only the half the user clicked tints β the other half keeps its label. - The top-of-panel typing line is gone (the breadcrumb header stays).
Implementation: CommandMenuState.activate(idx, subIdx) stashes the click's (rowIdx, subIdx) into typingOriginRowIdx / typingOriginSubIdx before dispatchEntry runs β captured at the outer click level so a Split's recursive half-dispatch (which loses the outer subIdx) doesn't lose the field's anchor. The renderer's isTypingHere(rowIdx, subIdx) predicate compares against those fields each frame; the indices reset on cancelTyping / close. If the menu rebuilds during typing and the row no longer exists, the predicate naturally fails for every row and the field just stops drawing β same fail-safe behaviour as the v0.41.0 top-of-panel line.
Menu activation now fires on mouse release, not press. Before v0.43.0 the InputEvent.InteractionKeyMappingTriggered handler activated the hovered entry the moment a click was consumed β so a press that started off the menu (e.g. a quick jab at empty world) would activate whichever entry was under the crosshair on the next frame. There was no way to cancel a click once started.
The new flow:
-
Press while menu open β
onInteractioncancels the vanilla swing/use animation and setspressArmed = true. Nothing else happens. -
Release while menu open β
onMouseButton(MouseButton.Pre)activates the hovered entry only ifpressArmedwas true. The flag is cleared either way.
Releases without a prior in-menu press (menu opened mid-click, drag started outside the menu) are ignored. The handler also clears pressArmed when the menu closes, so a press-then-close-then-release sequence can't accidentally activate the next time the menu opens.
Practical effect: the user can mouse-down on an entry, slide off the menu while still holding the button, and release to cancel β the same affordance every desktop button has had since the 80s but missing from the in-world menu until now.
While the menu is open:
- All interaction keymaps (attack / use / pick-block) fire
InputEvent.InteractionKeyMappingTriggered, which is cancelled at the top before the world interaction runs. Since v0.43.0 this handler only cancels and arms the press flag β activation is deferred to mouse release (see Click on release). -
PlayerInteractEvent.LeftClickBlock,RightClickBlock, andRightClickItemare also cancelled atEventPriority.HIGHESTas a belt-and-braces guard. - Each render frame overwrites
Minecraft.hitResultwith aBlockHitResult.miss(...)so continuous mining (which readshitResulteach tick) finds no target. - Each tick calls
mc.gameMode.stopDestroyBlock()to cancel any accumulated destroy progress.
Blocks behind the panel are not targetable, not highlightable, and not mineable for the duration the menu is open.
Since v0.682.0 (PR #1135) the editor menu is a screen overlay with a pinned tab strip β File | Current | Settings | Nav β as row 0. Two changes landed in PR #1282:
The Current tab used to widen the whole panel (1.6 β 2.6 units) so that "Walls: Endless Repetition" fitted. That sizing dated from the world-space decal, where 1.6 units held about fifteen characters; the pixel panel holds about thirty, so the override was removed and every tab now uses the shared 200px width. Labels that outgrow a cell are still truncated to it.
A floppy icon sits at the right end of the Dungeon Train > Editor header, on every tab. Clicking it runs the same command as File β Save (/dungeontrain save, or /dungeontrain editor part save in a parts plot) and leaves the menu open, as a toolbar button would. Hovering shows a tooltip.
Its colour is its status:
| Colour | Meaning |
|---|---|
| Steady blue | The plot you are standing in matches what is on disk |
| Pulsing green (1 Hz) | The plot has unsaved edits β tooltip reads "Save β unsaved changes" |
The status comes from the server's existing dirty scan (EditorDirtyCheck.findDirty, the same one the unsaved-changes screen uses), fetched with EditorUnsavedRequestPacket. It is asked for once when the menu opens and ten ticks after any menu command that can change the plot (Save, Undo/Redo, Clear, Reset, toggles) β never per tick, and no new packets. Parts plots are not covered by the scan, so the icon stays blue there; clicking still saves the part.
What counts as unsaved (v0.871.0, PR #1397). Three things, compared against the baseline taken when the plot was last stamped or saved: its blocks (variant cells excluded β the preview ticker cycles those), its decoration (item frames, paintings and the mobs placed in it, counted by type), and its variant pools β adding, removing or reconfiguring block variants with the Z menu flags the template until it is saved, and the changes list names the cells as variants > edited. Things that do not count: the author standing in the plot, a mob turning its head or wandering, and blocks decaying on their own β random ticks are off in the editor world, so grass under a placed block stays grass. Before v0.871.0 the first two lit the icon for every plot you walked into and the variant pools never did. Note the icon reflects any plot in the world, not only the one you stand in; /dt editor unsaved lists which.
Any MenuScreen can offer such a button by overriding headerAction() (a MenuHeaderAction of icon, label, command and ARGB tint); only the editor screen does today.
v0.833.0 β PR #1353
Pressing X with the menu in screen space opens the inventory-style editor screen anywhere in the editor world (between plots as well as inside one) and, as before, inside an editor plot in any other world; world-space mode and ordinary worlds keep the row-list menu. Opened between plots nothing is "here" β the header offers Go here instead of You are here β and everything else reads the same.
Templates Β· Layout Β· Settings Β· exit icon. Category is no longer a tab: it is the first row of the filter bar.
One row, full width above both columns, shared by Templates and Layout:
-
Collapsed (default):
[search] [βΈ Filters] [active chipsβ¦]. Each chip is a filter in force β the category cell, the chosen type, Mine / Built-in / Imported when on, creator mode's status, Starred and creator β and clicking a chip turns that filter off. -
Expanded (
βΎ Filters): the full chip row, then the category stripAll Β· Carriages Β· Contents Β· Tracks Β· Dimensionsand the type strip (Floor, Walls, β¦) in the left column. Load all sits at the end of the type strip on Templates only. The green square marks the category of the plot you stand in. - A long chip list clips at the panel's edge; the right pane starts beneath the row.
A spawn table of every roster type. Rows are fold Β· name Β· weight Β· items inside:
- Everything starts folded β type sections and each group's sub-variant list β and what you open is remembered across reopening. A search opens whatever it matched.
- The weight cell works like every editor number (see Editing numbers): click +1, shift- or right-click β1, cmd-click to type a value. A group parent's last cell counts its sub-variants; an opened group shows its
(self)share row and members one step in. Parts have no weight; track members are read-only for now. - Clicking a name selects it in the right pane (double-click enters it), where Stage and Move stay available.
- The same search and filters narrow the table; a filter that leaves nothing says Nothing matches these filters rather than Loading. The roster is fetched as soon as you enter the editor world or a plot, so the tab opens on its rows.
- Go here from between plots no longer falls back to a category switch (which clears and restamps every plot); it uses the roster's stamped category.
- The Find creator⦠search panel sits over the tile grid, never on the 3D preview.
- Contents group members now carry their gate and Stage ids like track members, so their chips are truthful.
v0.837.0 β PR #1355
The bottom row of the editor screen's right pane holds Test the Carriage (dimensional carriages, carriages and contents β see v0.959.0) with a narrow Reseed cell at its right end.
v0.860.0 β a test spawns the room's hostiles as built. The test copy used to go through the gentle-onboarding hostile gate like a carriage in play, and since an author in the editor world has travelled 0 carriages that gate sat in its no hostiles stage β every zombie, skeleton or pillager spawn-egg cell rolled, cleared its block to air and placed nothing (the log still said spawned). A test stamp (PortalTestSession.isTestStamp: the test pair key while a session is live) now spawns as authored, and a hostile the gate withholds in play makes spawnVariantMob return false, so spawn logs and counts only ever name mobs that were placed. PR #1383.
While you stand in a stamped test copy the button reads Exit Test Mode with the exit icon and runs /dungeontrain portal test back β back to your plot, test copy swept. It does not depend on what is selected in the roster (the test copy sits in the basement between plots, where nothing is selected), and it reverts to Test the Carriage the moment the session ends. This is the row-list menu's < Back from '' row, which the inventory-style screen had been missing.
A test stamps the room with the same roll every time (pairKey 0 against the world's generation seed), so an author saw identical chests on every test. The Reseed cell changes that in two ways depending on where you are:
-
Outside a test β a world switch (
/dungeontrain portal test reseed on|off, stored in the world'sDungeonTrainWorldData, off by default). Green tint = on: each test folds a fresh random salt into the room's rolls, so contents and block variants differ per test. Off, the roll is byte-identical to before the switch existed. -
Inside a test β a button (
/dungeontrain portal test reseed). Re-rolls the copy you are standing in with a fresh salt whatever the switch says, and puts you back exactly where you stood β unless the new roll filled that spot (a wall variant, furniture), in which case you land in the doorway instead. -
Hotkey β Ctrl+R (βR on macOS) (v0.963.0,
EditorUndoHotkeyClient, keykey.dungeontrain.editor_reseed, rebindable under Dungeon Train in Controls). It runs the same in-test reseed with no screen open. Outside a test it never flips the world switch: since v0.1056.0 it is Test the Carriage instead β for the plot you are standing in, or the selected template when the editor screen is open β viaPortalTestSaveCheckScreen(clean β straight in, unsaved β save prompt). In a plot with nothing to test (a part), or outside the editor, it does nothing.
The salt lives on PortalStructure.seedSalt and only ever reaches test stamps; live pairs carry 0 and keep their position-determined rolls. The switch's state rides on PortalTestSessionPacket, sent on every join, so the cell shows the server's state before the first test.
PR #1685. Select any template under Tracks and press Test the Carriage (/dungeontrain editor test tracks <model> <name>, where <model> is track, pillar_bottom|middle|top, adjunct_stairs, adjunct_stairs_entrance, tunnel_section or tunnel_portal). In the basement it stands up two rolls of a stretch of line:
- Open line β three columns on the generator's own spacing (12 high, so bottom, middle and top sections and the full arch all show) with a pillar staircase beside the middle one, over a grass floor.
- Tunnel β entrance portal, two sections and a mirrored exit portal on a stone embankment, with a down-stairs shaft rising through the middle of the sections to its entrance on the roof.
-
A train on the section under test β
[Β½ flatbed | carriage | Β½ flatbed], the way a one-carriage sub-level stands on the real line. It stands over the middle column for pillar sections and stairs, across the mouth for a portal, and inside the tunnel for a section or a staircase entrance. You arrive on its back pad, facing down the line.
The piece under test is used everywhere that kind of piece appears; everything else is picked the world's way. The whole scene stands in a band drawn at random from the tested template's gate (its phases; the level is the gate's lowest), and the other pieces, the carriage and its contents are picked within that band β the chat line names it. Reseed re-rolls everything, possibly into another allowed band; a focus reseed (Shift) re-rolls only the piece and keeps the line and band. Exit Test Mode sweeps the whole scene. An unknown piece or template name is refused.
The stamping is the generator's own (TrackGenerator / TunnelPlacer), not a copy β only the choice of names differs. Layout lives in track/TrackTestLayout, the band in track/TrackTestBand.
PR #1553. Select a carriage or contents template and press Test the Carriage (or the Nav tab's row in the world-space menu). One whole copy is stamped as relit world blocks under the world β shell, parts, block variants, contents, loot and mob cells, rolled at carriage index 0 the way the train rolls a carriage β and you are put inside it in creative. Reseed and Exit Test Mode work exactly as for a dimensional carriage (the same portal test reseed / portal test back commands forward to it). Parts have nothing to stand up, so the button stays greyed there; track pieces are stood up in a stretch of line (see Testing track pieces).
-
Carriage (
/dungeontrain editor test carriages <id>) β furnished with what the train would put in it: the pick runs through that carriage's contents allow-list and weights.portal/portal_shortcorridors are built the way the train builds them, with their corridor contents;portal_middlestands up empty; flatbeds get no contents. -
Contents (
/dungeontrain editor test contents <id>) β stands in a carriage that currently has those contents enabled in its Contents list, drawn by carriage weight (sub-variants count through their group's top parent; portal parts, flatbeds and weight-0 carriages never qualify). If no carriage enables it the test is refused with a message saying so. A group parent rolls one of its members; portal contents are tested inside their corridor. -
Editor contents plots follow the same rule for their surrounding shell (
ContentsShellPicker), fixed per template so a plot shows the same carriage on every visit; the standard carriage is only the fallback when nothing enables the contents. -
Layout (v0.1035.0, PR #1673) β laid out along +X as the train would meet it, and you arrive on the flatbed facing the copies:
- carriage / contents / whole room:
[flatbed | roll A | roll B]β roll B is the same template on a seed derived from roll A's, so Reseed re-rolls both and a focus reseed keeps the untested half of both. Roll A picks its back door as a carriage behind a flatbed would. - whole group:
[flatbed | group | flatbed]β it already spans several carriages. - Exit Test Mode sweeps the whole span, both rolls and flatbeds included.
- carriage / contents / whole room:
- Hostiles spawn as authored during a test (
CarriageTestSession.isTestStamp), like a dimensional-carriage test. - The copy sits at the bottom of the world beside the dimensional-carriage test band; Exit sweeps its blocks and entities. Quitting the world mid-test leaves the copy standing, as with dimensional carriages.
Settings tab, after Plot Lighting: Observers | On | Off. The same Label-plus-cells row shape as Editor Menus; the active cell is highlighted and each cell runs /dt editor observers on|off.
-
On (default) β observers behave as in vanilla for anything you do. What they no longer react to is the editor's own scaffolding: the 1 Hz variant preview cycle, previewing a row in the Z / block-variant menu, the template-blocks preview, the variant mirror's stamp, and
/dt reset/ delete-and-restamp. Those writes run under the same stamp guard that keeps observers quiet while a carriage is spawned (PR #1345), so a contraption facing a variant cell no longer fires itself every second. - Off β every observer inside an editor plot (or anywhere in the Train Editor void world) stays quiet, hand-placed and broken blocks included. Wire the contraption, switch back to On, test it.
The choice is world state β saved with the world (DungeonTrainWorldData), shown to everyone online, and restored on login. It is scoped by position (the observer's block must sit in a located editor plot), so a play world's train is never affected.
Settings tab, after Observers: Mobs | Blocks | Live. Same row shape as Observers; each cell runs /dt editor mobs blocks|live. Default Blocks.
- Blocks β a spawn egg right-clicked on a block inside an editor plot places the mob the way a block is placed: on the clicked cell (the face-adjacent cell when the clicked block is solid), facing you snapped to a quarter turn, and frozen β no AI, silent, invulnerable, never despawns, so it stays exactly where you put it and does not burn in the plot's daylight. One left-click removes it, like breaking a block in creative. The egg is kept in creative. Holding Z still adds the egg as a variant of the clicked cell instead.
-
Variant-cell ghosts (Blocks only) β a cell whose variant pool holds a mob entry used to show the command-block sentinel for that entry. Now, when the 3-second preview cycle lands on the mob entry, the cell is aired and the mob is drawn standing on it (a client-side model β it cannot be hit; break the cell block to remove the variant). A cell of
[stone, zombie]alternates stone β zombie the way a cell of two blocks alternates. Only the plot you stand in is ghosted, within four chunks of the camera. - Live β the vanilla egg: a wandering mob, as every world did before v0.903.0. No ghosts.
A frozen mob is the real entity, so it is captured into the template by the same entity capture that carries item frames and paintings and stamps back frozen into an editor plot. When the template is stamped onto a real train the freeze is stripped and the mob comes alive as normal β at every template β entity restore path, including shared-carriage leases authored in the builder world. The choice is world state (DungeonTrainWorldData), shown to everyone online and restored on login.
Known quirks: vanilla non-AI ticking still runs on a frozen mob (a frozen chicken lays eggs); a template saved under Blocks stamps back frozen in the editor whichever mode is active.
Settings tab, under Mobs: Test Mobs | Frozen | Live. Each cell runs /dt editor testmobs frozen|live. Default Frozen.
Test the Carriage stamps its copies into the Train Editor world's basement. That whole world counts as editor space, so before this setting a frozen mob (see Mobs setting) stood in the test copy as the same statue it is in the plot.
- Frozen: test copies keep frozen mobs still, as in the plot. This is the behaviour before v0.1312.0.
- Live: a frozen mob whose spawn lands inside a running test copy is thawed, the same way a real train thaws it. It moves, makes sounds and can be hurt. This works for carriages, contents, whole rooms and groups, track pieces and dimensional carriages. You stay in Creative, so hostiles wander but don't target you.
The check is by position: the copy's box for carriage tests, and the whole tiled window for dimensional carriages (TestCopyMobs, called from FrozenMobs.prepareForSpawn). Editor plots stay frozen even while a test is open. The setting is read when mobs spawn, so a change applies from the next test or Reseed. It is world state, shown to everyone online and restored on login.
v0.840.0 β PR #1361
The right pane used to show a dimensional carriage's rows β Walls, Lock, Copies, Door Wall, Contents, Books, Sky, Exits β only while you stood in that room, because every portal command resolved its room from where you stood. Now they show for whichever room is selected in the browser.
- The roster the screen loads carries each room's resolved settings tag and box (and each contents template's flip axes), so the rows can be built for a room you are only looking at. Standing in the room, the values still come from the per-tick status and update on the next frame; elsewhere they refresh with the roster about half a second after a tap.
- The server hangs the whole settings tree off a second root,
/dungeontrain editor portals room <name> β¦, which the screen sends for a room you are not standing in. The old spelling is unchanged and still acts on the plot under you. - Contents templates get the Flip
X / Y / Z / Roomsquad the world-space Current tab has.
The body is paged. Everything between the icon row and Test the Carriage β preview, sheet, rows β is one paged region. Page 1 is the 3D model with its sheet (path, size, blocks, weight, stage, levels). The room's rows fill the pages after, as many per page as the body holds; < n / N > sits in a slot the layout keeps at the foot of the body on every size, and the mouse wheel over the body turns pages too. A template with no rows (a carriage, a part) has one page and no pager.
Limits: a sub-variant room (a group member) has no roster row of its own, so its rows still need you to stand in it; Copies βΊ Edit opens the world-space block-variant panel where you stand, so use Go here first.
-
Keyboard layout: typing mode maps GLFW key codes directly to
[a-z0-9_]. A Dvorak or AZERTY user typing the physicalAkey will always seea, regardless of their layout. Variant / contents names are ASCII-only so this is acceptable but can feel unusual. - Valkyrien Skies / Sable ships: the v0.93.0 follow-player update tracks the player's world-space eye position, so on a moving ship the panel does follow the player along with the ship's translation β but the offset is in world axes, not ship-local axes. If the ship rotates, the panel does not rotate with it: the panel will appear to slide sideways relative to the ship. Reopen the menu after a turn to recapture a ship-aligned offset, or treat this as a follow-up if a fully ship-relative anchor is wanted.
-
Screen interruption: if you press
E(inventory) orT(chat) while the menu is open, the screen that opens takes priority and the menu auto-closes (themc.screen != nullguard runs every tick). The v0.41.0MenuTypingScreenis exempt from this guard β it's our own screen and dismissing the menu when the user just hitNewwould cancel typing the moment it started. -
Non-op players on dedicated servers: the
/dtcommand tree is gated onhasPermission(2)and isn't sent to the client's command tree. The menu's connection / player null-checks mean pressingXsilently does nothing for non-op players.
- Carriage Editor β the underlying editor commands.
- Features β back to the feature index.