namespace IslaApocalypse.Core { /// /// The single registry of constants for the v2 blueprint container — magic, version, /// section tags, validation bounds, and the sentinel values used when a v2 file is /// re-encoded from a v1 source that cannot supply real generation parameters. /// /// The byte-accurate layout lives in Core/Scripts/BLUEPRINT_FORMAT.md. Writer: /// BlueprintWriter.WriteV2. Reader: MapDataParser (v2 branch). Tags are FourCC codes /// stored as little-endian u32, so the raw bytes on disk read as ASCII ("PRMS", "HGTS", /// ...) in a hex dump. /// public static class BlueprintFormat { // "ISLA" as raw bytes 'I','S','L','A' == little-endian u32 0x414C5349. // Deliberately NOT a length-prefixed .NET string: the v1 header starts with the // 7-bit length prefix 0x07, so the first byte alone (0x49 vs 0x07) identifies the // format and the reader can dispatch without ambiguity. public const uint MAGIC = 0x414C5349; public const uint VERSION = 2; // Section tags (FourCC, little-endian). Reader rule: known tag -> parse, // unknown tag -> skip by length and continue. Never reuse a retired tag value. public const uint TAG_PARAMS = 0x534D5250; // "PRMS" public const uint TAG_HEIGHTS = 0x53544748; // "HGTS" public const uint TAG_BIOMES = 0x4D4F4942; // "BIOM" public const uint TAG_TOWNS = 0x4E574F54; // "TOWN" public const uint TAG_ROADS_HIGHWAY = 0x57484452; // "RDHW" public const uint TAG_ROADS_BRANCH = 0x52424452; // "RDBR" public const uint TAG_ROADS_RUGGED = 0x47524452; // "RDRG" public const uint TAG_ROADS_TRAIL = 0x4C544452; // "RDTL" public const uint TAG_WATER_BODY_IDS = 0x44494257; // "WBID" public const uint TAG_WATER_BODY_TABLE = 0x42544257; // "WBTB" public const uint TAG_WATER_SURFACE = 0x46525357; // "WSRF" public const uint TAG_TERRAIN_CURVE = 0x56524354; // "TCRV" public const uint TAG_TERRAIN_DETAIL = 0x4C544454; // "TDTL" // WSRF quantization: u16, 0 reserved as the no-water sentinel. A real level L // (raw blueprint height units) encodes as 1 + round(L × 32768), so a genuine // level can never encode to 0. Decodes back via (q − 1) / 32768. Covers // [0 .. ~1.99997] raw at 1/32768 raw resolution ≈ 7.7 mm of world height // (1 raw unit = 251 m) — far below the 1 m voxel. public const float WSRF_SCALE = 1f / 32768f; public static ushort EncodeWaterLevel(float level) { return (ushort)Godot.Mathf.Clamp(1 + Godot.Mathf.RoundToInt(level * 32768f), 1, ushort.MaxValue); } public static float DecodeWaterLevel(ushort quantized) { return (quantized - 1) * WSRF_SCALE; } // MapSize sanity bounds, checked before any allocation on read. public const int MIN_MAP_SIZE = 256; public const int MAX_MAP_SIZE = 32768; // Sentinels written into the params section when the source blueprint came from a // v1 file (a re-encode cannot know the original generation inputs). WorldSeed 0 is // also the config "randomize" sentinel, which no real resolved seed ever is. public const int SENTINEL_WORLD_SEED = 0; public const float SENTINEL_CRATER_RADIUS = -1f; public const float SENTINEL_DENSITY_MULTIPLIER = -1f; public const float SENTINEL_IMPACT_CENTER = -1f; // both components /// Renders a tag as its 4 ASCII characters, for log messages. public static string TagToString(uint tag) { return new string(new[] { (char)(tag & 0xFF), (char)((tag >> 8) & 0xFF), (char)((tag >> 16) & 0xFF), (char)((tag >> 24) & 0xFF) }); } } }