Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions module/src/creatures/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down
19 changes: 11 additions & 8 deletions module/src/gameobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<u32> {
/// 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<u32> {
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()
}

Expand Down Expand Up @@ -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()
Expand Down
33 changes: 33 additions & 0 deletions module/tests/instance_gameobject_pool_scope.rs
Original file line number Diff line number Diff line change
@@ -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"
);
}
Loading