Refactor Visual Script debugger apis to use bindings generator

This commit is contained in:
Wojtek Figat
2023-12-16 17:58:18 +01:00
parent c145042f52
commit 64e391df24
6 changed files with 122 additions and 251 deletions

View File

@@ -1343,108 +1343,6 @@ namespace FlaxEditor
public float AutoRebuildNavMeshTimeoutMs;
}
[StructLayout(LayoutKind.Sequential)]
[NativeMarshalling(typeof(VisualScriptLocalMarshaller))]
internal struct VisualScriptLocal
{
public string Value;
public string ValueTypeName;
public uint NodeId;
public int BoxId;
}
[CustomMarshaller(typeof(VisualScriptLocal), MarshalMode.Default, typeof(VisualScriptLocalMarshaller))]
internal static class VisualScriptLocalMarshaller
{
[StructLayout(LayoutKind.Sequential)]
internal struct VisualScriptLocalNative
{
public IntPtr Value;
public IntPtr ValueTypeName;
public uint NodeId;
public int BoxId;
}
internal static VisualScriptLocal ConvertToManaged(VisualScriptLocalNative unmanaged) => ToManaged(unmanaged);
internal static VisualScriptLocalNative ConvertToUnmanaged(VisualScriptLocal managed) => ToNative(managed);
internal static VisualScriptLocal ToManaged(VisualScriptLocalNative managed)
{
return new VisualScriptLocal()
{
Value = ManagedString.ToManaged(managed.Value),
ValueTypeName = ManagedString.ToManaged(managed.ValueTypeName),
NodeId = managed.NodeId,
BoxId = managed.BoxId,
};
}
internal static VisualScriptLocalNative ToNative(VisualScriptLocal managed)
{
return new VisualScriptLocalNative()
{
Value = ManagedString.ToNative(managed.Value),
ValueTypeName = ManagedString.ToNative(managed.ValueTypeName),
NodeId = managed.NodeId,
BoxId = managed.BoxId,
};
}
internal static void Free(VisualScriptLocalNative unmanaged)
{
ManagedString.Free(unmanaged.Value);
ManagedString.Free(unmanaged.ValueTypeName);
}
}
[StructLayout(LayoutKind.Sequential)]
[NativeMarshalling(typeof(VisualScriptStackFrameMarshaller))]
internal struct VisualScriptStackFrame
{
public VisualScript Script;
public uint NodeId;
public int BoxId;
}
[CustomMarshaller(typeof(VisualScriptStackFrame), MarshalMode.Default, typeof(VisualScriptStackFrameMarshaller))]
internal static class VisualScriptStackFrameMarshaller
{
[StructLayout(LayoutKind.Sequential)]
internal struct VisualScriptStackFrameNative
{
public IntPtr Script;
public uint NodeId;
public int BoxId;
}
internal static VisualScriptStackFrame ConvertToManaged(VisualScriptStackFrameNative unmanaged) => ToManaged(unmanaged);
internal static VisualScriptStackFrameNative ConvertToUnmanaged(VisualScriptStackFrame managed) => ToNative(managed);
internal static VisualScriptStackFrame ToManaged(VisualScriptStackFrameNative managed)
{
return new VisualScriptStackFrame()
{
Script = VisualScriptMarshaller.ConvertToManaged(managed.Script),
NodeId = managed.NodeId,
BoxId = managed.BoxId,
};
}
internal static VisualScriptStackFrameNative ToNative(VisualScriptStackFrame managed)
{
return new VisualScriptStackFrameNative()
{
Script = VisualScriptMarshaller.ConvertToUnmanaged(managed.Script),
NodeId = managed.NodeId,
BoxId = managed.BoxId,
};
}
internal static void Free(VisualScriptStackFrameNative unmanaged)
{
}
}
internal void BuildCommand(string arg)
{
if (TryBuildCommand(arg))
@@ -1723,21 +1621,6 @@ namespace FlaxEditor
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_RunVisualScriptBreakpointLoopTick", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetVisualScriptLocals", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "localsCount")]
internal static partial VisualScriptLocal[] Internal_GetVisualScriptLocals(out int localsCount);
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetVisualScriptStackFrames", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "stackFrameCount")]
internal static partial VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames(out int stackFrameCount);
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetVisualScriptPreviousScopeFrame", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
internal static partial VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame();
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_EvaluateVisualScriptLocal", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local);
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
internal static partial void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);

