using Godot; using Godot.Collections; // Required for Godot's built-in JSON parser namespace IslaApocalypse.Core // Change this if your namespace is different { public static class ConfigManager { // Default Fallbacks // public static int WorldSeed = 1063685222; public static int WorldSeed = (int)GD.Randi(); // if 0 also randomizes public static int MapSize = 8192; public static float CraterRadius = 400f; public static float DensityMultiplier = 1.0f; // <-- Replaces TownCount public static int ChunkRadius = 24; // Default chunk size, can be overridden by config // Iteration toggle: skip the ~25-min A* road pass entirely. The blueprint is // still exported (road sections present but empty) — an iteration artifact, // not a shippable world. Default false. public static bool SkipRoads = false; // Sea-level model (D-033, terrain-water task 04): "flat" = one scalar sea // level everywhere (SeaLevelValue); "field" = the legacy latitude Lerp // (0.26 north .. 0.15 south). Generator-only — the runtime never computes // sea level. Default: flat 0.15. public static string SeaLevelModel = "flat"; public static float SeaLevelValue = 0.15f; // Height-redistribution curve (tasks 05/06/07, graduation M-7): "v3" applies // the terraced-ascent curve with the per-seed peak spike (HeightCurve.cs); // "off" is the raw legacy profile. "v1"/"v2" were retired by their successor // recalibrations (old blueprints are regenerable). Biome classification is // curve-invariant by construction either way. Default: v3. public static string TerrainCurve = "v3"; public static void LoadConfig() { string path = "res://ServerConfig.json"; if (!FileAccess.FileExists(path)) { GD.PrintErr("[ConfigManager] ServerConfig.json not found! Defaulting to 8K."); return; } // Read the file using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read); string content = file.GetAsText(); // Parse the JSON var json = new Json(); var error = json.Parse(content); if (error != Error.Ok) { GD.PrintErr($"[ConfigManager] JSON Parse Error: {json.GetErrorMessage()}"); return; } var data = (Dictionary)json.Data; // Extract the Seed if (data.ContainsKey("WorldSeed")) { WorldSeed = (int)data["WorldSeed"]; } // Extract the MapProfile and run your Switch/Case logic! string profile = "8K"; if (data.ContainsKey("MapProfile")) { profile = (string)data["MapProfile"]; } // Extract the TownDensity and run your Switch/Case logic! string townDensity = "Normal"; if (data.ContainsKey("TownDensity")) { townDensity = (string)data["TownDensity"]; } // Extract the ChunkRadius if (data.ContainsKey("ChunkRadius")) { ChunkRadius = (int)data["ChunkRadius"]; } // Extract the SkipRoads iteration toggle if (data.ContainsKey("SkipRoads")) { SkipRoads = (bool)data["SkipRoads"]; } // Extract the sea-level model if (data.ContainsKey("SeaLevelModel")) { string model = (string)data["SeaLevelModel"]; if (model == "flat" || model == "field") SeaLevelModel = model; else GD.PrintErr($"[ConfigManager] Unknown SeaLevelModel '{model}'. Keeping '{SeaLevelModel}'."); } if (data.ContainsKey("SeaLevelValue")) { SeaLevelValue = (float)data["SeaLevelValue"]; } // Extract the terrain-curve gate if (data.ContainsKey("TerrainCurve")) { string curve = (string)data["TerrainCurve"]; if (curve == "off" || curve == "v3") TerrainCurve = curve; else if (curve == "v1" || curve == "v2") GD.PrintErr($"[ConfigManager] TerrainCurve '{curve}' was retired by a later recalibration (v3, task 07). Keeping '{TerrainCurve}' — use \"v3\" or \"off\"."); else GD.PrintErr($"[ConfigManager] Unknown TerrainCurve '{curve}'. Keeping '{TerrainCurve}'."); } switch (profile) { case "4K": MapSize = 4096; CraterRadius = 400f; // Scaled down crater break; case "6K": MapSize = 6144; CraterRadius = 600f; break; case "8K": MapSize = 8192; CraterRadius = 800f; // Your original crater size spread over an 8K map break; case "10K": MapSize = 10240; CraterRadius = 1000f; break; default: GD.PrintErr($"[ConfigManager] Unknown MapProfile '{profile}'. Defaulting to 8K."); MapSize = 8192; CraterRadius = 800f; break; } switch (townDensity) { case "Sparse": DensityMultiplier = 0.5f; break; case "Normal": DensityMultiplier = 1.0f; break; case "Dense": DensityMultiplier = 2.0f; break; default: GD.PrintErr($"[ConfigManager] Unknown TownDensity '{townDensity}'. Defaulting to Normal."); DensityMultiplier = 1.0f; break; } GD.Print($"[ConfigManager] Successfully loaded {profile} Profile. MapSize set to {MapSize}."); } } }