Retire regions: capacity-bounded simulator content, geo AOI instead of region scoping #15
Labels
No labels
agent
agent:ci
agent:done
agent:failed
agent:needs-input
agent:refined
agent:refining
agent:running
agent:skip
autonomous
driven
local
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jeroen/cartopolis#15
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The project moved from a flat, region-based world (OpenSim/SecondLife style
parcels) to a globe with
big_space. Simulator content is no longer bound toregion spaces; it should be capacity-bounded — a simulator caps how many
assets it hosts (prims / objects / scripts), not where they sit.
The concept is retired but the code is not.
map_stream.rs:258-261already saysso in a comment — "Regions are retired (ADR-020/029), so there is no seed region
to read a location from" — while
vibe_simstill seeds one, ships it on thewire, and the client still meshes it. That gap is actively misleading: it reads
like current design to anyone (or anything) grepping the tree.
It also causes a live replication bug, which is the real cost.
SimWorld::snapshot(crates/vibe_sim/src/state.rs:174-192) filters prims bywhether their region passed the observer AOI test:
…and regions are filtered by the distance from
region_sim_originto theobserver against
aoi_radius(default 500 m,config.rs:37-39). The singleseeded region sits at
Vec3::ZERO. So every prim in the world stopsreplicating as soon as the observer is more than 500 m from the sim grid origin,
regardless of where the prim actually is. A geo-distance AOI on the prim's own
GeoAnchoris both the fix and strictly more correct.Two further symptoms of the same vestige:
region_idsent client→server is fabricated: both authoring paths doregion_query.iter().next().map(|r| r.id).unwrap_or(1)(ui.rs:1686,ai_assistant.rs:560). It carries no information.GameState::regions_loaded(resources.rs:237) is write-only — set atnetwork.rs:298/304, read by nobody.Approach
1.
vibe_sim— capacity replaces scopingSimWorld::snapshot(state.rs:174-192) bygeographic distance from the observer to
PrimDto.geo, dropping the regionhop entirely. This is the bug fix.
SimConfig(config.rs:8-22)has
listen,database_path,tick_hz,aoi_radius,osm_tile_url_template,texture_dirand nothing else. Addmax_prims(and the fields below), enforcedin
SimWorld::add_prim(state.rs:218-238) before the DB insert, rejectedthrough the
ServerErrorpath that already exists for this shape atnet.rs:243-250(code 400 + message). Wire throughDefault(config.rs:48-58),apply_cli(:71-90) andcli.rs.state.rs:70-90) currently takes the lowest-id region'sorigin. Replace with a configured
spawn_lat/spawn_lng, falling back toVec3::ZERO— which is already what theunwrap_oryields with no region.regions: Vec<RegionDto>andregion_sim_originfromSimWorld(
state.rs:16-27) and the 300 m grid-layout generator inSimWorld::new(
:30-67) — the sole producer ofRegionDto::sim_*.db.rs: dropseed_default_region(:80-102, called at:76), the regionhalf of
load_world(:104-131), and the FK existence check ininsert_prim(
:143-153).2. Schema — migration V7
V1__initial.sqlcreatesregions(:3-15) and givesprimsaregion_id INTEGER NOT NULL(:19) withFOREIGN KEY … REFERENCES regions(id)(
:36) plusidx_prims_region(:39). SQLite cannot drop a FK-referenced columnin place, so V7 needs the table-rebuild dance (
CREATE TABLE prims_new …; INSERT SELECT; DROP; RENAME). NotePRIM_COLUMNS(db.rs:8) is positional androw_to_prim(:22-59) indexes off it — dropping the column shifts every index.3. Wire — protocol v12
Exactly three places carry a region:
PrimDto.region_id(
protocol.rs:222-224),NetMessage::WorldSnapshot.regions(:343-349),NetMessage::CreatePrim.region_id(:354-370). postcard is positional, soremoving them is breaking → append a
ProtocolRevision { version: 12, … }rowto
PROTOCOL_HISTORY(protocol.rs:29-51);PROTOCOL_VERSIONderives from it,so the number is written nowhere else. Roundtrip tests to update:
:597,:610,:693.4.
viberfoxclient — delete the render chaincomponents::Region(components.rs:4-16) andPrim.region_id(:22);rendering::spawn_regions+RegionMesh+update_region_materials(
rendering.rs:16-17, 429-556);tile_loader'sRegionTile/RegionTileTexture/load_region_tiles(tile_loader.rs:86-92, 340-429), whichlose their only producer;
debug::debug_region_entities(debug.rs:1-19, thewhole file);
GameState::regions_loaded; the region arms innetwork::apply_network_snapshot(network.rs:225, 286-303),data_layers::apply_feature_toggles(data_layers.rs:1109-1118, 1169-1187),ui::apply_prim_edits(ui.rs:1679-1705),ai_assistant(ai_assistant.rs:381, 532, 560, 573),picking::prim_picking(picking.rs:33, 167-180).Also drop the six
.after(rendering::spawn_regions)constraints (main.rs:640,:641,:642,:656,:682,:794). None of those systems need regions — theyall anchor off
MapStream; the ordering was a "world is ready" barrier. If one isgenuinely wanted,
prim_geo::place_geo_primsis the honest barrier.5.
vibe_core— dead tessellationregion_index/region_origin/regions_adjacent/REGION_SIZE(
geo.rs:97-124) have zero call sites outside their own test (:198-207) —pure deletion, no replacement.
Acceptance criteria
not on a region's. Regression test: an observer >500 m from the sim origin
still receives a prim next to them.
SimConfigcarries a prim/object capacity; exceeding it rejects theCreatePrimwith aServerError, and there is a test for the boundary.regioninvibe_core::protocol;PROTOCOL_HISTORYhas a v12 row andthe gapless-run test passes.
regionstable; V7 migrates an existingdata/world.dbwithout dataloss for prims.
grep -rn "Region" crates/returns only unrelated matches (transit region,subregion, hover region, overlap region — listed in Out of scope).
cargo run -p viberfox(solo) starts, streams and renders with no region.Care points — three things that break quietly
ui.rs:930gates it oncontext_menu.hit_region_id.is_some(), which is the only load-bearing use ofhit_region_id. Removing regions without changing that line permanentlyremoves prim creation from the map. It needs a new anchor — the click's
lat_lng(already onContextMenuState) is the obvious one.free_camera::get_ground_height(free_camera.rs:1327-1341, called:714and
:881) clamps the camera againstRegionMeshtransforms. With none ityields
0.0— same as offline today, so behaviourally safe, but it silentlystops doing anything. If terrain elevation is coming, this is the hook to
re-point at the streamed tiles.
REGION_ZOOM_LEVEL(17) must be renamed, not deleted — it is the de-factobase map zoom with live callers at
map_stream.rs:191,geo_nav.rs:848anddb.rs:87. SuggestBASE_MAP_ZOOM. CheckREGION_SIZE_METERS(
world.rs:31, re-exportedtile_utils.rs:4) for live consumers beforedeleting.
Verification
cargo check -p vibe_core,cargo check -p vibe_sim,cargo check -p viberfox;cargo test -p viberfox --bin viberfox,cargo test -p vibe_sim,cargo test -p vibe_core. Migration: copydata/world.dbfirst (project rule),then start
vibe_simagainst a pre-V7 copy and confirm prims survive.Visual:
cargo shots— the region ground quad disappearing must not leave a holewhere the streamed tiles were relying on it.
Out of scope
(positions are cluster-local
Vec3today); not part of removing regions.vibe_simorvibe_core(grep returns zero hits), so "max scripts per simulator" is greenfield and
belongs with whatever introduces scripting. This ticket sizes prims/objects.
globe_weather.rs:204(subregion APIparam),
transit_live.rs:68(transit region timezone),geo_nav.rs:947(regional framing),
driver.rs(hover regions),osm_buildings.rs:954(overlapregion),
docs/guides/server.md:101(Geofabrik extract).Branch:
feat/15-retire-regions-capacity-bounded