using Godot; using System.IO; using System.Collections.Generic; namespace IslaApocalypse.Core { // 1. The Data Container // This holds the unpacked data in RAM so the Server can ask it questions // without having to re-read the hard drive every single frame. public struct TownLocation { public Vector2 Position; public TownTier Tier; } public class WorldBlueprint { public int MapSize; public float[,] HeightMap; public Biome[,] BiomeMap; public List Towns = new List(); // All 4 road tiers! public List Highways = new List(); public List BranchRoads = new List(); public List RuggedRoads = new List(); public List TrailRoads = new List(); } // 2. The Parser Utility public static class MapDataParser { public static WorldBlueprint LoadMapData(string seedStr) { string filePath = ProjectSettings.GlobalizePath($"user://MapData_Seed_{seedStr}.dat"); if (!File.Exists(filePath)) { GD.PrintErr($"[MapDataParser] CRITICAL ERROR: Map file not found at {filePath}"); return null; } WorldBlueprint blueprint = new WorldBlueprint(); using (FileStream stream = File.OpenRead(filePath)) { using (BinaryReader reader = new BinaryReader(stream)) { // 1. Header Validation (CRITICAL: Must read string first to align bytes!) string header = reader.ReadString(); if (header != "ISLA_V1") { GD.PrintErr("[MapDataParser] ERROR: Invalid map version or corrupted file."); return null; } // 2. Read Map Dimensions & Initialize Arrays blueprint.MapSize = reader.ReadInt32(); blueprint.HeightMap = new float[blueprint.MapSize, blueprint.MapSize]; blueprint.BiomeMap = new Biome[blueprint.MapSize, blueprint.MapSize]; // 3. Read Raw Voxel Data (Height & Biome) for (int x = 0; x < blueprint.MapSize; x++) { for (int y = 0; y < blueprint.MapSize; y++) { blueprint.HeightMap[x, y] = reader.ReadSingle(); blueprint.BiomeMap[x, y] = (Biome)reader.ReadInt32(); } } // 4. Read Logistical Anchors (Towns & POIs) int townCount = reader.ReadInt32(); for (int i = 0; i < townCount; i++) { TownLocation town = new TownLocation(); town.Position = new Vector2(reader.ReadSingle(), reader.ReadSingle()); town.Tier = (TownTier)reader.ReadInt32(); blueprint.Towns.Add(town); } // 5. Read Road Networks // Highway int highwayCount = reader.ReadInt32(); for (int i = 0; i < highwayCount; i++) { int pathLength = reader.ReadInt32(); Vector2[] path = new Vector2[pathLength]; for (int p = 0; p < pathLength; p++) { path[p] = new Vector2(reader.ReadSingle(), reader.ReadSingle()); } blueprint.Highways.Add(path); } // Branch int branchCount = reader.ReadInt32(); for (int i = 0; i < branchCount; i++) { int pathLength = reader.ReadInt32(); Vector2[] path = new Vector2[pathLength]; for (int p = 0; p < pathLength; p++) { path[p] = new Vector2(reader.ReadSingle(), reader.ReadSingle()); } blueprint.BranchRoads.Add(path); } // Rugged int ruggedCount = reader.ReadInt32(); for (int i = 0; i < ruggedCount; i++) { int pathLength = reader.ReadInt32(); Vector2[] path = new Vector2[pathLength]; for (int p = 0; p < pathLength; p++) { path[p] = new Vector2(reader.ReadSingle(), reader.ReadSingle()); } blueprint.RuggedRoads.Add(path); } // Trails int trailCount = reader.ReadInt32(); for (int i = 0; i < trailCount; i++) { int pathLength = reader.ReadInt32(); Vector2[] path = new Vector2[pathLength]; for (int p = 0; p < pathLength; p++) { path[p] = new Vector2(reader.ReadSingle(), reader.ReadSingle()); } blueprint.TrailRoads.Add(path); } } } GD.Print($"[MapDataParser] Successfully loaded Blueprint for Seed {seedStr}. Dimension: {blueprint.MapSize}x{blueprint.MapSize}."); return blueprint; } } }