refactor(pipeline): MP1a cleanup - narrow public surface, csproj parity, move residue
Coordinator-directed final cleanup before the user gate; none behavioral: 1. MeshExtractor public surface narrowed to the cross-assembly entry points App actually calls (PrepareMeshData, PrepareCellStructMeshData, CollectParts, ComputeBounds); PrepareSetupMeshData, CollectEmittersFromScript, PrepareGfxObjMeshData, PrepareEnvCellMeshData, PrepareCellStructEdgeLineData back to private (internal dispatch, only reached via PrepareMeshData). 2. sideStagedSink constructor parameter is now REQUIRED (no default; type stays nullable for a conscious null): a bake tool that forgot the sink would silently lose particle-preload meshes. 3. AcDream.Content.csproj gains TreatWarningsAsErrors + LangVersion latest (parity with AcDream.Core.csproj). Surfaced zero warnings. 4. Dead usings removed from ObjectMeshManager.cs (BCnEncoder.*, SixLabors.*) — the inline decode moved out in Task 4. 5. Doc fixes: ObjectMeshData.cs cross-assembly <see cref> -> plain text (Content can't resolve App types); IDatReaderWriter.cs stale Phase O-T7 'both in this namespace' sentence rewritten. 6. Stale test doc comments updated to MeshExtractor.PrepareGfxObjMeshData (StipplingSurfaceEquivalenceTests, Issue119UpNullGfxObjDumpTests) — comments only, no code/assertion changes. dotnet build green (0 warnings in Content under warnings-as-errors); full test suite 4059 passed / 0 failed / 4 skipped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
932f904e00
commit
b0758d772b
7 changed files with 27 additions and 24 deletions
|
|
@ -19,11 +19,6 @@ using AcDream.Content;
|
||||||
using AcDream.Core.Rendering.Wb;
|
using AcDream.Core.Rendering.Wb;
|
||||||
using PixelFormat = Silk.NET.OpenGL.PixelFormat;
|
using PixelFormat = Silk.NET.OpenGL.PixelFormat;
|
||||||
using BoundingBox = Chorizite.Core.Lib.BoundingBox;
|
using BoundingBox = Chorizite.Core.Lib.BoundingBox;
|
||||||
using BCnEncoder.Decoder;
|
|
||||||
using BCnEncoder.Shared;
|
|
||||||
using BCnEncoder.ImageSharp;
|
|
||||||
using SixLabors.ImageSharp;
|
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
|
|
||||||
namespace AcDream.App.Rendering.Wb {
|
namespace AcDream.App.Rendering.Wb {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,14 @@ using System.Collections.ObjectModel;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
// Phase O-T7: verbatim copy of WorldBuilder.Shared.Services.IDatReaderWriter +
|
// Phase O-T7: verbatim copy of WorldBuilder.Shared.Services.IDatReaderWriter +
|
||||||
// IDatDatabase into the AcDream.App.Rendering.Wb namespace so the
|
// IDatDatabase, taken into our tree so the WorldBuilder.Shared project
|
||||||
// WorldBuilder.Shared project reference can be dropped.
|
// reference could be dropped.
|
||||||
// The only consumer of IDatReaderWriter in acdream is DatCollectionAdapter +
|
|
||||||
// ObjectMeshManager, both already in this namespace.
|
|
||||||
//
|
//
|
||||||
// MP1a (2026-07-05, Task 4): moved to AcDream.Content, namespace only —
|
// MP1a (2026-07-05, Task 4): moved to AcDream.Content, namespace only —
|
||||||
// MeshExtractor's constructor takes IDatReaderWriter and must be GL-free.
|
// MeshExtractor's constructor takes IDatReaderWriter and must be GL-free.
|
||||||
|
// Consumers: MeshExtractor (this assembly) reads through it;
|
||||||
// DatCollectionAdapter (the concrete DatCollection-backed implementation)
|
// DatCollectionAdapter (the concrete DatCollection-backed implementation)
|
||||||
// stays in AcDream.App; it now implements this Content-namespaced interface.
|
// and ObjectMeshManager live in AcDream.App and implement/hold it from there.
|
||||||
|
|
||||||
namespace AcDream.Content;
|
namespace AcDream.Content;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,10 +49,14 @@ public sealed class MeshExtractor {
|
||||||
/// The MP1b bake tool passes its own collector. The sink must be
|
/// The MP1b bake tool passes its own collector. The sink must be
|
||||||
/// thread-safe: one MeshExtractor is shared by up to MaxParallelLoads (4)
|
/// thread-safe: one MeshExtractor is shared by up to MaxParallelLoads (4)
|
||||||
/// decode workers.
|
/// decode workers.
|
||||||
|
/// The constructor argument is REQUIRED (no default): a bake tool that
|
||||||
|
/// forgot the sink would silently lose particle-preload meshes; requiring
|
||||||
|
/// the argument forces the decision. The type stays nullable so a caller
|
||||||
|
/// can consciously pass null when preloads are irrelevant.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Action<ObjectMeshData>? _sideStagedSink;
|
private readonly Action<ObjectMeshData>? _sideStagedSink;
|
||||||
|
|
||||||
public MeshExtractor(IDatReaderWriter dats, ILogger logger, Action<ObjectMeshData>? sideStagedSink = null) {
|
public MeshExtractor(IDatReaderWriter dats, ILogger logger, Action<ObjectMeshData>? sideStagedSink) {
|
||||||
_dats = dats;
|
_dats = dats;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_sideStagedSink = sideStagedSink;
|
_sideStagedSink = sideStagedSink;
|
||||||
|
|
@ -120,7 +124,7 @@ public sealed class MeshExtractor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectMeshData? PrepareSetupMeshData(ulong id, Setup setup, CancellationToken ct) {
|
private ObjectMeshData? PrepareSetupMeshData(ulong id, Setup setup, CancellationToken ct) {
|
||||||
var parts = new List<(ulong GfxObjId, Matrix4x4 Transform)>();
|
var parts = new List<(ulong GfxObjId, Matrix4x4 Transform)>();
|
||||||
var min = new Vector3(float.MaxValue);
|
var min = new Vector3(float.MaxValue);
|
||||||
var max = new Vector3(float.MinValue);
|
var max = new Vector3(float.MinValue);
|
||||||
|
|
@ -146,7 +150,7 @@ public sealed class MeshExtractor {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CollectEmittersFromScript(uint scriptId, List<StagedEmitter> emitters, CancellationToken ct) {
|
private void CollectEmittersFromScript(uint scriptId, List<StagedEmitter> emitters, CancellationToken ct) {
|
||||||
if (_dats.Portal.TryGet<PhysicsScript>(scriptId, out var script)) {
|
if (_dats.Portal.TryGet<PhysicsScript>(scriptId, out var script)) {
|
||||||
foreach (var hook in script.ScriptData) {
|
foreach (var hook in script.ScriptData) {
|
||||||
if (hook.Hook.HookType == AnimationHookType.CreateParticle && hook.Hook is CreateParticleHook particleHook) {
|
if (hook.Hook.HookType == AnimationHookType.CreateParticle && hook.Hook is CreateParticleHook particleHook) {
|
||||||
|
|
@ -295,7 +299,7 @@ public sealed class MeshExtractor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectMeshData? PrepareGfxObjMeshData(ulong id, GfxObj gfxObj, Vector3 scale, CancellationToken ct) {
|
private ObjectMeshData? PrepareGfxObjMeshData(ulong id, GfxObj gfxObj, Vector3 scale, CancellationToken ct) {
|
||||||
var vertices = new List<VertexPositionNormalTexture>();
|
var vertices = new List<VertexPositionNormalTexture>();
|
||||||
var UVLookup = new Dictionary<(ushort vertId, ushort uvIdx, bool isNeg), ushort>();
|
var UVLookup = new Dictionary<(ushort vertId, ushort uvIdx, bool isNeg), ushort>();
|
||||||
var batchesByFormat = new Dictionary<(int Width, int Height, TextureFormat Format), List<TextureBatchData>>();
|
var batchesByFormat = new Dictionary<(int Width, int Height, TextureFormat Format), List<TextureBatchData>>();
|
||||||
|
|
@ -562,7 +566,7 @@ public sealed class MeshExtractor {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectMeshData? PrepareEnvCellMeshData(ulong id, EnvCell envCell, CancellationToken ct) {
|
private ObjectMeshData? PrepareEnvCellMeshData(ulong id, EnvCell envCell, CancellationToken ct) {
|
||||||
var parts = new List<(ulong GfxObjId, Matrix4x4 Transform)>();
|
var parts = new List<(ulong GfxObjId, Matrix4x4 Transform)>();
|
||||||
var min = new Vector3(float.MaxValue);
|
var min = new Vector3(float.MaxValue);
|
||||||
var max = new Vector3(float.MinValue);
|
var max = new Vector3(float.MinValue);
|
||||||
|
|
@ -1069,7 +1073,7 @@ public sealed class MeshExtractor {
|
||||||
return (min, max);
|
return (min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectMeshData? PrepareCellStructEdgeLineData(ulong id, Dictionary<uint, CellStruct> cellStructs, Matrix4x4 transform, CancellationToken ct) {
|
private ObjectMeshData? PrepareCellStructEdgeLineData(ulong id, Dictionary<uint, CellStruct> cellStructs, Matrix4x4 transform, CancellationToken ct) {
|
||||||
var cellStructList = cellStructs.ToList();
|
var cellStructList = cellStructs.ToList();
|
||||||
if (cellStructList.Count == 0) {
|
if (cellStructList.Count == 0) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -48,15 +48,16 @@ public class ObjectMeshData {
|
||||||
public List<MeshBatchData> Batches { get; set; } = new();
|
public List<MeshBatchData> Batches { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// #125 (2026-06-12): GL upload-retry counter. A failed
|
/// #125 (2026-06-12): GL upload-retry counter. A failed upload through
|
||||||
/// <see cref="ObjectMeshManager.UploadMeshData"/> (returns null from its
|
/// the App-side upload path (it returns null from its
|
||||||
/// catch) used to be dropped permanently — the staged item was consumed,
|
/// catch) used to be dropped permanently — the staged item was consumed,
|
||||||
/// no render data was produced, and the prepared data lingered in the CPU
|
/// no render data was produced, and the prepared data lingered in the CPU
|
||||||
/// cache where <c>PrepareMeshDataAsync</c>'s cache-hit short-circuit
|
/// cache where <c>PrepareMeshDataAsync</c>'s cache-hit short-circuit
|
||||||
/// returned it without ever re-staging it for upload (session-sticky
|
/// returned it without ever re-staging it for upload (session-sticky
|
||||||
/// invisible mesh, one [wb-error] line). The drain loop now re-stages a
|
/// invisible mesh, one [wb-error] line). The drain loop now re-stages a
|
||||||
/// failed upload for the NEXT frame up to <see cref="ObjectMeshManager.
|
/// failed upload for the NEXT frame up to the App-side upload retry
|
||||||
/// MaxUploadRetries"/> times. The counter lives on the mesh-data object so
|
/// limit (<c>MaxUploadRetries</c>). The counter lives on the mesh-data
|
||||||
|
/// object so
|
||||||
/// it resets to 0 naturally whenever the id is re-prepared (fresh object),
|
/// it resets to 0 naturally whenever the id is re-prepared (fresh object),
|
||||||
/// and bounds a deterministic GL failure to a few loud lines instead of a
|
/// and bounds a deterministic GL failure to a few loud lines instead of a
|
||||||
/// silent permanent drop OR an unbounded per-frame retry storm. Retail
|
/// silent permanent drop OR an unbounded per-frame retry storm. Retail
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,11 @@ namespace AcDream.Core.Tests.Conformance;
|
||||||
/// invisible)` at startup (t5-gate-launch.log:33-34); the old tower shows
|
/// invisible)` at startup (t5-gate-launch.log:33-34); the old tower shows
|
||||||
/// missing stair parts (visible in retail — user axiom). UploadGfxObjMeshData
|
/// missing stair parts (visible in retail — user axiom). UploadGfxObjMeshData
|
||||||
/// returns null only when the PREPARE phase produced ZERO vertices
|
/// returns null only when the PREPARE phase produced ZERO vertices
|
||||||
/// (ObjectMeshManager.cs:1780), so the upload is innocent — some extraction
|
/// (ObjectMeshManager.UploadGfxObjMeshData's empty-vertices guard), so the
|
||||||
|
/// upload is innocent — some extraction
|
||||||
/// gate dropped every polygon. This dump prints the raw dat facts per polygon
|
/// gate dropped every polygon. This dump prints the raw dat facts per polygon
|
||||||
/// and replicates PrepareGfxObjMeshData's gates (ObjectMeshManager.cs:1040-1058)
|
/// and replicates MeshExtractor.PrepareGfxObjMeshData's gates (moved from
|
||||||
|
/// ObjectMeshManager in MP1a)
|
||||||
/// so the zeroing gate reads directly off the output.
|
/// so the zeroing gate reads directly off the output.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class Issue119UpNullGfxObjDumpTests
|
public sealed class Issue119UpNullGfxObjDumpTests
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ namespace AcDream.Core.Tests.Conformance;
|
||||||
/// (0x2) and BASE1_CLIPMAP (0x4) are skipped (D3DPolyRender inner draw,
|
/// (0x2) and BASE1_CLIPMAP (0x4) are skipped (D3DPolyRender inner draw,
|
||||||
/// Ghidra 0x0059d4a0; default on @0x00820e30). acdream suppresses them at
|
/// Ghidra 0x0059d4a0; default on @0x00820e30). acdream suppresses them at
|
||||||
/// BUILD time via Stippling.NoPos in all four extraction paths
|
/// BUILD time via Stippling.NoPos in all four extraction paths
|
||||||
/// (ObjectMeshManager.PrepareGfxObjMeshData:1046 + PrepareCellStructMeshData
|
/// (MeshExtractor.PrepareGfxObjMeshData + PrepareCellStructMeshData
|
||||||
/// :1394, CellMesh.Build:44, GfxObjMesh.Build:71).
|
/// [moved from ObjectMeshManager in MP1a], CellMesh.Build:44, GfxObjMesh.Build:71).
|
||||||
///
|
///
|
||||||
/// These criteria are equivalent ONLY if NoPos ⇔ untextured-surface holds on
|
/// These criteria are equivalent ONLY if NoPos ⇔ untextured-surface holds on
|
||||||
/// the content. This sweep pins both directions across the populated
|
/// the content. This sweep pins both directions across the populated
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue