From f1efc03fb4144b995b74365943e67a5ce1388c38 Mon Sep 17 00:00:00 2001
From: esnya <2088693+esnya@users.noreply.github.com>
Date: Thu, 20 Nov 2025 20:19:38 +0900
Subject: [PATCH 1/3] =?UTF-8?q?refactor(props):=20=F0=9F=94=A7=20update=20?=
=?UTF-8?q?project=20properties=20for=20improved=20configuration?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Directory.Build.props | 24 ++++++++++++
.../ReferenceReplacement.csproj | 37 +++----------------
.../ReferenceReplacementMod.cs | 2 +-
.../ReferenceReplacement.Tests.csproj | 22 -----------
4 files changed, 31 insertions(+), 54 deletions(-)
diff --git a/Directory.Build.props b/Directory.Build.props
index 92915b9..c301b98 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,9 +1,15 @@
+ net10.0
+ enable
+ latest
true
latest-all
enable
true
+ false
+ false
+ false
@@ -16,4 +22,22 @@
$([System.IO.Path]::GetFullPath('$(ResonitePath)'))
+
+
+
+ $([MSBuild]::ValueOrDefault('$(IsTestProject)','false'))
+
+
+
+
+
+ $(ResolvedResonitePath)/FrooxEngine.dll
+
+
+ $(ResolvedResonitePath)/Elements.Core.dll
+
+
+ $(ResolvedResonitePath)/Renderite.Shared.dll
+
+
diff --git a/src/ReferenceReplacement/ReferenceReplacement.csproj b/src/ReferenceReplacement/ReferenceReplacement.csproj
index f574d28..7929511 100644
--- a/src/ReferenceReplacement/ReferenceReplacement.csproj
+++ b/src/ReferenceReplacement/ReferenceReplacement.csproj
@@ -1,22 +1,15 @@
-
- net9.0
- enable
- enable
- 12.0
- false
- false
-
-
-
- false
-
-
$(DefineConstants);USE_RESONITE_HOT_RELOAD_LIB
+
+
+ <_Parameter1>ReferenceReplacement.Tests
+
+
+
$(ResolvedResonitePath)/Libraries/ResoniteModLoader.dll
@@ -26,30 +19,12 @@
$(ResolvedResonitePath)/rml_libs/0Harmony.dll
false
-
- $(ResolvedResonitePath)/FrooxEngine.dll
- false
-
-
- $(ResolvedResonitePath)/Elements.Core.dll
- false
-
-
- $(ResolvedResonitePath)/Renderite.Shared.dll
- false
-
$(ResolvedResonitePath)/rml_libs/ResoniteHotReloadLib.dll
false
-
-
- <_Parameter1>ReferenceReplacement.Tests
-
-
-
diff --git a/src/ReferenceReplacement/ReferenceReplacementMod.cs b/src/ReferenceReplacement/ReferenceReplacementMod.cs
index f4a29bd..03a2694 100644
--- a/src/ReferenceReplacement/ReferenceReplacementMod.cs
+++ b/src/ReferenceReplacement/ReferenceReplacementMod.cs
@@ -15,7 +15,7 @@ namespace ReferenceReplacement;
public class ReferenceReplacementMod : ResoniteMod
{
- public const string VersionTag = "0.1.0";
+ public static readonly string VersionTag = GitVersionInformation.FullSemVer;
private const string HarmonyId = "com.nekometer.esnya.reference-replacement";
private const string CreationMenuCategory = "Editor";
private const string CreationMenuLabel = "Reference Replacement (Mod)";
diff --git a/tests/ReferenceReplacement.Tests/ReferenceReplacement.Tests.csproj b/tests/ReferenceReplacement.Tests/ReferenceReplacement.Tests.csproj
index 0e2cd3b..621fc71 100644
--- a/tests/ReferenceReplacement.Tests/ReferenceReplacement.Tests.csproj
+++ b/tests/ReferenceReplacement.Tests/ReferenceReplacement.Tests.csproj
@@ -1,12 +1,5 @@
-
- net9.0
- enable
- enable
- false
-
-
@@ -20,19 +13,4 @@
-
-
- $(ResolvedResonitePath)/FrooxEngine.dll
- true
-
-
- $(ResolvedResonitePath)/Elements.Core.dll
- true
-
-
- $(ResolvedResonitePath)/Renderite.Shared.dll
- true
-
-
-
From 4f093ceb172c63bacea83897bf9f8d032afd2a3b Mon Sep 17 00:00:00 2001
From: esnya <2088693+esnya@users.noreply.github.com>
Date: Thu, 20 Nov 2025 21:21:12 +0900
Subject: [PATCH 2/3] =?UTF-8?q?feat(logic):=20=E2=9C=A8=20add=20reference?=
=?UTF-8?q?=20traversal=20and=20matching=20functionality?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Logic/ReferenceMatchCollector.cs | 57 +++
.../Logic/ReferenceScanner.cs | 336 ++----------------
.../Logic/ReferenceTraversal.cs | 215 +++++++++++
.../Logic/SyncCollectionTraversal.cs | 102 ++++++
.../Logic/TraversalCursor.cs | 62 ++++
.../Logic/TraversalExceptionFilter.cs | 18 +
.../ReferenceScannerTests.cs | 60 ++++
7 files changed, 536 insertions(+), 314 deletions(-)
create mode 100644 src/ReferenceReplacement/Logic/ReferenceMatchCollector.cs
create mode 100644 src/ReferenceReplacement/Logic/ReferenceTraversal.cs
create mode 100644 src/ReferenceReplacement/Logic/SyncCollectionTraversal.cs
create mode 100644 src/ReferenceReplacement/Logic/TraversalCursor.cs
create mode 100644 src/ReferenceReplacement/Logic/TraversalExceptionFilter.cs
diff --git a/src/ReferenceReplacement/Logic/ReferenceMatchCollector.cs b/src/ReferenceReplacement/Logic/ReferenceMatchCollector.cs
new file mode 100644
index 0000000..31b826f
--- /dev/null
+++ b/src/ReferenceReplacement/Logic/ReferenceMatchCollector.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+
+using FrooxEngine;
+
+namespace ReferenceReplacement.Logic;
+
+internal sealed class ReferenceMatchCollector
+{
+ private readonly IWorldElement _source;
+ private readonly IWorldElement _target;
+ private readonly HashSet _visitedRefs = new();
+ private readonly List _matches = new();
+
+ internal ReferenceMatchCollector(IWorldElement source, IWorldElement target)
+ {
+ _source = source ?? throw new ArgumentNullException(nameof(source));
+ _target = target ?? throw new ArgumentNullException(nameof(target));
+ }
+
+ public int IncompatibleCount { get; private set; }
+ public string? LastHitPath { get; private set; }
+
+ public void TryCapture(ISyncRef candidate, string path)
+ {
+ if (!_visitedRefs.Add(candidate))
+ {
+ return;
+ }
+
+ IWorldElement? current = candidate.Target;
+ if (current == null)
+ {
+ return;
+ }
+
+ if (!ReferenceEquals(current, _source) && current.ReferenceID != _source.ReferenceID)
+ {
+ return;
+ }
+
+ Type? requiredType = candidate.TargetType;
+ if (requiredType != null && !requiredType.IsInstanceOfType(_target))
+ {
+ IncompatibleCount++;
+ return;
+ }
+
+ LastHitPath = path;
+ _matches.Add(new SyncReferenceMatch(candidate, path));
+ }
+
+ public ReferenceScanResult BuildResult(int visitedMembers)
+ {
+ return new ReferenceScanResult(_matches.ToArray(), IncompatibleCount, visitedMembers, LastHitPath);
+ }
+}
diff --git a/src/ReferenceReplacement/Logic/ReferenceScanner.cs b/src/ReferenceReplacement/Logic/ReferenceScanner.cs
index b5ecf10..09dd71f 100644
--- a/src/ReferenceReplacement/Logic/ReferenceScanner.cs
+++ b/src/ReferenceReplacement/Logic/ReferenceScanner.cs
@@ -1,7 +1,5 @@
using System;
-using System.Collections;
using System.Collections.Generic;
-using System.Reflection;
using System.Runtime.CompilerServices;
using FrooxEngine;
@@ -10,327 +8,37 @@ namespace ReferenceReplacement.Logic;
internal static class ReferenceScanner
{
- public static ReferenceScanResult Scan(Slot root, IWorldElement source, IWorldElement target, Slot? excludedSlot = null)
+ public static ReferenceScanResult Scan(
+ Slot root,
+ IWorldElement source,
+ IWorldElement target,
+ Slot? excludedSlot = null,
+ ITraversalExceptionFilter? exceptionFilter = null)
{
ArgumentNullException.ThrowIfNull(root);
- ReferenceScanSession session = new(source, target, excludedSlot);
- session.VisitSlot(root, TraversalPath.FromSlot(root));
- return session.BuildResult();
- }
-
- internal static ReferenceScanResult Scan(HierarchyBlueprint blueprintRoot, IWorldElement source, IWorldElement target)
- {
- ArgumentNullException.ThrowIfNull(blueprintRoot);
+ TraversalCursor cursor = TraversalCursor.FromSlot(root);
+ ReferenceMatchCollector collector = new(source, target);
+ ReferenceTraversal traversal = new(exceptionFilter ?? DefaultTraversalExceptionFilter.Instance, collector);
+ traversal.TraverseSlot(root, cursor, excludedSlot);
- ReferenceScanSession session = new(source, target, excludedSlot: null);
- session.VisitBlueprint(blueprintRoot, new(blueprintRoot.Label));
- return session.BuildResult();
+ return collector.BuildResult(traversal.VisitedMembers);
}
- private sealed class ReferenceScanSession
+ internal static ReferenceScanResult Scan(
+ HierarchyBlueprint blueprintRoot,
+ IWorldElement source,
+ IWorldElement target,
+ ITraversalExceptionFilter? exceptionFilter = null)
{
- private readonly IWorldElement _source;
- private readonly IWorldElement _target;
- private readonly Slot? _excludedSlot;
- private readonly List _matches = new();
- private readonly HashSet _visitedRefs = new();
- private readonly HashSet