Skip to content

fix(tmodloader,terraria): start tModLoader with a built-in empty modpack - #44

Merged
ValgulNecron merged 9 commits into
mainfrom
fix/tmodloader-default-modpack
Oct 5, 2026
Merged

ValgulNecron merged 9 commits into
mainfrom
fix/tmodloader-default-modpack

Conversation

@ValgulNecron

@ValgulNecron ValgulNecron commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Problem: every default tModLoader server crash-looped. passivelemon's tModLoader scripts exit when MODPACK is blank ("Modpack name was not provided. Exiting...") or when ModPacks/<pack>/Mods/enabled.json is missing ("Modpack was not detected. Exiting..."), and both templates default MODPACK to "". That covers tmodloader and terraria's tModLoader versions.
  • Fix: a small command/args wrapper, active only with GP_LOADER=tmodloader. That env is set at template level for tmodloader and per version for terraria's tmodloader-latest, tmodloader-2026 and tmodloader-preview. The wrapper:
    • turns a blank MODPACK into vanilla;
    • creates ModPacks/vanilla/Mods/enabled.json as [] if missing (never overwritten);
    • then execs the image's own /opt/terraria/entrypoint.sh.
  • Vanilla Terraria: runs the same entrypoint, unchanged.
  • tmodloader persistence: the template mounted its PVC at /root/.local/share/Terraria/tModLoader, but the image keeps worlds, modpacks and serverconfig in /opt/terraria/config (-tmlsavedirectory /opt/terraria/config), so nothing was persisted. It now mounts /opt/terraria/config, and its Mods tab manages ModPacks/vanilla/Mods.
  • Versions: tmodloader 1.0.1 → 1.0.2 and terraria 2.2.2 → 2.2.3 (module.yaml). README, specs and sample are updated. The readiness probes are unchanged.

Console bridge (finding #3)

  • passivelemon runs the server in a detached tmux session and nothing reads container stdin. So console input and the Stop button's exit never reached the game, and stop always waited the 30 s grace.
  • The same wrapper now forwards each pty line with tmux send-keys -l (as PUID:PGID via gosu/su-exec), and forwards SIGTERM to the entrypoint.
  • Verified live on both pinned images:
    • playing, motd and say get game replies.
    • CR and LF endings both work, and key names arrive as literal text.
    • The bridge survives Ctrl-D and reattach.
    • exit stops the server in about 2 s with exit code 0.
    • SIGTERM still saves the world (7 s), and an early delete takes 13 s.

Verification

  • Live on the kubelab test cluster with throwaway pods running the pinned digests and the exact wrapper:
    • tModLoader (MODPACK="", nested ModPacks volume like terraria's): logged "Starting server with modpack vanilla...", "Listening on port 7777" and "Server started". Exec readiness probe Ready, 0 restarts. World written to /opt/terraria/config/Worlds, and enabled.json is [].
    • Vanilla Terraria (no GP_LOADER): "Listening on port 7777", Ready, 0 restarts, world created.
  • gp-module validate tmodloader terraria --strict: OK, 0 errors and 0 warnings (same as main). gp-module preview renders GP_LOADER only for tModLoader versions.

Notes

  • Existing tmodloader servers roll to the new mount. No worlds are lost, because nothing could start before this fix.
  • The image downloads .NET on every start (upstream behaviour), so the first readiness takes about a minute.
  • Console input likely doesn't reach the server: the image runs it inside tmux, not on container stdin. This is pre-existing and out of scope here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NsN6bnAMRM9XQtrTQ6KC7U

ValgulNecron and others added 7 commits October 5, 2026 05:15
passivelemon's tModLoader scripts exit when MODPACK is blank ("Modpack
name was not provided") or when ModPacks/<pack>/Mods/enabled.json is
missing ("Modpack was not detected"). Both templates default MODPACK to
"" and the wizard stores that value, so every default tModLoader server
crash-looped.

A small command wrapper, active only when GP_LOADER=tmodloader (template
env for tmodloader, per-version env for terraria's three tModLoader
versions), turns a blank MODPACK into "vanilla", creates
ModPacks/vanilla/Mods/enabled.json as [] if it is missing (never
overwriting it), then execs the image's own /opt/terraria/entrypoint.sh.
Vanilla Terraria runs the same entrypoint unchanged.

The tmodloader template also mounted its volume at
/root/.local/share/Terraria/tModLoader, while the image keeps worlds,
modpacks and serverconfig under /opt/terraria/config, so nothing was
persisted. It now mounts /opt/terraria/config, and its Mods tab manages
ModPacks/vanilla/Mods. Versions: tmodloader 1.0.2, terraria 2.2.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsN6bnAMRM9XQtrTQ6KC7U
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
… module.yaml

The wizard shows GameTemplate spec.version, which had drifted from the
module.yaml versions (terraria 2.2.0 vs 2.2.3, tmodloader 1.0.0 vs 1.0.2)
although the template header says they move in lockstep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsN6bnAMRM9XQtrTQ6KC7U
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
The kick, ban, and unban fields were incorrectly nested as objects with
a 'command' key, but the GameTemplate CRD defines these as string fields
directly. Restructured to match the CRD and the format used by other
modules (minecraft-java, rust).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsN6bnAMRM9XQtrTQ6KC7U
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…sion

Add rule 10 to validate.py: GameTemplate spec.version must match the
module.yaml version exactly, preventing drift like minecraft-java's
(2.8.1 vs 2.9.0) that caused the wizard to display outdated versions.
Also fix minecraft-java template spec.version to 2.9.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsN6bnAMRM9XQtrTQ6KC7U
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Standardize both ark-survival-evolved and the-isle to use "Dinosaurs"
(plural) for the dinosaur-themed game category. Avoids fragmenting the
catalog with two spellings of the same concept; aligns with English
conventions for game categories (Survival, Sandbox, etc.).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsN6bnAMRM9XQtrTQ6KC7U
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
…le.yaml

The new validate.py rule requires spec.version to equal module.yaml, which the players fix bumped to 1.0.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsN6bnAMRM9XQtrTQ6KC7U
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
Rule 10 was already taken by rule_images_pinned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsN6bnAMRM9XQtrTQ6KC7U
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
ValgulNecron and others added 2 commits October 5, 2026 15:20
…sion

passivelemon runs the server in a detached tmux session and nothing reads container
stdin, so console input and the Stop button's exit never reached the game (stop always
waited out the 30 s grace). The start wrapper now forwards each pty line with tmux
send-keys and forwards SIGTERM to the entrypoint. Verified live on both images.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018MnGTGHzHhFQCa22wRknUS
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
fix(modules): nuclear-option players, spec.version lockstep + validate rule, Dinosaurs category
@ValgulNecron
ValgulNecron merged commit b42eea2 into main Oct 5, 2026
1 check passed
@ValgulNecron
ValgulNecron deleted the fix/tmodloader-default-modpack branch October 5, 2026 13:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant