namespace AcDream.Core.World; /// /// Allocates stable, collision-free ids for procedurally generated scenery. /// /// /// The top nibble is fixed at 0x8, so bit 31 continues to identify /// procedural scenery to every renderer and physics consumer. The remaining /// 28 bits are X(8), Y(8), and a 12-bit per-landblock counter: /// 0x8XXYYIII. No consumer decodes the former byte-aligned /// 0x80XXYYII layout; they classify only on bit 31. /// /// /// /// 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++; } }