checkpoint: preserve user-gated FW closeout fixes

This commit is contained in:
Erik 2026-08-31 08:27:37 +02:00
parent a2f2eb7d78
commit b8befded8b
22 changed files with 1005 additions and 198 deletions

View file

@ -1,6 +1,7 @@
using System.Numerics;
using System.Runtime.InteropServices;
using AcDream.App.Rendering.Scene;
using AcDream.Core.Physics;
namespace AcDream.App.Rendering.Walk;
@ -54,6 +55,7 @@ namespace AcDream.App.Rendering.Walk;
internal sealed class WalkProductionWorldData : IWalkFrameWorldData
{
private readonly WalkBuildingRegistry _buildings;
private readonly ShadowObjectRegistry _shadows;
private RenderSceneQuery _scene;
private uint _tupleLandblockId;
private int _renderCenterLbX;
@ -77,9 +79,12 @@ internal sealed class WalkProductionWorldData : IWalkFrameWorldData
private RenderProjectionRecord[] _arena = new RenderProjectionRecord[4096];
private int _arenaLength;
internal WalkProductionWorldData(WalkBuildingRegistry buildings)
internal WalkProductionWorldData(
WalkBuildingRegistry buildings,
ShadowObjectRegistry shadows)
{
_buildings = buildings ?? throw new ArgumentNullException(nameof(buildings));
_shadows = shadows ?? throw new ArgumentNullException(nameof(shadows));
}
/// <summary>Rebuilds the frame's outdoor/shell buckets and clears the
@ -136,11 +141,12 @@ internal sealed class WalkProductionWorldData : IWalkFrameWorldData
shells.Add(record);
continue;
}
uint cellId = LandscapeCellId(
record.Transform.Position, _renderCenterLbX, _renderCenterLbY);
if (!_outdoorByCell.TryGetValue(cellId, out List<RenderProjectionRecord>? bucket))
_outdoorByCell[cellId] = bucket = new List<RenderProjectionRecord>();
bucket.Add(record);
BucketOutdoorRecord(
in record,
_shadows.GetOwnerCells(record.Source.LocalEntityId),
_outdoorByCell,
_renderCenterLbX,
_renderCenterLbY);
}
required = _scene.IndexCounts.For(RenderSceneIndex.OutdoorDynamic);
@ -155,18 +161,70 @@ internal sealed class WalkProductionWorldData : IWalkFrameWorldData
for (int i = 0; i < count; i++)
{
ref readonly RenderProjectionRecord record = ref _dynamicSweepScratch[i];
uint cellId = LandscapeCellId(
record.Transform.Position, _renderCenterLbX, _renderCenterLbY);
if (!_outdoorDynamicsByCell.TryGetValue(
cellId,
out List<RenderProjectionRecord>? bucket))
{
_outdoorDynamicsByCell[cellId] = bucket = new List<RenderProjectionRecord>();
}
bucket.Add(record);
BucketOutdoorRecord(
in record,
_shadows.GetOwnerCells(record.Source.LocalEntityId),
_outdoorDynamicsByCell,
_renderCenterLbX,
_renderCenterLbY);
}
}
/// <summary>
/// Installs one outdoor object's render shadow in every outdoor cell of
/// its authoritative physics <c>CELLARRAY</c>. This is retail's
/// <c>CPhysicsObj::add_shadows_to_cells</c> →
/// <c>CPartArray::AddPartsShadow</c> path: a large object straddling a
/// landblock edge must remain reachable when its origin cell leaves the
/// landscape walk. Objects without a collision registration (notably
/// short-lived visual effects) retain the root-position fallback.
/// </summary>
internal static void BucketOutdoorRecord(
in RenderProjectionRecord record,
IReadOnlyList<uint> shadowCells,
Dictionary<uint, List<RenderProjectionRecord>> buckets,
int renderCenterLbX,
int renderCenterLbY)
{
ArgumentNullException.ThrowIfNull(shadowCells);
ArgumentNullException.ThrowIfNull(buckets);
bool added = false;
for (int i = 0; i < shadowCells.Count; i++)
{
uint cellId = shadowCells[i];
uint cellIndex = cellId & 0xFFFFu;
if (cellIndex is < 1u or > 64u)
continue;
AddToBucket(in record, cellId, buckets);
added = true;
}
if (!added)
{
uint cellId = LandscapeCellId(
record.Transform.Position,
renderCenterLbX,
renderCenterLbY);
AddToBucket(in record, cellId, buckets);
}
}
private static void AddToBucket(
in RenderProjectionRecord record,
uint cellId,
Dictionary<uint, List<RenderProjectionRecord>> buckets)
{
if (!buckets.TryGetValue(
cellId,
out List<RenderProjectionRecord>? bucket))
{
buckets[cellId] = bucket = new List<RenderProjectionRecord>();
}
bucket.Add(record);
}
/// <summary>The landscape cell owning a RENDER-ORIGIN-RELATIVE position
/// — retail's 24 m cell grid inside the 192 m landblock, producing the
/// same TRUE <c>(lb &amp; 0xFFFF0000) | (cellX*8 + cellY + 1)</c> encoding