From 1dd20ddd40e2527595f7d5f877ff142030819620 Mon Sep 17 00:00:00 2001 From: Erik Date: Tue, 19 May 2026 11:37:58 +0200 Subject: [PATCH] feat(wb): [indoor-upload] probe for EnvCell mesh requests + completions Instruments WbMeshAdapter at two sites: - IncrementRefCount: on first call for an EnvCell id (low 16 bits >= 0x0100), tag the id in _pendingEnvCellRequests and log [indoor-upload] requested. - Tick: when WB's StagedMeshData drains an ObjectMeshData whose ObjectId matches a pending EnvCell, log [indoor-upload] completed with parts count, EnvCellGeometry vertex count, and upload result. Missing "completed" lines after "requested" identify hypothesis H1 (WB silently returns null from PrepareEnvCellMeshData). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs b/src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs index b57e043..23b2d68 100644 --- a/src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs +++ b/src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using AcDream.Core.Meshing; +using AcDream.Core.Rendering; using Chorizite.OpenGLSDLBackend; using Chorizite.OpenGLSDLBackend.Lib; using DatReaderWriter; @@ -34,6 +35,15 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter private readonly AcSurfaceMetadataTable _metadataTable = new(); private readonly HashSet _metadataPopulated = new(); + /// + /// EnvCell ids we've requested via PrepareMeshDataAsync but not yet + /// seen completion for in Tick(). Used by the [indoor-upload] probe + /// to log requested + completed pairs. Cleared per completion; + /// missing completions after a few seconds indicate WB silently + /// returned null (hypothesis H1 in the design spec). + /// + private readonly HashSet _pendingEnvCellRequests = new(); + /// /// True when this instance was created via ; /// all public methods no-op when uninitialized. @@ -134,6 +144,13 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter // per-part GfxObj ids (0x01XXXXXX). WB's Setup-expansion path is // unused. _ = _meshManager.PrepareMeshDataAsync(id, isSetup: false); + + // [indoor-upload] requested probe — only for EnvCell ids. + if (RenderingDiagnostics.IsEnvCellId(id) && RenderingDiagnostics.ProbeIndoorUploadEnabled) + { + _pendingEnvCellRequests.Add(id); + Console.WriteLine($"[indoor-upload] requested cellId=0x{id:X8}"); + } } } @@ -172,7 +189,26 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter _graphicsDevice!.ProcessGLQueue(); while (_meshManager!.StagedMeshData.TryDequeue(out var meshData)) { - _meshManager.UploadMeshData(meshData); + // [indoor-upload] completed probe — check BEFORE upload so we + // see what WB actually produced (vertex counts, parts) before + // any post-upload mutation. + bool isPendingEnvCell = RenderingDiagnostics.ProbeIndoorUploadEnabled + && _pendingEnvCellRequests.Remove(meshData.ObjectId); + + var renderData = _meshManager.UploadMeshData(meshData); + + if (isPendingEnvCell) + { + int parts = meshData.SetupParts?.Count ?? 0; + bool hasGeom = meshData.EnvCellGeometry is not null; + int cellGeomVerts = meshData.EnvCellGeometry?.Vertices?.Length ?? 0; + bool uploadOk = renderData is not null; + Console.WriteLine( + $"[indoor-upload] completed cellId=0x{meshData.ObjectId:X8} " + + $"isSetup={meshData.IsSetup} parts={parts} " + + $"hasEnvCellGeom={hasGeom} cellGeomVerts={cellGeomVerts} " + + $"uploadOk={uploadOk}"); + } } }