Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
DataPinEvaluator_inline.h
Go to the documentation of this file.
1/**
2 * @file DataPinEvaluator_inline.h
3 * @brief Inline implementation of DataPinEvaluator.
4 * @author Olympe Engine
5 * @date 2026-03-20
6 */
7
8#pragma once
9
10#include "TaskGraphTemplate.h"
11#include "LocalBlackboard.h"
12#include "../ECS/Components/TaskRunnerComponent.h"
13#include "../BlueprintEditor/MathOpOperand.h"
14#include "../system/system_utils.h"
15
16namespace Olympe {
17
18// ============================================================================
19// Helper inline functions
20// ============================================================================
21
23{
24 VariableType type = val.GetType();
25
26 if (type == VariableType::Float)
27 {
28 return val.AsFloat();
29 }
30 else if (type == VariableType::Int)
31 {
32 return static_cast<float>(val.AsInt());
33 }
34 else if (type == VariableType::Bool)
35 {
36 return val.AsBool() ? 1.0f : 0.0f;
37 }
38 else
39 {
40 throw std::runtime_error("Cannot convert TaskValue type to float for math operation");
41 }
42}
43
45 const std::string& op,
46 float left,
47 float right)
48{
49 float result = 0.0f;
50
51 if (op == "+")
52 {
53 result = left + right;
54 }
55 else if (op == "-")
56 {
57 result = left - right;
58 }
59 else if (op == "*")
60 {
61 result = left * right;
62 }
63 else if (op == "/")
64 {
65 if (std::fabs(right) < std::numeric_limits<float>::epsilon())
66 {
67 throw std::runtime_error("Division by zero in MathOp");
68 }
69 result = left / right;
70 }
71 else if (op == "%")
72 {
73 if (std::fabs(right) < std::numeric_limits<float>::epsilon())
74 {
75 throw std::runtime_error("Modulo by zero in MathOp");
76 }
77 result = std::fmod(left, right);
78 }
79 else if (op == "^")
80 {
81 result = std::pow(left, right);
82 }
83 else
84 {
85 throw std::runtime_error("Unknown math operator: " + op);
86 }
87
88 return TaskValue(result);
89}
90
91// Forward declaration for recursion
92inline DataPinEvaluationResult DataPinEvaluator_EvaluateRecursive(
93 int32_t nodeID,
94 const std::string& pinName,
95 const TaskGraphTemplate& tmpl,
96 TaskRunnerComponent& runner,
97 LocalBlackboard& localBB,
98 std::unordered_set<int32_t>& visitedNodes,
100
101// ============================================================================
102// Main public API
103// ============================================================================
104
106 int32_t nodeID,
107 const TaskGraphTemplate& tmpl,
110{
111 const TaskNodeDefinition* node = tmpl.GetNode(nodeID);
112 if (node == nullptr)
113 {
114 return false;
115 }
116
117 // Iterate through all data connections targeting this node
118 for (size_t i = 0; i < tmpl.DataConnections.size(); ++i)
119 {
120 const DataPinConnection& conn = tmpl.DataConnections[i];
121 if (conn.TargetNodeID != nodeID)
122 {
123 continue;
124 }
125
126 // Evaluate the source node's output pin
127 std::unordered_set<int32_t> visitedNodes;
129 conn.SourceNodeID,
130 conn.SourcePinName,
131 tmpl,
132 runner,
133 localBB,
135 0);
136
138 {
139 SYSTEM_LOG << "[DataPinEvaluator] Failed to evaluate pin: "
140 << conn.SourceNodeID << ":" << conn.SourcePinName
141 << " -> " << nodeID << ":" << conn.TargetPinName
142 << " (Status: " << static_cast<int>(result.Status) << ")\n";
143 return false;
144 }
145
146 // Cache the result for the target input pin
147 std::ostringstream dstKey;
148 dstKey << nodeID << ":" << conn.TargetPinName;
149 runner.DataPinCache[dstKey.str()] = result.Value;
150 }
151
152 return true;
153}
154
155// ============================================================================
156// Recursive evaluation implementation
157// ============================================================================
158
160 int32_t nodeID,
161 const std::string& pinName,
162 const TaskGraphTemplate& tmpl,
165 std::unordered_set<int32_t>& visitedNodes,
167{
168 // Check recursion depth limit
170 {
173 result.ErrorMessage = "Maximum recursion depth exceeded in data pin network";
174 return result;
175 }
176
177 // Check visited nodes for cycle detection
178 if (visitedNodes.find(nodeID) != visitedNodes.end())
179 {
182 result.ErrorMessage = "Circular dependency detected in data pin network";
183 return result;
184 }
185
186 // Mark node as visited
187 visitedNodes.insert(nodeID);
188
189 const TaskNodeDefinition* node = tmpl.GetNode(nodeID);
190 if (node == nullptr)
191 {
194 result.ErrorMessage = "Node ID not found in template";
195 visitedNodes.erase(nodeID);
196 return result;
197 }
198
199 // Check cache first
200 std::ostringstream cacheKey;
201 cacheKey << nodeID << ":" << pinName;
202 const std::string cacheKeyStr = cacheKey.str();
203
204 auto cacheIt = runner.DataPinCache.find(cacheKeyStr);
205 if (cacheIt != runner.DataPinCache.end())
206 {
209 result.Value = cacheIt->second;
210 visitedNodes.erase(nodeID);
211 return result;
212 }
213
214 // Dispatch to node-specific handler
216
217 switch (node->Type)
218 {
220 {
221 if (node->BBKey.empty())
222 {
224 result.ErrorMessage = "GetBBValue node missing BBKey";
225 }
226 else
227 {
228 try
229 {
230 result.Value = localBB.GetValueScoped(node->BBKey);
232 }
233 catch (const std::exception& e)
234 {
236 result.ErrorMessage = std::string("Failed to read blackboard value: ") + e.what();
237 }
238 }
239 break;
240 }
241
243 {
244 if (node->MathOperator.empty())
245 {
247 result.ErrorMessage = "MathOp node missing MathOperator";
248 }
249 else
250 {
251 try
252 {
253 const MathOpRef& mathOpRef = node->mathOpRef;
254 TaskValue leftOperand;
255 TaskValue rightOperand;
256
257 // Resolve left operand
259 {
260 try {
261 float constVal = std::stof(mathOpRef.leftOperand.constValue);
262 leftOperand = TaskValue(constVal);
263 } catch (...) {
264 leftOperand = TaskValue(0.0f);
265 }
266 }
267 else if (mathOpRef.leftOperand.mode == MathOpOperand::Mode::Pin)
268 {
269 bool found = false;
270 for (size_t i = 0; i < tmpl.DataConnections.size(); ++i)
271 {
272 const DataPinConnection& conn = tmpl.DataConnections[i];
273 if (conn.TargetNodeID == nodeID && conn.TargetPinName == "A")
274 {
275 // Create a local copy of visitedNodes for left operand evaluation
276 std::unordered_set<int32_t> visitedNodesLeft = visitedNodes;
278 conn.SourceNodeID,
279 conn.SourcePinName,
280 tmpl,
281 runner,
282 localBB,
284 recursionDepth + 1);
285
287 {
288 result = srcResult;
289 result.ErrorMessage = "Failed to evaluate left operand: " + srcResult.ErrorMessage;
290 visitedNodes.erase(nodeID);
291 return result;
292 }
293 leftOperand = srcResult.Value;
294 found = true;
295 break;
296 }
297 }
298 if (!found)
299 {
301 result.ErrorMessage = "No data connection found for MathOp left operand (Pin mode)";
302 visitedNodes.erase(nodeID);
303 return result;
304 }
305 }
306 else if (mathOpRef.leftOperand.mode == MathOpOperand::Mode::Variable)
307 {
308 leftOperand = localBB.GetValueScoped(mathOpRef.leftOperand.variableName);
309 }
310
311 // Resolve right operand
313 {
314 try {
315 float constVal = std::stof(mathOpRef.rightOperand.constValue);
316 rightOperand = TaskValue(constVal);
317 } catch (...) {
318 rightOperand = TaskValue(0.0f);
319 }
320 }
321 else if (mathOpRef.rightOperand.mode == MathOpOperand::Mode::Pin)
322 {
323 bool found = false;
324 for (size_t i = 0; i < tmpl.DataConnections.size(); ++i)
325 {
326 const DataPinConnection& conn = tmpl.DataConnections[i];
327 if (conn.TargetNodeID == nodeID && conn.TargetPinName == "B")
328 {
329 // Create a local copy of visitedNodes for right operand evaluation
330 std::unordered_set<int32_t> visitedNodesRight = visitedNodes;
332 conn.SourceNodeID,
333 conn.SourcePinName,
334 tmpl,
335 runner,
336 localBB,
338 recursionDepth + 1);
339
341 {
342 result = srcResult;
343 result.ErrorMessage = "Failed to evaluate right operand: " + srcResult.ErrorMessage;
344 visitedNodes.erase(nodeID);
345 return result;
346 }
347 rightOperand = srcResult.Value;
348 found = true;
349 break;
350 }
351 }
352 if (!found)
353 {
355 result.ErrorMessage = "No data connection found for MathOp right operand (Pin mode)";
356 visitedNodes.erase(nodeID);
357 return result;
358 }
359 }
360 else if (mathOpRef.rightOperand.mode == MathOpOperand::Mode::Variable)
361 {
362 rightOperand = localBB.GetValueScoped(mathOpRef.rightOperand.variableName);
363 }
364
365 // Compute result
366 float leftVal = DataPinEvaluator_TaskValueToFloat(leftOperand);
367 float rightVal = DataPinEvaluator_TaskValueToFloat(rightOperand);
368 result.Value = DataPinEvaluator_ComputeMath(node->MathOperator, leftVal, rightVal);
370 }
371 catch (const std::exception& e)
372 {
374 result.ErrorMessage = std::string("Math operation failed: ") + e.what();
375 }
376 }
377 break;
378 }
379
380 default:
382 result.ErrorMessage = "Node type does not support data pin evaluation";
383 break;
384 }
385
386 // Cache the result if successful
388 {
389 runner.DataPinCache[cacheKeyStr] = result.Value;
390 }
391
392 visitedNodes.erase(nodeID);
393 return result;
394}
395
396} // namespace Olympe
397
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
Runtime key-value store for task graph variables.
Immutable asset structure shared by all task graph runners.
static constexpr int32_t MAX_RECURSION_DEPTH
Maximum recursion depth to prevent stack overflow.
static bool EvaluateNodeInputPins(int32_t nodeID, const TaskGraphTemplate &tmpl, TaskRunnerComponent &runner, LocalBlackboard &localBB)
Evaluate all input data pins for a given node before execution.
Simple map-based blackboard for task graph runtime state.
Immutable, shareable task graph asset.
C++14-compliant type-safe value container for task parameters.
< Provides AssetID and INVALID_ASSET_ID
@ Success
Evaluation completed successfully.
@ InvalidNode
Node ID not found in template.
@ EvaluationError
Runtime error during evaluation (e.g., type mismatch)
@ CycleDetected
Circular dependency detected in data pin network.
VariableType
Type tags used by TaskValue to identify stored data.
@ Int
32-bit signed integer
@ Float
Single-precision float.
float DataPinEvaluator_TaskValueToFloat(const TaskValue &val)
TaskValue DataPinEvaluator_ComputeMath(const std::string &op, float left, float right)
@ GetBBValue
Data node – reads a Blackboard key.
@ MathOp
Data node – arithmetic operation (+, -, *, /)
DataPinEvaluationResult DataPinEvaluator_EvaluateRecursive(int32_t nodeID, const std::string &pinName, const TaskGraphTemplate &tmpl, TaskRunnerComponent &runner, LocalBlackboard &localBB, std::unordered_set< int32_t > &visitedNodes, int32_t recursionDepth)
Explicit connection between an output data pin of a source node and an input data pin of a target nod...
Result of a single data pin evaluation attempt.
@ Variable
References a blackboard variable by name.
@ Const
Literal constant value.
@ Pin
External data-input pin on the owning node.
std::string variableName
Blackboard key (mode == Variable), e.g. "mMoveSpeed".
std::string constValue
Literal string (mode == Const), e.g. "5.0".
Mode mode
Active mode.
Complete reference for a MathOp node: left operand, operator, right operand.
MathOpOperand leftOperand
Left-hand side operand (A)
MathOpOperand rightOperand
Right-hand side operand (B)
Full description of a single node in the task graph.
Per-entity runtime state for task graph execution.
#define SYSTEM_LOG