using Unity.Entities; using Unity.Mathematics; namespace ProjectM.Simulation { /// /// Identifies which world REGION an entity belongs to. M6 splits the single server world into two /// spatial regions at a large coordinate offset — the persistent home and /// the procedurally-arranged — and uses per-connection GhostRelevancy /// to replicate each region only to the connections whose player is currently in it. Server-side only /// (NOT a [GhostField]; the server makes all relevancy decisions). Added to players on spawn and to /// every region-scoped ghost the server spawns. Untagged ghosts are global (relevant to everyone). /// public struct RegionTag : IComponentData { /// Region id (see ): 0 = base, 1 = expedition. public byte Region; } /// Region ids for (a byte, not an enum, to keep server/Burst code trivial). public static class RegionId { /// The persistent, shared home base. public const byte Base = 0; /// The procedural expedition field (offset far from the base on +X). public const byte Expedition = 1; } /// /// Deterministic mapping of a region id to its world-space origin. The base region keeps the existing /// home-base coordinates; the expedition region lives at a large +X offset so the two never overlap in /// the single shared PhysicsWorld. Pure (no RNG/wall-clock) — server-authoritative teleports and field /// spawners resolve region positions through here. /// public static class RegionMath { /// World-space X offset of the expedition region (room sub-slot 0) from the base region. public const float ExpeditionOffsetX = 1000f; /// X stride between the two ping-pong room sub-slots — kept >= any sweep/AI/aggro range so two /// transiently-coexisting arenas can never interact in the shared PhysicsWorld. public const float RoomStrideX = 500f; /// Region-flip boundary X (half the expedition offset): a player/camera past this reads as the /// +1000 expedition region. Single source for the HUD / onboarding / atmosphere region checks (DR-013). public const float RegionBoundaryX = ExpeditionOffsetX * 0.5f; /// /// World-space origin of expedition room sub-slot (0 or 1 — the run FSM /// ping-pongs consecutive rooms between two offsets so the next room spawns at the idle slot while the /// cleared one is torn down). THE single expedition coordinate authority: every expedition placement /// (field scatter, enemy ring, party teleport) resolves through here. /// public static float3 ExpeditionRoomOrigin(float3 baseCenter, byte subSlot) { return baseCenter + new float3(ExpeditionOffsetX + subSlot * RoomStrideX, 0f, 0f); } /// World-space position of the room-exit PORTAL for sub-slot — the single /// client-derivable authority the HUD prompt AND the presentation beacon both resolve through (DR-046), so they /// can't drift. = the room origin nudged by in Z. public static float3 ExpeditionPortalPos(float3 baseCenter, byte subSlot) { float3 p = ExpeditionRoomOrigin(baseCenter, subSlot); p.z += Tuning.PortalOffsetZ; return p; } /// World-space origin of , given the base center (BaseGridMath.PlotCenter). /// The expedition resolves to room sub-slot 0 (legacy call sites; room-aware systems pass the ACTIVE /// sub-slot to directly). public static float3 RegionOrigin(byte region, float3 baseCenter) { return region == RegionId.Expedition ? ExpeditionRoomOrigin(baseCenter, 0) : baseCenter; } } }