Feature Main Menu Buttons - bh679/dungeon-train-mc GitHub Wiki
Since: v0.144.0 β PR #185 Icon column + Bilibili: PR #1042 (v0.615.0) Shaders in the bottom row: PR #1298 (v0.795.0) β the row went four-way, and vanilla's "Quit Game" / "Optionsβ¦" lost their extra words to fit.
Adds new buttons to the vanilla Minecraft title screen, reshuffling the existing layout to make room:
| Slot | Before (vanilla / NeoForge) | After |
|---|---|---|
| Mods row (full width) |
Mods (NeoForge) |
Train Editor | Video Tools (50 / 50) |
| Bottom row |
Options | Quit Game (50 / 50) |
Mods | Shaders | Options | Quit (25 / 25 / 25 / 25) |
| Icon column (above the accessibility icon) | β | Bilibili (Chinese clients only) / Discord / Credits |
Note: Discord began life as the text button in the Mods row described below. It now rides the icon column as a logomark, and Video Tools holds that slot. The Train Editor sections on this page are still current.
The Singleplayer / Multiplayer / Realms column and the language / accessibility icons stay where vanilla puts them. The main menu Dungeon Train wordmark and the Dev TitleScreen New-World shortcut (Shift swap) both continue to work unchanged.
A new "Discord" button on the title screen β click it, confirm the vanilla "Open Link in Browser?" prompt, and the system browser opens to the project Discord invite. A new "Train Editor" button next to it β click it and a four-tile picker asks what you want to build; pick a tile and the game loads a fresh creative-mode world on the Dungeon Train default preset and drops the player into that part of the editor.
A stack of 20Γ20 icon buttons owned by TitleScreenCreditsButton, anchored above the vanilla accessibility icon (or above the menu-chat envelope when that is showing) and stacking upward: Credits (a book), Discord one slot up, Bilibili one slot above that.
All three marks are drawn programmatically rather than shipped as textures β see DiscordIconButton, BilibiliIconButton, CreditsIconButton in client/menu/.
Clicking Discord or Bilibili opens vanilla ConfirmLinkScreen. Yes β Util.getPlatform().openUri(URI) opens the system browser, then returns the player to the title screen. No / Cancel β returns to title without launching anything. Standard Mojang-blessed pattern, same UX as the vanilla "Realms website" link.
URLs are not hardcoded at the call site. Both read OfficialLinks at click time: baked fallbacks ship in the jar so the buttons work offline, and one anonymous relay fetch per session can overlay a rotated link β so a new invite reaches already-shipped jars with no patch release.
The Bilibili icon appears only when the client's selected language is in the zh family (zh_cn, zh_tw, zh_hk, and Classical Chinese lzh), via ClientLanguage.isChinese(). Every other locale sees the column exactly as before: Discord + Credits.
Discord is blocked in mainland China, so for those players the icon below it is a dead end; Bilibili is the community link that actually opens.
Two deliberate choices worth knowing:
- The gate is language, not location. Minecraft exposes no country. A Chinese-language client anywhere qualifies; a mainland player running an English client does not. It is the best signal available and errs toward offering a working option to whoever is most likely to need one.
- Added, not substituted. Bilibili sits above Discord rather than replacing it β because the gate is language, a Chinese-language client outside China would otherwise lose a link that works fine for them.
The same wide zh gate decides the China payment route on the Support screen; the narrower Simplified-only test that removes Patreon and Revolut is separate on purpose (PaymentLinks.isSimplifiedChineseLocale) β one decides what to offer, the other what to take away.
A "pick what you're building, get a fresh creative world in that part of the editor" shortcut for content authoring. Three steps:
-
The picker (since PR #1265, v0.776.0) β clicking the button opens
TrainBuilderScreen, the same four-tile picker the Train Builder uses, titled Train Editor. Since PR #1405 (v0.877.0) it has the Nav tab's shape: the four tiles fill the left column, and the right column shows the picked tile's name, its picture and a short description, with Go here at the bottom and Back on the same row under the tiles. Clicking a tile only picks it (no hover lighting, no tooltips β only the chosen tile is lit); nothing is created until Go here is pressed β Back returns to the title screen having made no world. Geometry isBuilderPickerLayout, unit-tested across GUI scales 1β4. Each tile stands for one editor category:Tile Opens Train Outside carriagesβ the carriage shellsInside Carriage contentsβ what fills a carriageTracks & Tunnels tracksβ track tiles, pillars, tunnelsDimensional Carriages portalsβ the rooms behind a portalThe mapping lives in
BuilderModeCategory. Before this, every editor launch ran a bare/dungeontrain editorand always landed in Carriages, whatever the author actually meant to work on. -
Fresh creative void world β same code path as the Dev TitleScreen New-World shortcut. Calls
Minecraft.createWorldOpenFlows().createFreshLevel(...)withGameType.CREATIVE,Difficulty.NORMAL,allowCommands=true, a random seed, and the editor's quiet game rules baked in. Since PR #1281 (v0.788.0) the preset isdungeontrain:dungeon_train_editorβ a void, overworld-only world with no train (PendingWorldChoicesis armed withstartsWithTrain=false, the Train Builder's seam) β rather than the fulldungeontrain:dungeon_trainworld it used to build and never look at. See Development β The editor world for its shape. Tile click β standing on a plot went from ~40 s to ~4 s. -
Auto-enter editor β once the player has fully spawned in (server started +
mc.player/mc.level/mc.getConnection/mc.gameModeall non-null + a 10-tick settle delay, down from 40 in #1281 now there is no train bootstrap to wait out), the handler runs/dungeontrain editor <category>via the same dispatch path the X-menu's Editor entry uses. Two chat lines confirm the dispatch (Β§7[Train Editor] auto-running /dungeontrain editor portals+Β§e[Train Editor] please wait a few secondsβ¦).
EditorDevMode.queueOnForNextStart() is armed before the world starts, so the post-load ServerStartedEvent re-asserts EditorDevMode.set(CarriageTemplateStore.sourceTreeAvailable()). In a dev checkout (./gradlew runClient) the source tree is writable β dev mode lands ON; in a packaged jar install with no writable source tree the override is a no-op β dev mode stays OFF, so the status display and dev-only overlay codepaths remain honest for end users who happen to click the button.
TitleScreenLayoutHandler hooks ScreenEvent.Init.Post on TitleScreen and:
- Finds the three vanilla / NeoForge buttons by their translation keys (
fml.menu.mods,menu.options,menu.quit). - Captures the Mods button's bounds β that's where Video Tools + Train Editor will live.
- Resizes Mods / Options / Quit Game to thirds across the row Options + Quit Game used to share.
- Builds two new buttons sized to halves of the captured Mods slot and adds them via
event.addListener.
If any of the three vanilla buttons can't be located (third-party mod has already rewritten the menu), the handler logs a warning and skips both the layout reshuffle and the new buttons β leaves the menu untouched rather than half-modifying it.
EditorAutoOpenHandler is a one-shot client tick handler armed by the Train Editor button. On every ClientTickEvent.Post while armed, it waits for mc.player, mc.level, mc.getConnection, and mc.gameMode to all be non-null, then counts down 40 ticks before dispatching /dungeontrain editor <category> β the category the picker chose, carried across the world load on the client because the server has no record of which tile was clicked β via mc.player.connection.sendCommand (the same path the chat screen uses for typed commands, so any server-side feedback lands in chat too). The settle delay matters: dispatching during the configurationβplay phase transition was firing too early on some loads.
| Path | Purpose |
|---|---|
TitleScreenLayoutHandler.java |
Layout reshuffle + button installation |
EditorAutoOpenHandler.java |
One-shot post-load editor dispatcher |
EditorDevMode.java |
queueOnForNextStart() + ServerStartedEvent re-derive (gated on sourceTreeAvailable()) |
DevQuickWorldHandler.java |
launchFreshWorld(Screen) (visibility relaxed to package-private to share with the Train Editor button) |
TitleScreenCreditsButton.java |
The icon column: Credits + Discord + Bilibili, one anchor computation |
BilibiliIconButton.java |
The Bilibili mark, drawn programmatically |
ClientLanguage.java |
isChinese() β the one definition of the wide zh gate |
OfficialLinks.java |
Baked fallbacks + relay overlay for the Discord / Bilibili URLs |
assets/dungeontrain/lang/en_us.json |
gui.dungeontrain.discord_button, gui.dungeontrain.bilibili_button, gui.dungeontrain.editor_button
|
-
No interaction with Sable / Valkyrien Skies. TitleScreen-only; no block/collision/entity touch points. Dedicated server is unaffected (
@EventBusSubscriber(value = Dist.CLIENT)). -
Robust to other mods modifying the menu. If any of the three vanilla buttons isn't found at
Init.Posttime, the handler logs aWARNand bails β neither the reshuffle nor the new buttons are installed. The player keeps the menu the other mod produced; they just don't get Train Editor / Discord. -
The
[Train Editor]chat lines are visible only after the world has loaded β the auto-open dispatch posts them to the in-world chat overlay, not the title screen.
| Constant | File | Effect |
|---|---|---|
FALLBACK_DISCORD / FALLBACK_BILIBILI
|
OfficialLinks.java |
Baked link fallbacks. Rotating either for shipped jars is a relay change (links.js DEFAULTS), not a mod patch β keep the two in lock-step. |
GAP |
TitleScreenLayoutHandler.java |
Pixel gap between buttons in the row reshuffle (default 4). |
DISPATCH_DELAY_TICKS |
EditorAutoOpenHandler.java |
Settle delay between "player ready" and command dispatch (default 40 ticks = 2s). Bump if commands fire before chunks finish loading. |