perf(vfx): port retail particle visibility degradation

Resolve DAT-authored particle ranges from the hardware GfxObj, apply retail distance and completed-cell visibility gates, and preserve the exact finite/infinite off-view update semantics. This removes dense-world simulation work without shortening terrain, entity, fog, or streaming distance.

Publish doorway-clipped outdoor cells through a focused frame controller, retain effect cell identity for outdoor statics, reject hidden emitters before particle-slot scans, and offer an explicit opt-in Extended particle range.

Release build succeeds and all 5,857 tests pass with five intentional skips. Retail-conformance, architecture, and adversarial review cycles are clean; connected Aerlinthe visual/performance gate pending.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-17 15:27:36 +02:00
parent 82789eea88
commit f1ba147ac5
29 changed files with 1810 additions and 125 deletions

View file

@ -1,6 +1,7 @@
using DatReaderWriter;
using DatReaderWriter.DBObjs;
using DatReaderWriter.Types;
using AcDream.Core.Physics;
namespace AcDream.Core.World;
@ -74,6 +75,7 @@ public static class LandblockLoader
Position = stab.Frame.Origin,
Rotation = stab.Frame.Orientation,
MeshRefs = Array.Empty<MeshRef>(),
EffectCellId = OutdoorCellId(landblockId, stab.Frame.Origin),
};
stabEntity.RefreshAabb(); // A.5 T18: populate cached AABB at construction
result.Add(stabEntity);
@ -90,6 +92,7 @@ public static class LandblockLoader
Position = building.Frame.Origin,
Rotation = building.Frame.Orientation,
MeshRefs = Array.Empty<MeshRef>(),
EffectCellId = OutdoorCellId(landblockId, building.Frame.Origin),
IsBuildingShell = true, // Phase A8: tag at source array boundary
BuildingShellAnchorCellId = FirstBuildingAnchorCellId(building, landblockId),
};
@ -106,6 +109,17 @@ public static class LandblockLoader
return type == GfxObjMask || type == SetupMask;
}
private static uint? OutdoorCellId(uint landblockId, System.Numerics.Vector3 localPosition)
{
if (landblockId == 0)
return null;
return TerrainSurface.ComputeOutdoorCellId(
landblockId,
localPosition.X,
localPosition.Y);
}
private static uint? FirstBuildingAnchorCellId(BuildingInfo building, uint landblockId)
{
if (landblockId == 0)