17#include "../system/system_utils.h"
18#include "../third_party/imgui/imgui.h"
19#include "../TaskSystem/TaskGraphLoader.h"
22#include <unordered_set>
28#define ADD_TRACE(trace_str) \
30 const std::string& _trace_temp = (trace_str); \
31 m_verificationLogs.push_back(_trace_temp); \
32 SYSTEM_LOG << "[SimTrace] " << _trace_temp << "\n"; \
37 SYSTEM_LOG <<
"[VisualScriptEditorPanel] RunVerification() called for graph '"
58 if (
issue.nodeID >= 0)
64 SYSTEM_LOG <<
"[VisualScriptEditorPanel] RunVerification() done: "
72 SYSTEM_LOG <<
"[VisualScriptEditorPanel] RunGraphSimulation() called for graph '"
79 ADD_TRACE(
"[SIMULATION] Graph execution simulation started");
104 ADD_TRACE(
"[ERROR] No entry point or root node found!");
105 SYSTEM_LOG <<
"[VisualScriptEditorPanel] Simulation FAILED: No entry point\n";
136 ADD_TRACE(
"[BRANCH] Entering new execution branch - resetting cycle detection");
161 " has already been visited in this path");
169 if (!
nodePtr->NodeName.empty())
180 ADD_TRACE(
" +- [EVAL] EntryPoint - start of graph");
190 ADD_TRACE(
" +- [RESULT] EntryPoint completed");
205 valTrace <<
" | Value: " <<
it->second.AsString();
214 ADD_TRACE(
" | Outgoing data connections:");
235 " pin '" +
dataConn.TargetPinName +
"'");
254 ADD_TRACE(
" +- [RESULT] Read value from blackboard");
291 std::to_string(
dataConn.SourceNodeID));
305 ADD_TRACE(
" | Setting value in blackboard (simulated)");
315 ADD_TRACE(
" +- [RESULT] Value written to blackboard");
351 leftOp <<
"Variable: " <<
nodePtr->mathOpRef.leftOperand.variableName;
353 leftOp <<
"Const: " <<
nodePtr->mathOpRef.leftOperand.constValue;
359 rightOp <<
"Variable: " <<
nodePtr->mathOpRef.rightOperand.variableName;
361 rightOp <<
"Const: " <<
nodePtr->mathOpRef.rightOperand.constValue;
367 ADD_TRACE(
" | Result: [computed value]");
394 ADD_TRACE(
" +- [RESULT] Math operation executed");
405 bool conditionResult =
true;
406 ADD_TRACE(
" | Condition result: " + std::string(conditionResult ?
"TRUE" :
"FALSE"));
433 if (
conn.SourcePinName ==
"Then" ||
conn.SourcePinName ==
"Out" ||
conn.SourcePinName.empty())
438 else if (
conn.SourcePinName ==
"Else" ||
conn.SourcePinName ==
"OutElse")
461 ADD_TRACE(
" | WARNING: No Then/Else branches found!");
464 std::string
branchPath = !conditionResult ?
"Else" :
"Then";
465 ADD_TRACE(
" +- [RESULT] Branch explored: " +
branchPath +
" (both queued for exploration)");
485 ADD_TRACE(
" | Case selected: (first available)");
489 ADD_TRACE(
" +- [RESULT] Switch case executed");
510 ADD_TRACE(
" +- [RESULT] Delay completed");
519 if (
nodePtr->AtomicTaskID ==
"log_message")
526 const std::string&
msgValue =
msgIt->second.LiteralValue.to_string();
537 if (!
nodePtr->Parameters.empty())
567 ADD_TRACE(
" | (Task execution simulated)");
579 ADD_TRACE(
" +- [RESULT] Task completed");
599 ADD_TRACE(
" | Executing sequence outputs:");
642 if (!
nodePtr->conditions.empty())
647 ADD_TRACE(
" | Condition #" + std::to_string(
ci + 1) +
648 ": " +
cond.leftVariable +
" " +
cond.operatorStr +
" " +
cond.rightVariable);
657 ADD_TRACE(
" | Evaluating condition... TRUE (Loop continues)");
668 if (
conn.SourcePinName ==
"Loop" ||
conn.SourcePinName ==
"OutLoop")
670 else if (
conn.SourcePinName ==
"Completed" ||
conn.SourcePinName ==
"OutCompleted")
682 ADD_TRACE(
" | (Loop condition false - would exit)");
686 ADD_TRACE(
" +- [RESULT] Loop iteration executed");
692 ADD_TRACE(
" +- [EVAL] ForEach loop node");
694 ADD_TRACE(
" | (ForEach iteration parameters pending implementation)");
705 if (
conn.SourcePinName ==
"Loop Body" ||
conn.SourcePinName ==
"OutLoop")
707 else if (
conn.SourcePinName ==
"Completed" ||
conn.SourcePinName ==
"OutCompleted")
713 ADD_TRACE(
" | Iterating list (simulated)");
721 ADD_TRACE(
" | List empty or iterations completed");
725 ADD_TRACE(
" +- [RESULT] ForEach loop executed");
738 auto it =
nodePtr->Parameters.find(
"subgraph_path");
749 if (!
nodePtr->InputParams.empty())
789 "./OlympeBlueprintEditor/Blueprints/",
827 ADD_TRACE(
" | === ENTERING SUBGRAPH ===");
843 if (!
nodePtr->OutputParams.empty())
845 ADD_TRACE(
" | Output Parameter Mapping:");
864 ADD_TRACE(
" | === EXITING SUBGRAPH ===");
886 ADD_TRACE(
" | [ERROR] SubGraph path is empty!");
890 if (!
nodePtr->OutputParams.empty())
892 ADD_TRACE(
" | Output Parameters (return values):");
911 ADD_TRACE(
" +- [RESULT] SubGraph completed");
929 ADD_TRACE(
" +- [RESULT] Node processed");
946 ADD_TRACE(
"[EXIT] -> Next token from stack: Node #" + std::to_string(
nextToken.nodeID) +
951 ADD_TRACE(
"[EXIT] -> Graph complete (all tokens consumed)");
963 ADD_TRACE(
"[WARNING] Maximum steps reached (" + std::to_string(
maxSteps) +
") - possible infinite loop");
967 ADD_TRACE(
"[SUCCESS] Graph execution completed - all branches finished");
979 SYSTEM_LOG <<
"[VisualScriptEditorPanel] Simulation completed: " <<
stepCount <<
" steps\n";
985 ImGui::TextDisabled(
"Graph Verification");
989 ImGui::TextDisabled(
"Click 'Verify' in toolbar to run verification.");
1002 ImGui::TextColored(
ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
1007 ImGui::TextColored(
ImVec4(1.0f, 0.85f, 0.0f, 1.0f),
"OK — warnings present");
1011 ImGui::TextColored(
ImVec4(0.3f, 1.0f, 0.3f, 1.0f),
"OK — no issues");
1024 for (
int s = 0;
s < 3; ++
s)
1033 ImGui::PushID(
static_cast<int>(
i));
1036 ImGui::TextColored(
ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
"[E]");
1038 ImGui::TextColored(
ImVec4(1.0f, 0.85f, 0.0f, 1.0f),
"[W]");
1040 ImGui::TextColored(
ImVec4(0.4f, 0.7f, 1.0f, 1.0f),
"[I]");
1043 ImGui::Text(
"%s: %s",
issue.ruleID.c_str(),
issue.message.c_str());
1045 if (
issue.nodeID >= 0)
1048 std::string
btnLabel =
"Go##go" + std::to_string(
i);
1049 if (ImGui::SmallButton(
btnLabel.c_str()))
1068 ImGui::TextDisabled(
"(Click 'Verify' or 'Run Graph' button to generate output)");
1078 ImGui::TextColored(
ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
1079 "[ERROR] Graph has %d error(s)",
1084 ImGui::TextColored(
ImVec4(1.0f, 0.85f, 0.0f, 1.0f),
1085 "[WARNING] Graph is valid but has warnings");
1089 ImGui::TextColored(
ImVec4(0.3f, 1.0f, 0.3f, 1.0f),
1090 "[OK] Graph is valid - no issues found");
1096 ImGui::BeginChild(
"VerificationLogsChild",
ImVec2(0, 0),
true);
1108 if (
logEntry.find(
"[ERROR]") != std::string::npos)
1110 else if (
logEntry.find(
"[WARN]") != std::string::npos)
1112 else if (
logEntry.find(
"[INFO]") != std::string::npos)
1114 else if (
logEntry.find(
"[SIMULATION]") != std::string::npos)
1116 else if (
logEntry.find(
"[ENTER]") != std::string::npos)
1118 else if (
logEntry.find(
"[EXIT]") != std::string::npos)
1120 else if (
logEntry.find(
"[EVAL]") != std::string::npos)
1122 else if (
logEntry.find(
"[RESULT]") != std::string::npos)
1124 else if (
logEntry.find(
"[CYCLE]") != std::string::npos)
1126 else if (
logEntry.find(
"[WARNING]") != std::string::npos)
1128 else if (
logEntry.find(
"[SUCCESS]") != std::string::npos)
1130 else if (
logEntry.find(
"===") != std::string::npos)
1145 const char*
sevLabels[3] = {
"[ERROR]",
"[WARN]",
"[INFO]" };
1147 ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
1148 ImVec4(1.0f, 0.85f, 0.0f, 1.0f),
1149 ImVec4(0.5f, 0.8f, 1.0f, 1.0f)
1152 for (
int s = 0;
s < 3; ++
s)
1164 std::string message =
issue.message;
1165 if (
issue.nodeID >= 0)
1167 message +=
" (Node: " + std::to_string(
issue.nodeID) +
")";
1176 ImGui::TextDisabled(
"(No logs to display)");
1206 "Node " + std::to_string(
eNode.nodeID) +
" (" +
1207 eNode.def.NodeName +
"): no exec-in connection");
1212 eNode.def.SubGraphPath.empty())
1215 "Node " + std::to_string(
eNode.nodeID) +
1216 " (SubGraph): SubGraphPath is empty");
1223 ImGui::TextDisabled(
"Preset Bank (Global)");
1232 if (ImGui::Button(
"+##addpreset",
ImVec2(25, 0)))
1237 ImGui::TextDisabled(
"New Preset");
1240 ImGui::TextDisabled(
"Total: %zu preset(s)",
presetCount);
1248 ImGui::TextDisabled(
"(no presets - create one to get started)");
1254 ImGui::PushID(
preset.id.c_str());
1262#ifndef OLYMPE_HEADLESS
1277 ImGui::TextColored(
ImVec4(1.0f, 0.843f, 0.0f, 1.0f),
"Condition #%zu",
index);
1279 ImGui::SameLine(0.0f, 12.0f);
1286 ImGui::SameLine(0.0f, 6.0f);
1298 default:
opStr =
"?";
break;
1301 const char*
opNames[] = {
"==",
"!=",
"<",
"<=",
">",
">=" };
1308 for (
int i = 0;
i < 6; ++
i)
1317 ImGui::SetNextItemWidth(50.0f);
1323 ImGui::SameLine(0.0f, 6.0f);
1330 ImGui::SameLine(0.0f, 12.0f);
1352 if (ImGui::Button(
"Dup##dup_preset",
ImVec2(40, 0)))
1368 ImGui::SameLine(0.0f, 4.0f);
1371 if (ImGui::Button(
"X##del_preset",
ImVec2(25, 0)))
1389 ImGui::PopStyleColor(3);
1421 ADD_TRACE(
indent +
"+- [DATA] GetBBValue #" + std::to_string(nodeID));
1422 if (!
nodePtr->NodeName.empty())
1432 if (!
nodePtr->NodeName.empty())
1437 std::string
leftDesc =
"[const/var]";
1470 const std::string&
indent)
1472 if (parameters.empty())
1475 std::ostringstream
ss;
1476 ss <<
"\n" <<
indent <<
"Parameters:";
1478 for (
const auto&
param : parameters)
1491 ss <<
"[Variable: " <<
binding.VariableName <<
"]";
1501 const std::string&
indent,
1557 if (!
nodePtr->NodeName.empty())
1599 leftDesc =
"Variable: " +
nodePtr->mathOpRef.leftOperand.variableName;
1635 std::ostringstream
ss;
1644 ss <<
"GetBBValue | Key: '" <<
node.BBKey <<
"'";
1648 ss <<
"SetBBValue | Key: '" <<
node.BBKey <<
"'";
1652 ss <<
"MathOp | Op: " <<
node.MathOperator;
1656 ss <<
"Branch | Type: Conditional";
1660 ss <<
"Switch | Var: '" <<
node.switchVariable <<
"' | Cases: " <<
node.switchCases.size();
1664 ss <<
"Delay | Duration: " <<
node.DelaySeconds <<
"s";
1669 ss <<
"AtomicTask | TaskID: '" <<
node.AtomicTaskID <<
"'";
1671 if (!
node.Parameters.empty())
1673 auto it =
node.Parameters.begin();
1674 ss <<
" | " <<
it->first <<
": " <<
it->second.LiteralValue.to_string();
1688 ss <<
"SubGraph | Path: '" <<
node.SubGraphPath <<
"'";
1700 ss <<
"Unknown node type";
1710 std::map<std::string, TaskValue>&
blackboard,
1730 tmpl->EntryPointID :
tmpl->RootNodeID;
1756 for (
size_t i = 0;
i <
tmpl->Nodes.size(); ++
i)
1790 for (
size_t i = 0;
i <
tmpl->ExecConnections.size(); ++
i)
1804 for (
size_t i = 0;
i <
tmpl->ExecConnections.size(); ++
i)
1818 for (
size_t i = 0;
i <
tmpl->ExecConnections.size(); ++
i)
1832 for (
size_t i = 0;
i <
tmpl->ExecConnections.size(); ++
i)
1847 std::vector<ExecPinConnection> outputs;
1848 for (
size_t i = 0;
i <
tmpl->ExecConnections.size(); ++
i)
1852 outputs.push_back(
tmpl->ExecConnections[
i]);
1857 for (
int oi =
static_cast<int>(outputs.size()) - 1;
oi >= 0; --
oi)
1867 std::vector<ExecPinConnection> outputs;
1868 for (
size_t i = 0;
i <
tmpl->ExecConnections.size(); ++
i)
1872 outputs.push_back(
tmpl->ExecConnections[
i]);
1877 for (
int oi =
static_cast<int>(outputs.size()) - 1;
oi >= 0; --
oi)
1890 auto it =
nodePtr->Parameters.find(
"subgraph_path");
1913 "./OlympeBlueprintEditor/Blueprints/",
1953 if (!
nodePtr->OutputParams.empty())
1995 for (
size_t i = 0;
i <
tmpl->ExecConnections.size(); ++
i)
2010 for (
size_t i = 0;
i <
tmpl->ExecConnections.size(); ++
i)
ComponentTypeID GetComponentTypeID_Static()
ImNodes-based graph editor for ATS Visual Script graphs (Phase 5).
#define ADD_TRACE(trace_str)
size_t GetPresetCount() const
Returns the total number of presets in the registry.
void DeletePreset(const std::string &id)
Removes a preset from the registry.
void UpdatePreset(const std::string &id, const ConditionPreset &updated)
Replaces the data of an existing preset (id must already exist).
std::string DuplicatePreset(const std::string &id)
Creates an independent copy of an existing preset with a new UUID.
bool Save(const std::string &filepath) const
Saves all presets to a JSON file.
std::vector< ConditionPreset > GetFilteredPresets(const std::string &filter) const
Returns all presets whose name contains the filter substring.
ConditionPreset * GetPreset(const std::string &id)
Returns a mutable pointer to the preset, or nullptr if not found.
static TaskGraphTemplate * LoadFromFile(const std::string &path, std::vector< std::string > &outErrors)
Loads a TaskGraphTemplate from a JSON file on disk.
Immutable, shareable task graph asset.
std::vector< TaskNodeDefinition > Nodes
All graph nodes.
std::vector< ExecPinConnection > ExecConnections
Explicit exec connections (ATS VS only)
std::string Name
Friendly name of this template (e.g. "PatrolBehaviour")
std::vector< BlackboardEntry > Blackboard
Local blackboard declared in this graph.
int32_t RootNodeID
ID of the root node (must exist in Nodes)
int32_t EntryPointID
ID of the EntryPoint node (for VS graphs)
std::vector< DataPinConnection > DataConnections
Explicit data connections (ATS VS only)
std::vector< ConditionPreset > Presets
Presets are now stored in the graph JSON, not in external files.
std::string to_string() const
Converts the stored value to a string representation.
static VSVerificationResult Verify(const TaskGraphTemplate &graph)
Run all verification rules on the given graph.
void TraceUpstreamDataNodes(int32_t sourceNodeID, const std::string &indent, std::unordered_set< int > &visitedDataNodes)
Recursively traces all upstream pure data nodes in the graph.
std::vector< std::string > m_validationErrors
std::unique_ptr< DynamicDataPinManager > m_pinManager
Dynamic pin manager shared across all Branch nodes in this panel.
void RunGraphSimulation()
Simulates runtime execution of the current graph and logs traces.
void RenderPresetItemCompact(const ConditionPreset &preset, size_t index)
Render a single preset item in compact horizontal format with index.
TaskGraphTemplate m_template
The template currently being edited.
void EvaluateDataNode(int32_t nodeID, int depth, const std::string &indent)
Helper to recursively evaluate data nodes (MathOp, GetBBValue, etc.) and trace their execution.
std::string FormatTaskParameters(const std::unordered_map< std::string, ParameterBinding > ¶meters, const std::string &indent)
Format task parameters into a readable string.
bool m_simulationDone
True if simulation has been run.
std::vector< std::string > m_verificationLogs
Verification log messages (populated by RunVerification()) Phase 24.3 — for display in the verificati...
std::string GetNodePropertyString(const TaskNodeDefinition &node)
Gets a comprehensive property string for any node type.
void RenderValidationOverlay()
std::vector< ExecutionToken > m_executionTokenStack
Phase 24.4 — Execution token stack for multi-branch simulation Enables proper handling of Sequence no...
std::vector< std::string > m_validationWarnings
Validation messages (rebuilt each frame)
VSVerificationResult m_verificationResult
Latest verification result (produced by RunVerification())
void RunVerification()
Runs VSGraphVerifier on the current graph and stores the result.
void RenderVerificationPanel()
Renders the verification results panel (Phase 21-B).
int m_focusNodeID
Node ID to focus/scroll to on next RenderCanvas() frame (-1 = none)
void RunGraphSimulationRecursive(const TaskGraphTemplate *tmpl, std::map< std::string, TaskValue > &blackboard, std::unordered_set< std::string > &visitedGraphs, int recursionDepth, const std::string &traceIndent)
Internal recursive simulation function with cycle detection.
bool RenderOperandEditor(Operand &operand, const char *labelSuffix)
Render a single operand with dropdown for mode and value editor Returns true if the operand was modif...
bool m_verificationDone
True once RunVerification() has been called at least once for the current graph.
void RenderPresetBankPanel()
Part B: Preset Bank panel (middle of right panel)
std::vector< VSEditorNode > m_editorNodes
Editor nodes (mirrors m_template.Nodes + position/selection state)
int m_selectedNodeID
Currently selected node (for properties panel)
void RenderVerificationLogsPanel()
Public render method for verification logs panel.
ConditionPresetRegistry m_presetRegistry
Global registry of ConditionPreset objects.
std::vector< std::string > m_simulationTraces
Simulation execution traces (populated by RunGraphSimulation()) Phase 24.4 — added to verification lo...
std::unique_ptr< ConditionPresetLibraryPanel > m_libraryPanel
Global condition preset library panel (UI for creating/editing/deleting presets).
< Provides AssetID and INVALID_ASSET_ID
@ LocalVariable
Value is read from the local blackboard at runtime.
@ Literal
Value is embedded directly in the template.
ComparisonOp
The relational operator used in a ConditionPreset.
@ AtomicTask
Leaf node that executes a single atomic task.
@ While
Conditional loop (Loop / Completed exec outputs)
@ SubGraph
Sub-graph call (SubTask)
@ DoOnce
Single-fire execution (reset via Reset pin)
@ Delay
Timer (Completed exec output after N seconds)
@ GetBBValue
Data node – reads a Blackboard key.
@ MathOp
Data node – arithmetic operation (+, -, *, /)
@ SetBBValue
Data node – writes a Blackboard key.
@ ForEach
Iterate over BB list (Loop Body / Completed exec outputs)
@ Switch
Multi-branch on value (N exec outputs)
@ EntryPoint
Unique entry node for VS graphs (replaces Root)
@ Branch
If/Else conditional (Then / Else exec outputs)
@ VSSequence
Execute N outputs in order ("VS" prefix avoids collision with BT Sequence=1)
constexpr int32_t NODE_INDEX_NONE
Sentinel value for "no node" in node index / ID fields.
Describes a single condition expression for Branch/While nodes.
Explicit connection between an output data pin of a source node and an input data pin of a target nod...
Explicit connection between a named exec-out pin of a source node and the exec-in pin of a target nod...
std::string SourcePinName
e.g. "Then", "Else", "Loop", "Completed"
Represents a single execution point in graph simulation (Phase 24).
int32_t nodeID
Current node to execute.
@ Variable
References a blackboard variable by name.
@ Const
Literal constant value.
@ Pin
External data-input pin on the owning node.
Describes how a single parameter value is supplied to a task node.
TaskValue LiteralValue
Used when Type == Literal.
Full description of a single node in the task graph.
std::vector< VSVerificationIssue > issues