From 03f08f00c1a9c4a6c9980f189dc45bdc155a671a Mon Sep 17 00:00:00 2001 From: Erik Date: Tue, 2 Jun 2026 09:15:37 +0200 Subject: [PATCH] =?UTF-8?q?fix(core):=20UCG=20Stage=201=20=E2=80=94=20Reso?= =?UTF-8?q?lvePortalPolygon=20all-or-nothing=20(match=20BuildLoadedCell)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- src/AcDream.Core/World/Cells/EnvCell.cs | 14 +++++--- .../World/Cells/EnvCellFromDatTests.cs | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/AcDream.Core/World/Cells/EnvCell.cs b/src/AcDream.Core/World/Cells/EnvCell.cs index f4dc2e0..10a0407 100644 --- a/src/AcDream.Core/World/Cells/EnvCell.cs +++ b/src/AcDream.Core/World/Cells/EnvCell.cs @@ -76,11 +76,15 @@ public sealed class EnvCell : ObjCell private static IReadOnlyList ResolvePortalPolygon(CellStruct cellStruct, ushort polygonId) { - if (!cellStruct.Polygons.TryGetValue(polygonId, out var poly)) return Array.Empty(); - var verts = new List(poly.VertexIds.Count); - foreach (var vid in poly.VertexIds) - if (cellStruct.VertexArray.Vertices.TryGetValue((ushort)vid, out var v)) - verts.Add(new Vector3(v.Origin.X, v.Origin.Y, v.Origin.Z)); + if (!cellStruct.Polygons.TryGetValue(polygonId, out var poly) || poly.VertexIds.Count < 3) + return Array.Empty(); + var verts = new Vector3[poly.VertexIds.Count]; + for (int i = 0; i < poly.VertexIds.Count; i++) + { + if (!cellStruct.VertexArray.Vertices.TryGetValue((ushort)poly.VertexIds[i], out var v)) + return Array.Empty(); // any miss -> empty (matches BuildLoadedCell:5686-5691) + verts[i] = new Vector3(v.Origin.X, v.Origin.Y, v.Origin.Z); + } return verts; } } diff --git a/tests/AcDream.Core.Tests/World/Cells/EnvCellFromDatTests.cs b/tests/AcDream.Core.Tests/World/Cells/EnvCellFromDatTests.cs index b13d5c7..09d6741 100644 --- a/tests/AcDream.Core.Tests/World/Cells/EnvCellFromDatTests.cs +++ b/tests/AcDream.Core.Tests/World/Cells/EnvCellFromDatTests.cs @@ -40,4 +40,36 @@ public class EnvCellFromDatTests Assert.Equal(Vector3.Zero, env.LocalBoundsMax); Assert.Null(env.ContainmentBsp); } + + [Fact] + public void FromDat_PortalPolygonMissingAVertex_YieldsEmptyPolygonLocal() + { + var cellStruct = new CellStruct + { + VertexArray = new VertexArray { Vertices = new Dictionary + { + [0] = new SWVertex { Origin = new Vector3(0, 0, 0) }, + [1] = new SWVertex { Origin = new Vector3(1, 0, 0) }, + // vertex 2 intentionally MISSING + }}, + Polygons = new Dictionary + { + [0] = new Polygon { VertexIds = new List { 0, 1, 2 } }, + }, + }; + var dat = new DatEnvCell + { + Flags = (EnvCellFlags)0, + CellPortals = new List + { + new() { OtherCellId = 0x0105, PolygonId = 0, OtherPortalId = 0, Flags = (PortalFlags)0 }, + }, + VisibleCells = new List(), + }; + + var env = EnvCell.FromDat(0xA9B40104u, dat, cellStruct, Matrix4x4.Identity); + + Assert.Single(env.Portals); + Assert.Empty(env.Portals[0].PolygonLocal); + } }