View File

@@ -526,133 +526,6 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
Engine::OnDraw();
}
struct VisualScriptLocalManaged
{
MString* Value;
MString* ValueTypeName;
uint32 NodeId;
int32 BoxId;
};
DEFINE_INTERNAL_CALL(MArray*) EditorInternal_GetVisualScriptLocals(int* localsCount)
{
MArray* result = nullptr;
*localsCount = 0;
const auto stack = VisualScripting::GetThreadStackTop();
if (stack && stack->Scope)
{
const int32 count = stack->Scope->Parameters.Length() + stack->Scope->ReturnedValues.Count();
const MClass* mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptLocal");
ASSERT(mclass);
result = MCore::Array::New(mclass, count);
VisualScriptLocalManaged local;
local.NodeId = MAX_uint32;
if (stack->Scope->Parameters.Length() != 0)
{
auto s = stack;
while (s->PreviousFrame && s->PreviousFrame->Scope == stack->Scope)
s = s->PreviousFrame;
if (s)
local.NodeId = s->Node->ID;
}
VisualScriptLocalManaged* resultPtr = MCore::Array::GetAddress<VisualScriptLocalManaged>(result);
for (int32 i = 0; i < stack->Scope->Parameters.Length(); i++)
{
auto& v = stack->Scope->Parameters[i];
local.BoxId = i + 1;
local.Value = MUtils::ToString(v.ToString());
local.ValueTypeName = MUtils::ToString(v.Type.GetTypeName());
resultPtr[i] = local;
}
for (int32 i = 0; i < stack->Scope->ReturnedValues.Count(); i++)
{
auto& v = stack->Scope->ReturnedValues[i];
local.NodeId = v.NodeId;
local.BoxId = v.BoxId;
local.Value = MUtils::ToString(v.Value.ToString());
local.ValueTypeName = MUtils::ToString(v.Value.Type.GetTypeName());
resultPtr[stack->Scope->Parameters.Length() + i] = local;
}
*localsCount = count;
}
return result;
}
struct VisualScriptStackFrameManaged
{
MObject* Script;
uint32 NodeId;
int32 BoxId;
};
DEFINE_INTERNAL_CALL(MArray*) EditorInternal_GetVisualScriptStackFrames(int* stackFramesCount)
{
MArray* result = nullptr;
*stackFramesCount = 0;
const auto stack = VisualScripting::GetThreadStackTop();
if (stack)
{
int32 count = 0;
auto s = stack;
while (s)
{
s = s->PreviousFrame;
count++;
}
const MClass* mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptStackFrame");
ASSERT(mclass);
result = MCore::Array::New(mclass, count);
VisualScriptStackFrameManaged* resultPtr = MCore::Array::GetAddress<VisualScriptStackFrameManaged>(result);
s = stack;
count = 0;
while (s)
{
VisualScriptStackFrameManaged frame;
frame.Script = s->Script->GetOrCreateManagedInstance();
frame.NodeId = s->Node->ID;
frame.BoxId = s->Box ? s->Box->ID : MAX_uint32;
resultPtr[count] = frame;
s = s->PreviousFrame;
count++;
}
*stackFramesCount = count;
}
return result;
}
DEFINE_INTERNAL_CALL(VisualScriptStackFrameManaged) EditorInternal_GetVisualScriptPreviousScopeFrame()
{
VisualScriptStackFrameManaged frame;
Platform::MemoryClear(&frame, sizeof(frame));
const auto stack = VisualScripting::GetThreadStackTop();
if (stack)
{
auto s = stack;
while (s->PreviousFrame && s->PreviousFrame->Scope == stack->Scope)
s = s->PreviousFrame;
if (s && s->PreviousFrame)
{
s = s->PreviousFrame;
frame.Script = s->Script->GetOrCreateManagedInstance();
frame.NodeId = s->Node->ID;
frame.BoxId = s->Box ? s->Box->ID : MAX_uint32;
}
}
return frame;
}
DEFINE_INTERNAL_CALL(bool) EditorInternal_EvaluateVisualScriptLocal(VisualScript* script, VisualScriptLocalManaged* local)
{
Variant v;
if (VisualScripting::Evaluate(script, VisualScripting::GetThreadStackTop()->Instance, local->NodeId, local->BoxId, v))
{
local->Value = MUtils::ToString(v.ToString());
local->ValueTypeName = MUtils::ToString(v.Type.GetTypeName());
return true;
}
return false;
}
DEFINE_INTERNAL_CALL(void) EditorInternal_DeserializeSceneObject(SceneObject* sceneObject, MString* jsonObj)
{
PROFILE_CPU_NAMED("DeserializeSceneObject");

View File

@@ -489,6 +489,95 @@ void ManagedEditor::RequestStartPlayOnEditMode()
Internal_RequestStartPlayOnEditMode->Invoke(GetManagedInstance(), nullptr, nullptr);
}
Array<ManagedEditor::VisualScriptStackFrame> ManagedEditor::GetVisualScriptStackFrames()
{
Array<VisualScriptStackFrame> result;
const auto stack = VisualScripting::GetThreadStackTop();
auto s = stack;
while (s)
{
VisualScriptStackFrame& frame = result.AddOne();
frame.Script = s->Script;
frame.NodeId = s->Node->ID;
frame.BoxId = s->Box ? s->Box->ID : MAX_uint32;
s = s->PreviousFrame;
}
return result;
}
ManagedEditor::VisualScriptStackFrame ManagedEditor::GetVisualScriptPreviousScopeFrame()
{
VisualScriptStackFrame frame;
Platform::MemoryClear(&frame, sizeof(frame));
const auto stack = VisualScripting::GetThreadStackTop();
if (stack)
{
auto s = stack;
while (s->PreviousFrame && s->PreviousFrame->Scope == stack->Scope)
s = s->PreviousFrame;
if (s && s->PreviousFrame)
{
s = s->PreviousFrame;
frame.Script = s->Script;
frame.NodeId = s->Node->ID;
frame.BoxId = s->Box ? s->Box->ID : MAX_uint32;
}
}
return frame;
}
Array<ManagedEditor::VisualScriptLocal> ManagedEditor::GetVisualScriptLocals()
{
Array<VisualScriptLocal> result;
const auto stack = VisualScripting::GetThreadStackTop();
if (stack && stack->Scope)
{
const int32 count = stack->Scope->Parameters.Length() + stack->Scope->ReturnedValues.Count();
result.Resize(count);
VisualScriptLocal local;
local.NodeId = MAX_uint32;
if (stack->Scope->Parameters.Length() != 0)
{
auto s = stack;
while (s->PreviousFrame && s->PreviousFrame->Scope == stack->Scope)
s = s->PreviousFrame;
if (s)
local.NodeId = s->Node->ID;
}
for (int32 i = 0; i < stack->Scope->Parameters.Length(); i++)
{
auto& v = stack->Scope->Parameters[i];
local.BoxId = i + 1;
local.Value = v.ToString();
local.ValueTypeName = v.Type.GetTypeName();
result[i] = local;
}
for (int32 i = 0; i < stack->Scope->ReturnedValues.Count(); i++)
{
auto& v = stack->Scope->ReturnedValues[i];
local.NodeId = v.NodeId;
local.BoxId = v.BoxId;
local.Value = v.Value.ToString();
local.ValueTypeName = v.Value.Type.GetTypeName();
result[stack->Scope->Parameters.Length() + i] = local;
}
}
return result;
}
bool ManagedEditor::EvaluateVisualScriptLocal(VisualScript* script, VisualScriptLocal& local)
{
Variant v;
const auto stack = VisualScripting::GetThreadStackTop();
if (stack && VisualScripting::Evaluate(script, stack->Instance, local.NodeId, local.BoxId, v))
{
local.Value = v.ToString();
local.ValueTypeName = v.Type.GetTypeName();
return true;
}
return false;
}
void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly)
{
ASSERT(!HasManagedInstance());

View File

@@ -210,6 +210,31 @@ public:
API_FUNCTION() static bool TryRestoreImportOptions(API_PARAM(Ref) AudioTool::Options& options, String assetPath);
#endif
public:
API_STRUCT(Internal, NoDefault) struct VisualScriptStackFrame
{
DECLARE_SCRIPTING_TYPE_MINIMAL(VisualScriptStackFrame);
API_FIELD() class VisualScript* Script;
API_FIELD() uint32 NodeId;
API_FIELD() int32 BoxId;
};
API_STRUCT(Internal, NoDefault) struct VisualScriptLocal
{
DECLARE_SCRIPTING_TYPE_MINIMAL(VisualScriptLocal);
API_FIELD() String Value;
API_FIELD() String ValueTypeName;
API_FIELD() uint32 NodeId;
API_FIELD() int32 BoxId;
};
API_FUNCTION(Internal) static Array<VisualScriptStackFrame> GetVisualScriptStackFrames();
API_FUNCTION(Internal) static VisualScriptStackFrame GetVisualScriptPreviousScopeFrame();
API_FUNCTION(Internal) static Array<VisualScriptLocal> GetVisualScriptLocals();
API_FUNCTION(Internal) static bool EvaluateVisualScriptLocal(VisualScript* script, API_PARAM(Ref) VisualScriptLocal& local);
private:
void OnEditorAssemblyLoaded(MAssembly* assembly);

View File

@@ -123,7 +123,7 @@ namespace FlaxEditor.Surface
BoxId = box.ID,
};
var script = ((Windows.Assets.VisualScriptWindow)box.Surface.Owner).Asset;
if (Editor.Internal_EvaluateVisualScriptLocal(Object.GetUnmanagedPtr(script), ref local))
if (Editor.EvaluateVisualScriptLocal(script, ref local))
{
text = $"{local.Value ?? string.Empty} ({local.ValueTypeName})";
return true;

View File

@@ -797,11 +797,12 @@ namespace FlaxEditor.Windows.Assets
}
// Check if any breakpoint was hit
for (int i = 0; i < Surface.Breakpoints.Count; i++)
var breakpoints = Surface.Breakpoints;
for (int i = 0; i < breakpoints.Count; i++)
{
if (Surface.Breakpoints[i].ID == flowInfo.NodeId)
if (breakpoints[i].ID == flowInfo.NodeId)
{
OnDebugBreakpointHit(ref flowInfo, Surface.Breakpoints[i]);
OnDebugBreakpointHit(ref flowInfo, breakpoints[i]);
break;
}
}
@@ -820,7 +821,7 @@ namespace FlaxEditor.Windows.Assets
var state = (BreakpointHangState)Editor.Instance.Simulation.BreakpointHangTag;
if (state.Locals == null)
{
state.Locals = Editor.Internal_GetVisualScriptLocals(out var _);
state.Locals = Editor.GetVisualScriptLocals();
Editor.Instance.Simulation.BreakpointHangTag = state;
}
return state;
@@ -831,7 +832,7 @@ namespace FlaxEditor.Windows.Assets
var state = (BreakpointHangState)Editor.Instance.Simulation.BreakpointHangTag;
if (state.StackFrames == null)
{
state.StackFrames = Editor.Internal_GetVisualScriptStackFrames(out var _);
state.StackFrames = Editor.GetVisualScriptStackFrames();
Editor.Instance.Simulation.BreakpointHangTag = state;
}
return state;
@@ -976,7 +977,7 @@ namespace FlaxEditor.Windows.Assets
return;
// Break on any of the output connects from the previous scope node
var frame = Editor.Internal_GetVisualScriptPreviousScopeFrame();
var frame = Editor.GetVisualScriptPreviousScopeFrame();
if (frame.Script != null)
{
if (_debugStepOutNodesIds == null)