From f3a131b8b321b8a6b08c46b14c341b8809dd7d54 Mon Sep 17 00:00:00 2001 From: autocommit Date: Wed, 29 Apr 2026 10:11:55 -0700 Subject: [PATCH] =?UTF-8?q?feat(simulator):=20=E2=9C=A8=20Add=20species=20?= =?UTF-8?q?registration=20API=20endpoints=20to=20manage=20fauna=20species?= =?UTF-8?q?=20for=20controlled=20population=20seeding=20in=20ecology=20sim?= =?UTF-8?q?ulations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- src/simulator/api-gdext/src/lib.rs | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/simulator/api-gdext/src/lib.rs b/src/simulator/api-gdext/src/lib.rs index bc5a3a00..a26561c2 100644 --- a/src/simulator/api-gdext/src/lib.rs +++ b/src/simulator/api-gdext/src/lib.rs @@ -20,6 +20,8 @@ use mc_climate::spec; use mc_core::grid::GridState; use mc_ecology::EcologyEngine; use mc_ecology::fauna_product::{fauna_product_supply, FaunaProduct}; +use mc_ecology::population::PopulationSlot; +use mc_ecology::species::Species; use mc_mapgen::MapGenerator; struct MagicCivPhysicsExtension; @@ -334,6 +336,42 @@ impl GdFaunaEcology { } out } + + /// Register a fauna species from its canonical JSON definition (the same + /// shape consumed by `mc_ecology::species::Species::from_json`, matching + /// `public/resources/ecology/fauna/species/*.json`). The numeric + /// `species_id` is derived from a hash of the string `id` field; the + /// caller passes that returned id to `seed_population`. + /// + /// Returns `-1` on parse error. Used by proof scenes and integration tests + /// to construct controlled fauna populations against the live engine. + #[func] + fn register_species_from_json(&mut self, species_json: GString) -> i64 { + match Species::from_json(&species_json.to_string()) { + Ok(species) => { + let id = species.id as i64; + self.inner.register_species(species); + id + } + Err(e) => { + godot_error!("GdFaunaEcology::register_species_from_json: {e}"); + -1 + } + } + } + + /// Seed a population slot onto a tile. `species_id` must be the value + /// returned by a prior `register_species_from_json` call. Negative or + /// out-of-range ids are silently ignored. Multiple seed calls on the + /// same tile push additional slots (matches `EcologyEngine::seed_population`). + #[func] + fn seed_population(&mut self, col: i32, row: i32, species_id: i64, population: f64) { + if !(0..=u32::MAX as i64).contains(&species_id) { + return; + } + let slot = PopulationSlot::new(species_id as u32, population as f32); + self.inner.seed_population(col, row, slot); + } } // ── GdAtmosphericChemistry ──────────────────────────────────────────────