namespace AcDream.Core.World; /// /// Allocates stable, collision-free ids for procedurally generated scenery. /// /// /// The top nibble is fixed at 0x8: tests /// (id & 0xF0000000u) == 0x80000000u, the full nibble, not bit 31 /// alone. Bit 31 alone is NOT a reliable procedural-scenery test — it is /// also set by LandblockStaticEntityIdAllocator's 0xC... /// namespace (top nibble 1100) and by the synthetic render ids /// 0xDA11_D0xx (paperdoll) and 0xFFFF_FF01 (portal tunnel). /// LandblockPhysicsPublisher.cs's isOutdoorMesh predicate /// intentionally tests bit 31 alone — it wants "any of these broader /// synthetic/outdoor namespaces", not specifically procedural scenery — but /// that is the one deliberate exception; every OTHER consumer, including /// foliage-wind classification, must use . The /// remaining 28 bits are X(8), Y(8), and a 12-bit per-landblock counter: /// 0x8XXYYIII. /// /// /// /// The old 8-bit counter aborted generation after 256 drawable spawns. That /// exception rejected the entire streamed landblock before render publication, /// exposing the grey clear color as portal space ended. A 12-bit counter gives /// 4096 entries while retaining full landblock coordinates. Overflow fails /// before it can alias the next landblock. /// /// public static class ProceduralSceneryIdAllocator { public const uint MaxCounter = 0xFFFu; public static uint Base(uint landblockX, uint landblockY) => 0x80000000u | ((landblockX & 0xFFu) << 20) | ((landblockY & 0xFFu) << 12); public static uint Allocate(uint landblockX, uint landblockY, ref uint counter) { if (counter > MaxCounter) throw new InvalidDataException( $"Landblock ({landblockX & 0xFFu:X2},{landblockY & 0xFFu:X2}) exceeds the 4096-entry procedural scenery id namespace."); return Base(landblockX, landblockY) + counter++; } /// /// The full top-nibble test — 0x8..., not bit 31 alone. Bit 31 /// alone also matches LandblockStaticEntityIdAllocator's /// 0xC... ids (top nibble 1100 also has bit 31 set) and /// the synthetic render ids 0xDA11_D0xx / 0xFFFF_FF01. /// public static bool IsInNamespace(uint entityId) => (entityId & 0xF0000000u) == 0x80000000u; }