feat(vfx): port retail effect scheduling and delivery
This commit is contained in:
parent
363e046112
commit
96ddfdf175
28 changed files with 2473 additions and 691 deletions
|
|
@ -37,8 +37,8 @@ public static class InteriorEntityIdAllocator
|
|||
{
|
||||
/// <summary>Per-landblock counter budget (12 bits). A landblock hydrating
|
||||
/// more interior entities than this would alias into the next Y-slot —
|
||||
/// exactly the #190 bug, just at a higher threshold. Callers should log
|
||||
/// loudly (never silently wrap) if this is ever exceeded.</summary>
|
||||
/// exactly the #190 bug, just at a higher threshold. <see cref="Allocate"/>
|
||||
/// fails before that can happen.</summary>
|
||||
public const uint MaxCounter = 0xFFFu;
|
||||
|
||||
/// <summary>The first id in this landblock's reserved range (counter=0).
|
||||
|
|
@ -46,4 +46,18 @@ public static class InteriorEntityIdAllocator
|
|||
/// within the landblock.</summary>
|
||||
public static uint Base(uint landblockX, uint landblockY)
|
||||
=> 0x40000000u | ((landblockX & 0xFFu) << 20) | ((landblockY & 0xFFu) << 12);
|
||||
|
||||
/// <summary>
|
||||
/// Allocates the next canonical interior-static ID and advances
|
||||
/// <paramref name="counter"/>. The full 12-bit range, including
|
||||
/// <see cref="MaxCounter"/>, is valid; the next request fails rather than
|
||||
/// aliasing the following landblock.
|
||||
/// </summary>
|
||||
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 interior entity id namespace.");
|
||||
return Base(landblockX, landblockY) + counter++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,22 +47,29 @@ public static class LandblockLoader
|
|||
// legacy starting-from-1 monotonic Ids — compatible with their assertions
|
||||
// which check uniqueness within a single landblock.
|
||||
//
|
||||
// Latent: if a landblock has >256 stabs (rare), nextId overflows the
|
||||
// low byte and bleeds into the lbY byte → cross-LB collision. Same
|
||||
// pattern + same limitation as scenery/interior. Document but don't
|
||||
// fix in this commit — out of scope for the Tier 1 cache bug fix.
|
||||
// The low byte reserves 0 for the namespace base and 1..255 for
|
||||
// entities. Never wrap into the Y byte: a collision here would corrupt
|
||||
// every renderer/physics/effect table keyed by WorldEntity.Id.
|
||||
uint stabIdBase = landblockId == 0
|
||||
? 0u
|
||||
: 0xC0000000u | ((landblockId >> 24) & 0xFFu) << 16 | ((landblockId >> 16) & 0xFFu) << 8;
|
||||
uint nextId = stabIdBase == 0 ? 1u : stabIdBase + 1u;
|
||||
|
||||
uint AllocateId()
|
||||
{
|
||||
if (stabIdBase != 0 && nextId > stabIdBase + 0xFFu)
|
||||
throw new InvalidDataException(
|
||||
$"Landblock 0x{landblockId:X8} exceeds the 255-entry static stab id namespace.");
|
||||
return nextId++;
|
||||
}
|
||||
|
||||
foreach (var stab in info.Objects)
|
||||
{
|
||||
if (!IsSupported(stab.Id))
|
||||
continue;
|
||||
var stabEntity = new WorldEntity
|
||||
{
|
||||
Id = nextId++,
|
||||
Id = AllocateId(),
|
||||
SourceGfxObjOrSetupId = stab.Id,
|
||||
Position = stab.Frame.Origin,
|
||||
Rotation = stab.Frame.Orientation,
|
||||
|
|
@ -78,7 +85,7 @@ public static class LandblockLoader
|
|||
continue;
|
||||
var buildingEntity = new WorldEntity
|
||||
{
|
||||
Id = nextId++,
|
||||
Id = AllocateId(),
|
||||
SourceGfxObjOrSetupId = building.ModelId,
|
||||
Position = building.Frame.Origin,
|
||||
Rotation = building.Frame.Orientation,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue