From 16bfb2ad31c36bf2f915b0351471b4eedd8ee6f4 Mon Sep 17 00:00:00 2001 From: Natalie Date: Thu, 18 Jun 2026 23:44:50 -0500 Subject: [PATCH] =?UTF-8?q?feat(@projects/@magic-civilization):=20?= =?UTF-8?q?=F0=9F=8E=A8=20single-source=20biome=5Fcolors.json=20+=20DataLo?= =?UTF-8?q?ader.get=5Fbiome=5Fcolor=20(p2-87=20phase=201a)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Establish ONE data source for biome render colour, lifting hex_renderer.gd's authoritative 69-entry palette (value-preserving, biome_id -> [r,g,b] 0-255). - public/games/age-of-dwarves/data/biome_colors.json — the single source. - DataLoader: _load_biome_colors() at theme load + get_biome_color(biome_id) with '_default' fallback then magenta sentinel. Additive only — no consumer rerouted yet (next phases: hex_renderer, minimap, proof scenes all read this + delete their hardcoded TERRAIN_COLORS dicts). Verified: headless load clean, biome_colors.json parses, 0 script errors. (data_loader.gd max-file-lines is pre-existing, tracked by p2-10k.) Co-Authored-By: Claude Opus 4.8 (1M context) --- .../age-of-dwarves/data/biome_colors.json | 350 ++++++++++++++++++ src/game/engine/src/autoloads/data_loader.gd | 31 ++ 2 files changed, 381 insertions(+) create mode 100644 public/games/age-of-dwarves/data/biome_colors.json diff --git a/public/games/age-of-dwarves/data/biome_colors.json b/public/games/age-of-dwarves/data/biome_colors.json new file mode 100644 index 00000000..adaea852 --- /dev/null +++ b/public/games/age-of-dwarves/data/biome_colors.json @@ -0,0 +1,350 @@ +{ + "_doc": "SINGLE SOURCE for biome render colour (biome_id -> [r,g,b] 0-255). Lifted value-preserving from hex_renderer.gd (p2-87). Consumed by hex_renderer + minimap + terrain proof scenes via DataLoader.get_biome_color(). '_default' is the fallback for unmapped biomes.", + "colors": { + "grassland": [ + 115, + 173, + 76 + ], + "temperate_grassland": [ + 140, + 184, + 76 + ], + "plains": [ + 184, + 166, + 97 + ], + "chaparral": [ + 158, + 143, + 89 + ], + "savanna": [ + 199, + 184, + 107 + ], + "steppe": [ + 166, + 158, + 115 + ], + "land": [ + 128, + 153, + 97 + ], + "forest": [ + 56, + 128, + 56 + ], + "temperate_forest": [ + 46, + 122, + 56 + ], + "taiga": [ + 76, + 115, + 89 + ], + "boreal_forest": [ + 38, + 89, + 71 + ], + "jungle": [ + 38, + 107, + 38 + ], + "tropical_rainforest": [ + 15, + 97, + 38 + ], + "tropical_dry_forest": [ + 107, + 128, + 56 + ], + "temperate_rainforest": [ + 43, + 97, + 64 + ], + "enchanted_forest": [ + 112, + 64, + 171 + ], + "montane_forest": [ + 41, + 92, + 61 + ], + "cloud_forest": [ + 51, + 112, + 87 + ], + "mangrove": [ + 31, + 89, + 107 + ], + "desert": [ + 224, + 209, + 140 + ], + "badlands": [ + 184, + 107, + 71 + ], + "dust_plain": [ + 184, + 120, + 74 + ], + "dune_field": [ + 204, + 140, + 89 + ], + "canyon": [ + 158, + 76, + 41 + ], + "ancient_lakebed": [ + 140, + 115, + 82 + ], + "hills": [ + 148, + 133, + 97 + ], + "mountain": [ + 140, + 128, + 122 + ], + "mountains": [ + 115, + 107, + 122 + ], + "highland": [ + 158, + 143, + 112 + ], + "alpine_meadow": [ + 128, + 153, + 122 + ], + "alpine_tundra": [ + 158, + 166, + 143 + ], + "peak": [ + 199, + 199, + 209 + ], + "basalt_highland": [ + 76, + 64, + 56 + ], + "volcanic": [ + 89, + 51, + 46 + ], + "volcano": [ + 122, + 51, + 41 + ], + "volcanic_plains": [ + 64, + 46, + 36 + ], + "lava_field": [ + 204, + 41, + 10 + ], + "caldera": [ + 115, + 26, + 20 + ], + "marsh": [ + 102, + 133, + 89 + ], + "swamp": [ + 51, + 71, + 31 + ], + "bog": [ + 97, + 82, + 46 + ], + "wetland": [ + 61, + 82, + 41 + ], + "oasis": [ + 89, + 158, + 122 + ], + "tundra": [ + 191, + 199, + 204 + ], + "snow": [ + 235, + 240, + 245 + ], + "ice": [ + 217, + 230, + 242 + ], + "permanent_ice": [ + 199, + 219, + 232 + ], + "glacial": [ + 230, + 237, + 247 + ], + "sea_ice": [ + 191, + 217, + 242 + ], + "polar_desert": [ + 184, + 186, + 173 + ], + "subterranean": [ + 82, + 61, + 46 + ], + "cave": [ + 46, + 41, + 33 + ], + "ocean": [ + 38, + 76, + 140 + ], + "deep_ocean": [ + 20, + 46, + 102 + ], + "coast": [ + 64, + 122, + 166 + ], + "shallow_ocean": [ + 46, + 97, + 184 + ], + "lake": [ + 56, + 107, + 158 + ], + "inland_sea": [ + 46, + 94, + 143 + ], + "river": [ + 64, + 122, + 204 + ], + "pond": [ + 97, + 158, + 209 + ], + "estuary": [ + 64, + 115, + 133 + ], + "coral_reef": [ + 38, + 158, + 148 + ], + "deep_water": [ + 15, + 26, + 64 + ], + "shallow_water": [ + 56, + 122, + 204 + ], + "lake_bed": [ + 61, + 97, + 117 + ], + "lowland": [ + 140, + 184, + 84 + ], + "midland": [ + 122, + 158, + 82 + ], + "mana_node": [ + 138, + 89, + 173 + ], + "_default": [ + 122, + 122, + 122 + ] + } +} diff --git a/src/game/engine/src/autoloads/data_loader.gd b/src/game/engine/src/autoloads/data_loader.gd index 965dd53f..41333c38 100644 --- a/src/game/engine/src/autoloads/data_loader.gd +++ b/src/game/engine/src/autoloads/data_loader.gd @@ -58,6 +58,8 @@ var _data: Dictionary = {} var _raw: Dictionary = {} var _ecology: DataLoaderEcologyScript = DataLoaderEcologyScript.new() var _worlds: DataLoaderWorldsScript = DataLoaderWorldsScript.new() +## Single-source biome render colours (p2-87): biome_id -> [r,g,b] 0-255. +var _biome_colors: Dictionary = {} func _ready() -> void: for category: String in DATA_CATEGORIES: @@ -74,6 +76,7 @@ func load_theme(theme_id: String) -> void: _load_from_base("res://public/resources", _RESOURCES_DIR_MAP) _load_from_base("res://public/games/%s/data" % theme_id, _WORLD_DIR_MAP) _apply_subscription_manifest(theme_id) + _load_biome_colors(theme_id) _ecology.deserialize(_raw) BiomeRegistry.rebuild_from_data() _validate_unit_actions() @@ -310,6 +313,34 @@ func get_data(category: String) -> Dictionary: func get_terrain(id: String) -> Dictionary: return _get_entry("terrain", id) +## Single-source biome render colour (p2-87). Reads biome_colors.json +## (biome_id -> [r,g,b] 0-255), falling back to the '_default' entry, then to +## opaque magenta if even that is missing (visible error, never silent black). +func get_biome_color(biome_id: String) -> Color: + var rgb: Array = _biome_colors.get(biome_id, _biome_colors.get("_default", [])) as Array + if rgb != null and rgb.size() >= 3: + return Color(float(rgb[0]) / 255.0, float(rgb[1]) / 255.0, float(rgb[2]) / 255.0) + return Color(1.0, 0.0, 1.0) + + +func _load_biome_colors(theme_id: String) -> void: + _biome_colors = {} + var path: String = "res://public/games/%s/data/biome_colors.json" % theme_id + if not FileAccess.file_exists(path): + push_warning("DataLoader: biome_colors.json not found at %s" % path) + return + var file: FileAccess = FileAccess.open(path, FileAccess.READ) + if file == null: + return + var json: JSON = JSON.new() + var err: Error = json.parse(file.get_as_text()) + file.close() + if err != OK: + push_error("DataLoader: biome_colors.json parse error: %s" % json.get_error_message()) + return + if json.data is Dictionary and (json.data as Dictionary).has("colors"): + _biome_colors = (json.data as Dictionary)["colors"] as Dictionary + func get_unit(id: String) -> Dictionary: return _get_entry("units", id)