SeedLab Walkthrough¶
Difficulty: Advanced Concepts: World generation patching, runtime flag overrides, dual-panel UI, preset system, hierarchical feature model
SeedLab lets players mix and match individual features from Terraria's secret and special seeds, both at runtime and during world generation.
What It Does¶
- In-Game Panel (F10 in-world): Toggle seed features while playing. Enemy stats, spawn rates, and boss AI change immediately.
- World-Gen Panel (F10 at menu): Configure which seed features to force-enable before creating a new world.
- 15 Seeds: 9 special seeds (For the Worthy, Drunk World, Don't Starve, Not the Bees, Remix, Zenith, Celebration, No Traps, Skyblock) + 6 secret seeds (Vampire, Infected, Team Spawns, Dual Dungeons, Halloween Forever, Christmas Forever)
- 120+ Individual Features: Each seed is decomposed into granular toggleable effects
- Presets: Save and load custom seed configurations
Architecture¶
SeedLab uses a hierarchical feature model with three tiers:
Seed (e.g., "For the Worthy")
├── Group (e.g., "Enemy Scaling")
│ ├── Feature (e.g., "Enemy Stat Multipliers")
│ └── Feature (e.g., "Boss Life Scaling")
└── Group (e.g., "Gameplay Changes")
├── Feature (e.g., "Bunnies Are Hostile")
└── Feature (e.g., "Demon Eyes Shoot Lasers")
This hierarchy enables three granularity levels: toggle an entire seed, a group of related features, or individual effects.
Key Concepts¶
1. Dual-Mode Operation¶
SeedLab has two completely independent systems:
Runtime mode modifies the current world's gameplay by patching methods like NPC.SetDefaults, NPC.AI, and Spawner.GetSpawnRate. Changes take effect immediately.
World-gen mode modifies Terraria's seed flags during world creation by patching WorldGen.Reset() and GenPass.Apply(). Features must be configured before creating the world.
Each mode has its own state file:
- state.json: Runtime feature toggles (per-world)
- state-worldgen.json: World-gen feature overrides
2. Global vs. Mixed Flag Overrides¶
The runtime patching system uses an optimization to minimize overhead:
If ALL features of a seed are enabled → Set Main.getGoodWorld = true globally
If ALL features of a seed are disabled → Set Main.getGoodWorld = false globally
If MIXED (some on, some off) → Keep global flag + use per-method prefixes
When a seed is fully enabled or disabled, the global flag handles everything and per-method patches skip their checks entirely. Only when features are mixed does the mod need per-method prefix/postfix pairs:
// Prefix: save original flag, apply override
static void NPC_SetDefaults_Prefix(ref bool __state)
{
__state = Main.getGoodWorld; // save original
if (FeatureManager.IsFeatureEnabled("ftw_enemy_scaling"))
Main.getGoodWorld = true;
}
// Postfix: restore original flag
static void NPC_SetDefaults_Postfix(bool __state)
{
Main.getGoodWorld = __state; // restore
}
This save/restore pattern ensures one feature's override doesn't leak into unrelated code.
3. Harmony Patch Targets¶
Runtime features patch approximately 7 key methods:
| Target | Purpose |
|---|---|
NPC.SetDefaults |
Enemy stat scaling (FTW, Zenith, Celebration) |
NPC.AI |
Boss behavior changes (FTW, Not the Bees, No Traps) |
NPC.ScaleStats_ByDifficulty_Tweaks |
Boss life/damage multipliers |
Spawner.GetSpawnRate |
Spawn rate adjustments |
Spawner.SpawnNPC |
Spawn pool and depth changes |
Player.UpdateBuffs |
Hunger debuff (Don't Starve) |
| Global flag toggles | Binary seed flags (Vampire, Infected, etc.) |
4. Two UI Panels¶
In-Game Panel (InGamePanel) uses the Core UI framework:
- Collapsible seed sections with group toggles
- Normal mode (grouped) vs Advanced mode (individual features)
- Scrollable content with mouse wheel support
- Preset save/load buttons
World-Gen Panel (WorldGenPanel) uses DraggablePanel from the Widget Library:
- Three tabs: By Seed, By Category, Presets
- Two-state checkboxes (unchecked = vanilla, checked = force on)
- Built-in presets for each full seed configuration
- Active count display in panel header
F10 opens whichever panel is appropriate: in-game panel when in a world, world-gen panel when at the menu.
5. Command Registration¶
SeedLab registers debug commands for remote/scripted control:
context.RegisterCommand("status", "Show current seed feature states", CmdStatus);
context.RegisterCommand("toggle", "Toggle a seed/group: seed-lab.toggle ftw", CmdToggle);
context.RegisterCommand("preset", "Manage presets: seed-lab.preset list", CmdPreset);
context.RegisterCommand("reset", "Reset all features to match world seed flags", CmdReset);
Commands are auto-namespaced with the mod ID, so toggle becomes seed-lab.toggle.
6. State Persistence¶
Feature states are saved per-world using the mod's config folder:
public void SaveState()
{
var data = new Dictionary<string, bool>();
foreach (var feature in _features)
data[feature.Id] = feature.Enabled;
File.WriteAllText(_statePath, JsonConvert.SerializeObject(data));
}
On world load, the mod reads the world's original seed flags and then applies any saved overrides:
public void OnWorldLoad()
{
InitFromWorldFlags(); // Read Main.getGoodWorld, Main.drunkWorld, etc.
LoadState(); // Apply saved overrides on top
RecalculateGlobalFlags();
}
Lessons Learned¶
- Save/restore flag pattern: When overriding global state for a single method call, always save the original in a prefix and restore in a postfix
- Global optimization: Skip per-method patching when the entire seed is uniformly enabled or disabled
- Dual-panel UI: Same keybind can open different panels depending on game state (in-world vs menu)
- Hierarchical features: Grouping features into seeds and groups gives users three levels of control granularity
- State independence: Runtime and world-gen states are completely separate, preventing confusing interactions
For more on Harmony patching patterns, see Harmony Basics.