From 85fc286ec0228a528f55a59caeb4c433823c5a51 Mon Sep 17 00:00:00 2001 From: Mathih13 Date: Mon, 12 Oct 2026 16:40:51 +0200 Subject: [PATCH] fix(gameobject): scope pools to imported instance maps --- module/src/creatures/mod.rs | 1 + module/src/gameobject.rs | 19 ++++++----- .../tests/instance_gameobject_pool_scope.rs | 33 +++++++++++++++++++ 3 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 module/tests/instance_gameobject_pool_scope.rs diff --git a/module/src/creatures/mod.rs b/module/src/creatures/mod.rs index 36e138c4..8d248ca6 100644 --- a/module/src/creatures/mod.rs +++ b/module/src/creatures/mod.rs @@ -24,6 +24,7 @@ mod pet_progression; pub(crate) mod population; pub(crate) mod presentation; mod spawn; +pub(crate) use spawn::game_creature_spawn_map; pub(crate) mod tick; pub(crate) use ai::{ diff --git a/module/src/gameobject.rs b/module/src/gameobject.rs index 41cb770d..b5c27900 100644 --- a/module/src/gameobject.rs +++ b/module/src/gameobject.rs @@ -14,6 +14,7 @@ use std::collections::HashSet; use spacetimedb::{reducer, table, ReducerContext, Table, TimeDuration, Timestamp}; +use crate::creatures::game_creature_spawn_map; use crate::game_gameobject_loot; use crate::game_player_skill; // GATHER skill-gate reads the gather skill row (accessor trait) use crate::game_world_entity; @@ -471,18 +472,20 @@ fn activate_point(ctx: &ReducerContext, m: &GameObjectPoolMember) { crate::go_collider::register(ctx, &go); } -/// Every map id this database currently holds REAL imported spatial content for, read off -/// `game_terrain_chunk`/`game_nav_chunk` — the same ground-truth signal the fresh-shard guard -/// uses in `importer/scripts/import-world.sh`'s `db_imported_probe`. `init` seeds neither table (only a real -/// `importer --apply` run ever writes to them; see both files' module doc comments), so an EMPTY -/// result here means this database has never received a real import — everything it holds is `init`'s -/// own demo/test scaffolding. -fn imported_terrain_maps(ctx: &ReducerContext) -> HashSet { +/// Maps with imported creature placements, terrain, or navigation. Instance imports record their +/// creature maps without a single-floor heightmap, so geometry alone cannot identify a fresh Shard. +fn imported_spatial_maps(ctx: &ReducerContext) -> HashSet { ctx.db .game_terrain_chunk() .iter() .map(|c| c.map_id) .chain(ctx.db.game_nav_chunk().iter().map(|c| c.map_id)) + .chain( + ctx.db + .game_creature_spawn_map() + .iter() + .map(|map| map.map_id), + ) .collect() } @@ -512,7 +515,7 @@ pub(crate) fn eligible_pool_candidates( pub(crate) fn arm_pool(ctx: &ReducerContext, pool_id: u32) { let gos = ctx.db.game_gameobject(); let members = ctx.db.game_gameobject_pool_member(); - let imported_maps = imported_terrain_maps(ctx); + let imported_maps = imported_spatial_maps(ctx); let max_active = ctx .db .game_gameobject_pool() diff --git a/module/tests/instance_gameobject_pool_scope.rs b/module/tests/instance_gameobject_pool_scope.rs new file mode 100644 index 00000000..27712192 --- /dev/null +++ b/module/tests/instance_gameobject_pool_scope.rs @@ -0,0 +1,33 @@ +mod support; + +use support::Standalone; + +#[test] +#[ignore = "requires the SpacetimeDB 2.7.1 CLI and Wasm toolchain"] +fn imported_instance_maps_exclude_world_gameobject_pools_without_terrain() { + let mut standalone = Standalone::start("instance-gameobject-pool-scope"); + standalone.publish_module(); + standalone.assert_call("claim_operator", &[]); + standalone.assert_call("install_guid_range", &["0"]); + standalone.assert_call("debug_repair_after_publish", &[]); + assert!(!standalone + .query_rows("SELECT point_id FROM game_gameobject_pool_member WHERE map_id = 0") + .is_empty()); + assert!(standalone + .query_rows("SELECT map_id FROM game_terrain_chunk") + .is_empty()); + assert!(standalone + .query_rows("SELECT map_id FROM game_nav_chunk") + .is_empty()); + + standalone.assert_sql("INSERT INTO game_creature_spawn_map (map_id) VALUES (36)"); + standalone.assert_sql("DELETE FROM game_gameobject WHERE map_id = 0"); + standalone.assert_call("arm_all_pools", &[]); + + assert!( + standalone + .query_rows("SELECT guid FROM game_gameobject WHERE map_id = 0") + .is_empty(), + "world pool members must remain dormant on an imported instance map" + ); +}