acdream/src/AcDream.Core/World/LandblockStaticEntityIdAllocator.cs
Erik 749e8ceeb1 fix(rendering): bound portal resource lifetime
Separate logical ownership, render publication, and GPU retirement across live entities, landblocks, particles, textures, mesh arenas, portal/UI teardown, and per-frame scratch storage. Add bounded DAT/texture caches, upload budgets, three-frame fence retirement, exact-incarnation appearance reconciliation, frame pacing, and extensive lifetime conformance coverage.\n\nThe seven-destination connected route now cuts peak working/private memory roughly in half, returns Caul to 125-153 FPS locally, and produces no WER or AMD reset.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
2026-07-18 21:35:16 +02:00

36 lines
1.3 KiB
C#

namespace AcDream.Core.World;
/// <summary>
/// Allocates stable, collision-free local ids for dat-authored
/// <c>LandBlockInfo.Objects</c> and building shells.
/// </summary>
/// <remarks>
/// The top nibble is fixed at <c>0xC</c>. The remaining 28 bits encode the
/// complete landblock X byte, Y byte, and a 12-bit per-landblock counter:
/// <c>0xCXXYYIII</c>. The former <c>0xC0XXYYII</c> packing had only eight
/// counter bits, so a legitimate dense retail landblock aborted after 255
/// entries and was retried every time it streamed into view.
/// </remarks>
public static class LandblockStaticEntityIdAllocator
{
public const uint MaxCounter = 0xFFFu;
public static uint Base(uint landblockX, uint landblockY) =>
0xC0000000u
| ((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 static entity id namespace.");
}
return Base(landblockX, landblockY) + counter++;
}
public static bool IsInNamespace(uint entityId) =>
(entityId & 0xF0000000u) == 0xC0000000u;
}