islaApocalypse/Core/Scripts/MapDataParser.cs
beezm 7f0f43b5fb baseline: working salvaged prototype on Godot 4.7.1 (pre-F1)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 01:45:41 -04:00

129 lines
No EOL
4 KiB
C#

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<TownLocation> Towns = new List<TownLocation>();
// All 4 road tiers!
public List<Vector2[]> Highways = new List<Vector2[]>();
public List<Vector2[]> BranchRoads = new List<Vector2[]>();
public List<Vector2[]> RuggedRoads = new List<Vector2[]>();
public List<Vector2[]> TrailRoads = new List<Vector2[]>();
}
// 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;
}
}
}