diff --git a/Source/Editor/Surface/Archetypes/Animation.StateMachine.cs b/Source/Editor/Surface/Archetypes/Animation.StateMachine.cs
index d1d8cbea1..598adc22b 100644
--- a/Source/Editor/Surface/Archetypes/Animation.StateMachine.cs
+++ b/Source/Editor/Surface/Archetypes/Animation.StateMachine.cs
@@ -250,6 +250,9 @@ namespace FlaxEditor.Surface.Archetypes
set => Values[1] = value;
}
+ ///
+ public VisjectSurfaceContext ParentContext => Context;
+
///
public void OnContextCreated(VisjectSurfaceContext context)
{
@@ -1311,6 +1314,9 @@ namespace FlaxEditor.Surface.Archetypes
set => Values[1] = value;
}
+ ///
+ public VisjectSurfaceContext ParentContext => Context;
+
///
public void OnContextCreated(VisjectSurfaceContext context)
{
@@ -1682,6 +1688,9 @@ namespace FlaxEditor.Surface.Archetypes
set => RuleGraph = value;
}
+ ///
+ public VisjectSurfaceContext ParentContext => SourceState.Context;
+
///
public void OnContextCreated(VisjectSurfaceContext context)
{
diff --git a/Source/Editor/Surface/ISurfaceContext.cs b/Source/Editor/Surface/ISurfaceContext.cs
index cade0b6f0..8e5f330cb 100644
--- a/Source/Editor/Surface/ISurfaceContext.cs
+++ b/Source/Editor/Surface/ISurfaceContext.cs
@@ -25,6 +25,11 @@ namespace FlaxEditor.Surface
///
byte[] SurfaceData { get; set; }
+ ///
+ /// Gets the context which owns this surface context (null for root).
+ ///
+ VisjectSurfaceContext ParentContext { get; }
+
///
/// Called when Visject Surface context gets created for this surface data source. Can be used to link for some events.
///
diff --git a/Source/Editor/Surface/Undo/ConnectBoxesAction.cs b/Source/Editor/Surface/Undo/ConnectBoxesAction.cs
index 7fa2476cb..72b9242a4 100644
--- a/Source/Editor/Surface/Undo/ConnectBoxesAction.cs
+++ b/Source/Editor/Surface/Undo/ConnectBoxesAction.cs
@@ -33,6 +33,14 @@ namespace FlaxEditor.Surface.Undo
CaptureConnections(iB, out _inputBefore);
CaptureConnections(oB, out _outputBefore);
+
+#if BUILD_DEBUG
+ // Validate handles
+ if (_context.Get(_surface) != iB.ParentNode.Context)
+ throw new System.Exception("Invalid ContextHandle");
+ if (_input.Get(iB.ParentNode.Context) != iB || _output.Get(oB.ParentNode.Context) != oB)
+ throw new System.Exception("Invalid BoxHandle");
+#endif
}
public void End()
diff --git a/Source/Editor/Surface/Undo/ContextHandle.cs b/Source/Editor/Surface/Undo/ContextHandle.cs
index 5206c7f16..c816511cc 100644
--- a/Source/Editor/Surface/Undo/ContextHandle.cs
+++ b/Source/Editor/Surface/Undo/ContextHandle.cs
@@ -1,7 +1,9 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
+using System.Text;
using FlaxEngine;
+using FlaxEngine.Json;
namespace FlaxEditor.Surface.Undo
{
@@ -9,7 +11,7 @@ namespace FlaxEditor.Surface.Undo
/// The helper structure for Surface context handle.
///
[HideInEditor]
- public struct ContextHandle
+ public struct ContextHandle : IEquatable
{
private readonly string[] _path;
@@ -42,6 +44,31 @@ namespace FlaxEditor.Surface.Undo
}
}
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The child context provider.
+ public ContextHandle(ISurfaceContext child)
+ {
+ if (child == null)
+ throw new ArgumentNullException();
+ VisjectSurfaceContext parent = child.ParentContext;
+ VisjectSurfaceContext context = parent;
+ int count = 1;
+ while (parent != null)
+ {
+ count++;
+ parent = parent.Parent;
+ }
+ _path = new string[count];
+ _path[0] = child.SurfaceName;
+ for (int i = 1; i < count; i++)
+ {
+ _path[i] = context.Context.SurfaceName;
+ context = context.Parent;
+ }
+ }
+
///
/// Gets the context.
///
@@ -69,5 +96,46 @@ namespace FlaxEditor.Surface.Undo
return context;
}
+
+ ///
+ public bool Equals(ContextHandle other)
+ {
+ return JsonSerializer.ValueEquals(_path, other._path);
+ }
+
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ContextHandle other && Equals(other);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ int hash = 17;
+ if (_path != null)
+ {
+ unchecked
+ {
+ for (var i = 0; i < _path.Length; i++)
+ {
+ var item = _path[i];
+ hash = hash * 23 + (item != null ? item.GetHashCode() : 0);
+ }
+ }
+ }
+ return hash;
+ }
+
+ ///
+ public override string ToString()
+ {
+ var sb = new StringBuilder();
+ if (_path == null)
+ return string.Empty;
+ for (int i = _path.Length - 1; i >= 0; i--)
+ sb.Append(_path[i]).Append('/');
+ return sb.ToString();
+ }
}
}
diff --git a/Source/Editor/Surface/VisjectSurface.Context.cs b/Source/Editor/Surface/VisjectSurface.Context.cs
index e3547fa52..1d8b97729 100644
--- a/Source/Editor/Surface/VisjectSurface.Context.cs
+++ b/Source/Editor/Surface/VisjectSurface.Context.cs
@@ -2,6 +2,8 @@
using System;
using System.Collections.Generic;
+using FlaxEditor.Surface.Undo;
+using FlaxEngine;
namespace FlaxEditor.Surface
{
@@ -9,7 +11,7 @@ namespace FlaxEditor.Surface
{
private VisjectSurfaceContext _root;
private VisjectSurfaceContext _context;
- private readonly Dictionary _contextCache = new Dictionary();
+ private readonly Dictionary _contextCache = new Dictionary();
///
/// The surface context stack.
@@ -54,11 +56,12 @@ namespace FlaxEditor.Surface
return;
// Get or create context
- if (!_contextCache.TryGetValue(context, out VisjectSurfaceContext surfaceContext))
+ var contextHandle = new ContextHandle(context);
+ if (!_contextCache.TryGetValue(contextHandle, out VisjectSurfaceContext surfaceContext))
{
surfaceContext = CreateContext(_context, context);
_context?.Children.Add(surfaceContext);
- _contextCache.Add(context, surfaceContext);
+ _contextCache.Add(contextHandle, surfaceContext);
context.OnContextCreated(surfaceContext);
@@ -118,7 +121,8 @@ namespace FlaxEditor.Surface
}
// Check if has context in cache
- if (_contextCache.TryGetValue(context, out VisjectSurfaceContext surfaceContext))
+ var contextHandle = new ContextHandle(context);
+ if (_contextCache.TryGetValue(contextHandle, out VisjectSurfaceContext surfaceContext))
{
// Remove from navigation path
while (ContextStack.Contains(surfaceContext))
@@ -126,7 +130,7 @@ namespace FlaxEditor.Surface
// Dispose
surfaceContext.Clear();
- _contextCache.Remove(context);
+ _contextCache.Remove(contextHandle);
}
}
@@ -147,7 +151,8 @@ namespace FlaxEditor.Surface
return;
// Check if already in a path
- if (_contextCache.TryGetValue(context, out VisjectSurfaceContext surfaceContext) && ContextStack.Contains(surfaceContext))
+ var contextHandle = new ContextHandle(context);
+ if (_contextCache.TryGetValue(contextHandle, out VisjectSurfaceContext surfaceContext) && ContextStack.Contains(surfaceContext))
{
// Change stack
do
diff --git a/Source/Editor/Surface/VisjectSurfaceWindow.cs b/Source/Editor/Surface/VisjectSurfaceWindow.cs
index 93b7a685d..0b3bc8130 100644
--- a/Source/Editor/Surface/VisjectSurfaceWindow.cs
+++ b/Source/Editor/Surface/VisjectSurfaceWindow.cs
@@ -899,6 +899,9 @@ namespace FlaxEditor.Surface
///
public abstract byte[] SurfaceData { get; set; }
+ ///
+ public VisjectSurfaceContext ParentContext => null;
+
///
public void OnContextCreated(VisjectSurfaceContext context)
{
diff --git a/Source/Editor/Viewport/Previews/MaterialPreview.cs b/Source/Editor/Viewport/Previews/MaterialPreview.cs
index 1cfd13743..632ec199e 100644
--- a/Source/Editor/Viewport/Previews/MaterialPreview.cs
+++ b/Source/Editor/Viewport/Previews/MaterialPreview.cs
@@ -366,6 +366,9 @@ namespace FlaxEditor.Viewport.Previews
}
}
+ ///
+ public VisjectSurfaceContext ParentContext => null;
+
///
void ISurfaceContext.OnContextCreated(VisjectSurfaceContext context)
{
diff --git a/Source/Editor/Windows/AssetReferencesGraphWindow.cs b/Source/Editor/Windows/AssetReferencesGraphWindow.cs
index 6e7d3d0ef..de5b86f96 100644
--- a/Source/Editor/Windows/AssetReferencesGraphWindow.cs
+++ b/Source/Editor/Windows/AssetReferencesGraphWindow.cs
@@ -408,6 +408,9 @@ namespace FlaxEditor.Windows
///
public byte[] SurfaceData { get; set; }
+ ///
+ public VisjectSurfaceContext ParentContext => null;
+
///
public void OnContextCreated(VisjectSurfaceContext context)
{
diff --git a/Source/Editor/Windows/Assets/VisjectFunctionSurfaceWindow.cs b/Source/Editor/Windows/Assets/VisjectFunctionSurfaceWindow.cs
index 2a75a76bd..7ae6ae8be 100644
--- a/Source/Editor/Windows/Assets/VisjectFunctionSurfaceWindow.cs
+++ b/Source/Editor/Windows/Assets/VisjectFunctionSurfaceWindow.cs
@@ -179,6 +179,9 @@ namespace FlaxEditor.Windows.Assets
///
public abstract byte[] SurfaceData { get; set; }
+ ///
+ public VisjectSurfaceContext ParentContext => null;
+
///
public void OnContextCreated(VisjectSurfaceContext context)
{
diff --git a/Source/Editor/Windows/Assets/VisualScriptWindow.cs b/Source/Editor/Windows/Assets/VisualScriptWindow.cs
index 72a043eaa..6c2ec72b0 100644
--- a/Source/Editor/Windows/Assets/VisualScriptWindow.cs
+++ b/Source/Editor/Windows/Assets/VisualScriptWindow.cs
@@ -1147,6 +1147,9 @@ namespace FlaxEditor.Windows.Assets
}
}
+ ///
+ public VisjectSurfaceContext ParentContext => null;
+
///
public void OnContextCreated(VisjectSurfaceContext context)
{
diff --git a/Source/Editor/Windows/Search/ContentSearchWindow.cs b/Source/Editor/Windows/Search/ContentSearchWindow.cs
index 1545fd80b..5ee3ff11c 100644
--- a/Source/Editor/Windows/Search/ContentSearchWindow.cs
+++ b/Source/Editor/Windows/Search/ContentSearchWindow.cs
@@ -105,6 +105,9 @@ namespace FlaxEngine.Windows.Search
///
public byte[] SurfaceData { get; set; }
+ ///
+ public VisjectSurfaceContext ParentContext => null;
+
///
public void OnContextCreated(VisjectSurfaceContext context)
{