From 43b68e6430676924f34fdc8d2f389543c4864ab5 Mon Sep 17 00:00:00 2001 From: Aleph Date: Sat, 27 Dec 2025 07:35:08 -0800 Subject: [PATCH 1/8] avoid handle recursion in MeshFace.ToString() MeshFace.ToString() was interpolating {Handle}, which calls FaceHandle.ToString() / PrintMembers(...) and can recurse through half-edge refs. This caused InsufficientExecutionStackException when the inspector or TreeView.ScrollTo(...) formats selected faces, especially with trace logging. Switched ToString() to a stable identifier (HandleIndex) and guard the object name to prevent recursive stringification. --- game/addons/tools/Code/Scene/Mesh/MeshFace.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/game/addons/tools/Code/Scene/Mesh/MeshFace.cs b/game/addons/tools/Code/Scene/Mesh/MeshFace.cs index 616b63686..2aeb313aa 100644 --- a/game/addons/tools/Code/Scene/Mesh/MeshFace.cs +++ b/game/addons/tools/Code/Scene/Mesh/MeshFace.cs @@ -24,7 +24,13 @@ public MeshFace( MeshComponent component, FaceHandle handle ) } public readonly override int GetHashCode() => HashCode.Combine( Component, nameof( MeshFace ), Handle ); - public override readonly string ToString() => IsValid ? $"{Component.GameObject.Name} Face {Handle}" : "Invalid Face"; + public override readonly string ToString() + { + if ( !IsValid ) return "Invalid Face"; + + var objectName = Component.GameObject?.Name ?? ""; + return $"{objectName} Face #{HandleIndex}"; + } [JsonIgnore, Hide] public readonly Vector2 TextureOffset From 04fb4f99f1cb9c7b336ab7567d810bc8c64f7656 Mon Sep 17 00:00:00 2001 From: Aleph Date: Sat, 27 Dec 2025 07:37:18 -0800 Subject: [PATCH 2/8] avoid handle recursion in MeshVertex.ToString() Prevents InsufficientExecutionStackException spam when selecting vertices with trace logging enabled --- game/addons/tools/Code/Scene/Mesh/MeshVertex.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/game/addons/tools/Code/Scene/Mesh/MeshVertex.cs b/game/addons/tools/Code/Scene/Mesh/MeshVertex.cs index acc1af190..10b3d0c36 100644 --- a/game/addons/tools/Code/Scene/Mesh/MeshVertex.cs +++ b/game/addons/tools/Code/Scene/Mesh/MeshVertex.cs @@ -25,5 +25,11 @@ public MeshVertex( MeshComponent component, VertexHandle handle ) } public readonly override int GetHashCode() => HashCode.Combine( Component, nameof( MeshVertex ), Handle ); - public override readonly string ToString() => IsValid ? $"{Component.GameObject.Name} Vertex {Handle}" : "Invalid Vertex"; + public override readonly string ToString() + { + if ( !IsValid ) return "Invalid Vertex"; + + var objectName = Component.GameObject?.Name ?? ""; + return $"{objectName} Vertex #{HandleIndex}"; + } } From 27951d755b86a01d2e162569a9facde8ea7e5e26 Mon Sep 17 00:00:00 2001 From: Aleph Date: Sat, 27 Dec 2025 07:41:02 -0800 Subject: [PATCH 3/8] Fix MeshEdge ToString recursion --- game/addons/tools/Code/Scene/Mesh/MeshEdge.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/game/addons/tools/Code/Scene/Mesh/MeshEdge.cs b/game/addons/tools/Code/Scene/Mesh/MeshEdge.cs index 8de7f19a2..5f8465c4c 100644 --- a/game/addons/tools/Code/Scene/Mesh/MeshEdge.cs +++ b/game/addons/tools/Code/Scene/Mesh/MeshEdge.cs @@ -32,5 +32,11 @@ public readonly PolygonMesh.EdgeSmoothMode EdgeSmoothing } public readonly override int GetHashCode() => HashCode.Combine( Component, nameof( MeshEdge ), Handle ); - public override readonly string ToString() => IsValid ? $"{Component.GameObject.Name} Edge {Handle}" : "Invalid Edge"; + public override readonly string ToString() + { + if ( !IsValid ) return "Invalid Edge"; + + var objectName = Component.GameObject?.Name ?? ""; + return $"{objectName} Edge #{HandleIndex}"; + } } From b899f96b0c8198ff08a3fecbe306710722e64608 Mon Sep 17 00:00:00 2001 From: Aleph Date: Sat, 27 Dec 2025 09:26:03 -0800 Subject: [PATCH 4/8] Revert "avoid handle recursion in MeshFace.ToString()" This reverts commit 43b68e6430676924f34fdc8d2f389543c4864ab5. --- game/addons/tools/Code/Scene/Mesh/MeshFace.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/game/addons/tools/Code/Scene/Mesh/MeshFace.cs b/game/addons/tools/Code/Scene/Mesh/MeshFace.cs index 2aeb313aa..616b63686 100644 --- a/game/addons/tools/Code/Scene/Mesh/MeshFace.cs +++ b/game/addons/tools/Code/Scene/Mesh/MeshFace.cs @@ -24,13 +24,7 @@ public MeshFace( MeshComponent component, FaceHandle handle ) } public readonly override int GetHashCode() => HashCode.Combine( Component, nameof( MeshFace ), Handle ); - public override readonly string ToString() - { - if ( !IsValid ) return "Invalid Face"; - - var objectName = Component.GameObject?.Name ?? ""; - return $"{objectName} Face #{HandleIndex}"; - } + public override readonly string ToString() => IsValid ? $"{Component.GameObject.Name} Face {Handle}" : "Invalid Face"; [JsonIgnore, Hide] public readonly Vector2 TextureOffset From 6b8e3a2620ee69e1f7b0a325adc7f7126acaaaea Mon Sep 17 00:00:00 2001 From: Aleph Date: Sat, 27 Dec 2025 09:29:20 -0800 Subject: [PATCH 5/8] Revert " avoid handle recursion in MeshVertex.ToString()" This reverts commit 04fb4f99f1cb9c7b336ab7567d810bc8c64f7656. --- game/addons/tools/Code/Scene/Mesh/MeshVertex.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/game/addons/tools/Code/Scene/Mesh/MeshVertex.cs b/game/addons/tools/Code/Scene/Mesh/MeshVertex.cs index 10b3d0c36..acc1af190 100644 --- a/game/addons/tools/Code/Scene/Mesh/MeshVertex.cs +++ b/game/addons/tools/Code/Scene/Mesh/MeshVertex.cs @@ -25,11 +25,5 @@ public MeshVertex( MeshComponent component, VertexHandle handle ) } public readonly override int GetHashCode() => HashCode.Combine( Component, nameof( MeshVertex ), Handle ); - public override readonly string ToString() - { - if ( !IsValid ) return "Invalid Vertex"; - - var objectName = Component.GameObject?.Name ?? ""; - return $"{objectName} Vertex #{HandleIndex}"; - } + public override readonly string ToString() => IsValid ? $"{Component.GameObject.Name} Vertex {Handle}" : "Invalid Vertex"; } From d334eb9e21af30f390922538b682d111d9a496b0 Mon Sep 17 00:00:00 2001 From: Aleph Date: Sat, 27 Dec 2025 09:29:41 -0800 Subject: [PATCH 6/8] Revert "Fix MeshEdge ToString recursion" This reverts commit 27951d755b86a01d2e162569a9facde8ea7e5e26. --- game/addons/tools/Code/Scene/Mesh/MeshEdge.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/game/addons/tools/Code/Scene/Mesh/MeshEdge.cs b/game/addons/tools/Code/Scene/Mesh/MeshEdge.cs index 5f8465c4c..8de7f19a2 100644 --- a/game/addons/tools/Code/Scene/Mesh/MeshEdge.cs +++ b/game/addons/tools/Code/Scene/Mesh/MeshEdge.cs @@ -32,11 +32,5 @@ public readonly PolygonMesh.EdgeSmoothMode EdgeSmoothing } public readonly override int GetHashCode() => HashCode.Combine( Component, nameof( MeshEdge ), Handle ); - public override readonly string ToString() - { - if ( !IsValid ) return "Invalid Edge"; - - var objectName = Component.GameObject?.Name ?? ""; - return $"{objectName} Edge #{HandleIndex}"; - } + public override readonly string ToString() => IsValid ? $"{Component.GameObject.Name} Edge {Handle}" : "Invalid Edge"; } From 365eb5a01fda539672c904ee3477c4b21bc3005a Mon Sep 17 00:00:00 2001 From: Aleph Date: Sat, 27 Dec 2025 09:36:33 -0800 Subject: [PATCH 7/8] Add ToString overrides for HalfEdgeMesh handle types I kept ToString() to just the index so it stays a low-level identity string. Higher-level tools can add whatever labeling or context they need --- .../Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/engine/Sandbox.Engine/Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs b/engine/Sandbox.Engine/Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs index 189303439..f41325979 100644 --- a/engine/Sandbox.Engine/Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs +++ b/engine/Sandbox.Engine/Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs @@ -72,6 +72,9 @@ public HalfEdgeHandle Edge get => new( Mesh is null ? -1 : Mesh[this].Edge, Mesh ); set => Mesh?.SetVertexEdge( this, value ); } + + public override string ToString() + => Index >= 0 ? $"{Index}" : "Invalid Vertex"; } public sealed record FaceHandle : IHandle @@ -93,6 +96,9 @@ public HalfEdgeHandle Edge get => new( Mesh is null ? -1 : Mesh[this].Edge, Mesh ); set => Mesh?.SetFaceEdge( this, value ); } + + public override string ToString() + => Index >= 0 ? $"{Index}" : "Invalid Face"; } public sealed record HalfEdgeHandle : IHandle @@ -132,6 +138,9 @@ public FaceHandle Face get => new( Mesh is null ? -1 : Mesh[this].Face, Mesh ); set => Mesh?.SetEdgeFace( this, value ); } + + public override string ToString() + => Index >= 0 ? $"{Index}" : "Invalid Edge"; } internal sealed partial class Mesh From 185de130e220a81536cff76253c5729a8f355762 Mon Sep 17 00:00:00 2001 From: Aleph Date: Sat, 27 Dec 2025 09:54:21 -0800 Subject: [PATCH 8/8] fix formatting --- .../Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/engine/Sandbox.Engine/Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs b/engine/Sandbox.Engine/Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs index f41325979..c64dab0ef 100644 --- a/engine/Sandbox.Engine/Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs +++ b/engine/Sandbox.Engine/Scene/Components/Mesh/HalfEdgeMesh/HalfEdgeMesh.cs @@ -73,8 +73,7 @@ public HalfEdgeHandle Edge set => Mesh?.SetVertexEdge( this, value ); } - public override string ToString() - => Index >= 0 ? $"{Index}" : "Invalid Vertex"; + public override string ToString() => Index >= 0 ? $"{Index}" : "Invalid Vertex"; } public sealed record FaceHandle : IHandle @@ -97,8 +96,7 @@ public HalfEdgeHandle Edge set => Mesh?.SetFaceEdge( this, value ); } - public override string ToString() - => Index >= 0 ? $"{Index}" : "Invalid Face"; + public override string ToString() => Index >= 0 ? $"{Index}" : "Invalid Face"; } public sealed record HalfEdgeHandle : IHandle @@ -139,8 +137,7 @@ public FaceHandle Face set => Mesh?.SetEdgeFace( this, value ); } - public override string ToString() - => Index >= 0 ? $"{Index}" : "Invalid Edge"; + public override string ToString() => Index >= 0 ? $"{Index}" : "Invalid Edge"; } internal sealed partial class Mesh