feat(rendering): port retail building degrade walk

Add exact retail building degrade selection, shared FPS/degrade ownership, complete-body gating, selected-shell submission, ordinary ladder mesh residency, frame-scoped retry rearm, Config controls, installed-DAT census, and lifecycle/allocation proofs.

Reviews: OpenAI retail pass 3 PASS; OpenAI production pass 5 PASS. Gates: Release 0W/0E; focused 285/285; hermetic 16811/16811; InstalledDat 469 pass, 10 documented fail, 1 documented skip; both manifests 30/30.
This commit is contained in:
Erik 2026-09-04 22:29:13 +02:00
parent d0f45f6a99
commit c673f767e9
41 changed files with 1829 additions and 167 deletions

View file

@ -1,14 +1,96 @@
using AcDream.App.Streaming;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Wb;
using AcDream.App.Rendering.Walk;
using AcDream.Core.World;
using DatReaderWriter.DBObjs;
using System.Collections.Immutable;
using System.Numerics;
namespace AcDream.App.Tests.Streaming;
public sealed class StreamingControllerReadinessTests
{
[Fact]
public void NearPublication_OwnsWalkLadderAsOrdinaryReadinessAndReleasesOnRetirement()
{
const uint landblockId = 0x1236FFFFu;
const ulong ladderId = 0x01001234ul;
var meshes = new ReadinessMeshAdapter();
var state = new GpuWorldState(new LandblockSpawnAdapter(meshes));
var outbox = new Queue<LandblockStreamResult>();
var building = new WalkBuilding
{
PositionCellId = 0x12360001u,
DegradeLevels =
[
new WalkBuildingDegradeLevel((uint)ladderId, 1u, 0f, 10f, 20f, null),
],
};
var envCells = new EnvCellLandblockBuild(
landblockId,
Array.Empty<LoadedCell>(),
Array.Empty<EnvCellShellPlacement>(),
[new WalkBuildingFactory.Entry(building, Matrix4x4.Identity, Matrix4x4.Identity)]);
var build = new LandblockBuild(
new LoadedLandblock(landblockId, new LandBlock(), Array.Empty<WorldEntity>()),
envCells);
outbox.Enqueue(new LandblockStreamResult.Loaded(
landblockId,
LandblockStreamTier.Near,
build,
new AcDream.Core.Terrain.LandblockMeshData([], [])));
var controller = new StreamingController(
enqueueLoad: (_, _) => { },
enqueueUnload: _ => { },
drainCompletions: maximum =>
{
var drained = new List<LandblockStreamResult>();
while (drained.Count < maximum && outbox.TryDequeue(out var result))
drained.Add(result);
return drained;
},
applyTerrain: (_, _) => { },
state: state,
nearRadius: 0,
farRadius: 0);
for (int frame = 0; frame < 32 && !meshes.ReferenceCounts.ContainsKey(ladderId); frame++)
controller.Tick(0x12, 0x36);
Assert.Equal(1, meshes.ReferenceCounts[ladderId]);
Assert.False(controller.IsRenderNeighborhoodResident(landblockId, 0, 0));
meshes.ReadyIds.Add(ladderId);
Assert.True(controller.IsRenderNeighborhoodResident(landblockId, 0, 0));
state.RemoveEntitiesFromLandblock(landblockId);
Assert.Empty(meshes.ReferenceCounts);
GpuLandblockSpatialPublication revisit = state.CommitEntitiesToExistingLandblockSpatial(
landblockId,
Array.Empty<WorldEntity>(),
additionalRenderIds: null,
additionalOrdinaryRenderIds: envCells.WalkBuildingMeshDependencies);
state.ActivateLandblockPresentation(revisit);
Assert.Equal(1, meshes.ReferenceCounts[ladderId]);
state.RemoveLandblock(landblockId);
Assert.Empty(meshes.ReferenceCounts);
GpuLandblockSpatialPublication resetPublication =
state.CommitLandblockSpatial(
build.Landblock,
additionalRenderIds: null,
tier: LandblockStreamTier.Near,
additionalOrdinaryRenderIds:
envCells.WalkBuildingMeshDependencies);
state.ActivateLandblockPresentation(resetPublication);
Assert.Equal(1, meshes.ReferenceCounts[ladderId]);
GpuWorldRecenterRetirement reset = state.DetachAllForOriginRecenter();
Assert.Equal(landblockId, Assert.Single(reset.Landblocks).LandblockId);
state.ReleaseLandblockMeshReferences(landblockId);
Assert.Empty(meshes.ReferenceCounts);
}
[Fact]
public void RenderNeighborhoodResident_RequiresEveryPublishedLandblockInRing()
{