Fix crash when using curves inside Anim Graph

https://forum.flaxengine.com/t/bug-report-v1-12-using-curves-in-the-animation-graph-causes-a-crash/2594
This commit is contained in:
2026-05-28 13:30:40 +02:00
parent c36c39df37
commit 6daec81db1
6 changed files with 66 additions and 52 deletions
@@ -61,14 +61,14 @@ void AnimGraphBase::Clear()
StateTransitions.Resize(0);
// Base
GraphType::Clear();
VisjectGraph::Clear();
}
#if USE_EDITOR
void AnimGraphBase::GetReferences(Array<Guid>& output) const
{
GraphType::GetReferences(output);
VisjectGraph::GetReferences(output);
// Collect references from nested graph (assets used in state machines)
for (const auto* subGraph : SubGraphs)
@@ -163,7 +163,7 @@ VisjectExecutor::Value VisualScriptExecutor::eatBox(Node* caller, Box* box)
// Add to the calling stack
VisualScripting::StackFrame frame = *stack.Stack;
frame.Node = parentNode;
frame.Node = (VisualScriptGraphNode*)parentNode;
frame.Box = box;
frame.PreviousFrame = stack.Stack;
stack.Stack = &frame;
@@ -189,7 +189,7 @@ VisjectExecutor::Value VisualScriptExecutor::eatBox(Node* caller, Box* box)
VisjectExecutor::Graph* VisualScriptExecutor::GetCurrentGraph() const
{
auto& stack = ThreadStacks.Get();
return stack.Stack && stack.Stack->Script ? &stack.Stack->Script->Graph : nullptr;
return stack.Stack && stack.Stack->Script ? (Graph*)&stack.Stack->Script->Graph : nullptr;
}
void VisualScriptExecutor::ProcessGroupParameters(Box* box, Node* node, Value& value)
@@ -432,7 +432,7 @@ void VisualScriptExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value&
// Call Impulse or Pure Method
if (boxBase->ID == 0 || (bool)node->Values[3])
{
auto& cache = node->Data.InvokeMethod;
auto& cache = ((VisualScriptGraphNode*)node)->Data.InvokeMethod;
if (!cache.Method)
{
// Load method signature
@@ -667,7 +667,7 @@ void VisualScriptExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value&
// Get Field
case 7:
{
auto& cache = node->Data.GetSetField;
auto& cache = ((VisualScriptGraphNode*)node)->Data.GetSetField;
if (!cache.Field)
{
const auto typeName = (StringView)node->Values[0];
@@ -753,7 +753,7 @@ void VisualScriptExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value&
// Get Field
case 8:
{
auto& cache = node->Data.GetSetField;
auto& cache = ((VisualScriptGraphNode*)node)->Data.GetSetField;
if (!cache.Field)
{
const auto typeName = (StringView)node->Values[0];
+38 -2
View File
@@ -12,11 +12,47 @@
#define VISUAL_SCRIPT_GRAPH_MAX_CALL_STACK 250
#define VISUAL_SCRIPT_DEBUGGING USE_EDITOR
#define VisualScriptGraphNode VisjectGraphNode<>
class VisualScripting;
class VisualScriptingBinaryModule;
/// <summary>
/// Visual Script graph node.
/// </summary>
class VisualScriptGraphNode : public VisjectGraphNode<>
{
public:
struct InvokeMethodData
{
void* Method;
BinaryModule* Module;
int32 ParamsCount;
uint32 OutParamsMask;
bool IsStatic;
};
struct GetSetFieldData
{
void* Field;
BinaryModule* Module;
bool IsStatic;
};
/// <summary>
/// Custom cached data per node type. Compact to use as small amount of memory as possible.
/// </summary>
struct AdditionalData
{
union
{
InvokeMethodData InvokeMethod;
GetSetFieldData GetSetField;
};
};
// The custom per-node data. Used to cache data for faster usage at runtime.
AdditionalData Data;
};
/// <summary>
/// The Visual Script graph data.
/// </summary>
+9
View File
@@ -167,6 +167,15 @@ public:
// Base
return Base::onNodeLoaded(n);
}
void Clear() override
{
FloatCurves.Clear();
Float2Curves.Clear();
Float3Curves.Clear();
Float4Curves.Clear();
Base::Clear();
}
};
/// <summary>
+1 -1
View File
@@ -952,7 +952,7 @@ void VisjectExecutor::ProcessGroupTools(Box* box, Node* node, Value& value)
#define SAMPLE_CURVE(id, curves, type, graphType) \
case id: \
{ \
const auto& curve = GetCurrentGraph()->curves[node->Data.Curve.CurveIndex]; \
const auto& curve = GetCurrentGraph()->curves[node->CurveIndex]; \
const float time = (float)tryGetValue(node->GetBox(0), Value::Zero); \
value.Type = VariantType(VariantType::graphType); \
curve.Evaluate(*(type*)value.AsData, time, false); \
+11 -42
View File
@@ -42,42 +42,6 @@ public:
template<class BoxType = VisjectGraphBox>
class VisjectGraphNode : public GraphNode<BoxType>
{
public:
struct CurveData
{
/// <summary>
/// The curve index.
/// </summary>
int32 CurveIndex;
};
/// <summary>
/// Custom cached data per node type. Compact to use as small amount of memory as possible.
/// </summary>
struct AdditionalData
{
union
{
CurveData Curve;
struct
{
void* Method;
BinaryModule* Module;
int32 ParamsCount;
uint32 OutParamsMask;
bool IsStatic;
} InvokeMethod;
struct
{
void* Field;
BinaryModule* Module;
bool IsStatic;
} GetSetField;
};
};
public:
VisjectGraphNode()
: GraphNode<BoxType>()
@@ -85,10 +49,7 @@ public:
}
public:
/// <summary>
/// The custom data (depends on node type). Used to cache data for faster usage at runtime.
/// </summary>
AdditionalData Data;
int32 CurveIndex = MAX_uint16;
/// <summary>
/// The asset references. Linked resources such as Animation assets are referenced in graph data as ID. We need to keep valid refs to them at runtime to keep data in memory.
@@ -148,7 +109,7 @@ public:
#define SETUP_CURVE(id, curves, access) \
case id: \
{ \
n->Data.Curve.CurveIndex = curves.Count(); \
n->CurveIndex = curves.Count(); \
auto& curve = curves.AddOne(); \
const int32 keyframesCount = n->Values[0].AsInt; \
auto& keyframes = curve.GetKeyframes(); \
@@ -177,9 +138,17 @@ public:
}
}
// Base
return Base::onNodeLoaded(n);
}
void Clear() override
{
FloatCurves.Clear();
Float2Curves.Clear();
Float3Curves.Clear();
Float4Curves.Clear();
Base::Clear();
}
};
/// <summary>