Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
ConditionEvaluator.cpp
Go to the documentation of this file.
1/**
2 * @file ConditionEvaluator.cpp
3 * @brief Implements structured Condition evaluation for Branch/While nodes.
4 * @author Olympe Engine
5 * @date 2026-03-15
6 *
7 * @details
8 * C++14 compliant — no std::optional, structured bindings, std::filesystem.
9 */
10
11#include "ConditionEvaluator.h"
12#include "../system/system_utils.h"
13
14#include <sstream>
15#include <cstring> // std::sscanf
16#include <cmath> // std::fabs
17
18namespace Olympe {
19
20// ============================================================================
21// EvaluateAll
22// ============================================================================
23
25 const std::vector<Condition>& conditions,
27 const std::unordered_map<std::string, TaskValue>& dataPinCache,
28 int32_t nodeID)
29{
30 // Empty list -> implicit true (no conditions = always pass)
31 if (conditions.empty())
32 return true;
33
34 for (size_t i = 0; i < conditions.size(); ++i)
35 {
36 if (!EvaluateCondition(conditions[i], localBB, dataPinCache, nodeID))
37 return false;
38 }
39 return true;
40}
41
42// ============================================================================
43// EvaluateCondition
44// ============================================================================
45
47 const Condition& cond,
49 const std::unordered_map<std::string, TaskValue>& dataPinCache,
50 int32_t nodeID)
51{
54
55 if (!GetConditionValue(cond.leftMode, cond.leftPin, cond.leftVariable,
56 cond.leftConstValue, localBB, dataPinCache, nodeID, leftVal))
57 {
58 return false;
59 }
60
61 if (!GetConditionValue(cond.rightMode, cond.rightPin, cond.rightVariable,
62 cond.rightConstValue, localBB, dataPinCache, nodeID, rightVal))
63 {
64 return false;
65 }
66
67 if (cond.operatorStr.empty())
68 {
69 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
70 << ": operator is empty — defaulting to false\n";
71 return false;
72 }
73
74 return CompareValues(leftVal, rightVal, cond.operatorStr, nodeID);
75}
76
77// ============================================================================
78// GetConditionValue
79// ============================================================================
80
82 const std::string& mode,
83 const std::string& pin,
84 const std::string& variable,
85 const TaskValue& constValue,
87 const std::unordered_map<std::string, TaskValue>& dataPinCache,
88 int32_t nodeID,
90{
91 if (mode == "Const")
92 {
93 // Const is always available — return the literal value directly.
94 outValue = constValue;
95 return true;
96 }
97 else if (mode == "Variable")
98 {
99 if (variable.empty())
100 {
101 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
102 << ": WARNING — Variable mode with empty variable name\n";
103 return false;
104 }
105 if (!localBB.HasVariable(variable))
106 {
107 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
108 << ": WARNING — Variable '" << variable
109 << "' not found in blackboard\n";
110 return false;
111 }
112 try
113 {
114 outValue = localBB.GetValue(variable);
115 return true;
116 }
117 catch (...)
118 {
119 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
120 << ": WARNING — Failed to read variable '" << variable << "'\n";
121 return false;
122 }
123 }
124 else if (mode == "Pin")
125 {
126 if (pin.empty())
127 {
128 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
129 << ": WARNING — Pin mode with empty pin reference\n";
130 return false;
131 }
132
133 // Parse "Node#42.Out" -> cacheKey = "42:Out"
134 int32_t srcNodeID = -1;
135 std::string pinName;
136 if (!ParsePinRef(pin, srcNodeID, pinName))
137 {
138 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
139 << ": WARNING — Could not parse pin reference '" << pin << "'\n";
140 return false;
141 }
142
143 std::ostringstream key;
144 key << srcNodeID << ":" << pinName;
145 const std::string cacheKey = key.str();
146
147 auto it = dataPinCache.find(cacheKey);
148 if (it == dataPinCache.end())
149 {
150 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
151 << ": WARNING — Pin '" << pin
152 << "' (cache key '" << cacheKey << "') not found in DataPinCache\n";
153 return false;
154 }
155
156 outValue = it->second;
157 return true;
158 }
159
160 // Unknown mode
161 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
162 << ": WARNING — Unknown condition mode '" << mode << "'\n";
163 return false;
164}
165
166// ============================================================================
167// CompareValues
168// ============================================================================
169
171 const TaskValue& right,
172 const std::string& op,
173 int32_t nodeID)
174{
175 const VariableType lt = left.GetType();
176 const VariableType rt = right.GetType();
177
178 // --- Bool comparisons ---
180 {
181 const bool lv = left.AsBool();
182 const bool rv = right.AsBool();
183 if (op == "==") return lv == rv;
184 if (op == "!=") return lv != rv;
185 if (op == "<") return (!lv && rv); // false < true
186 if (op == ">") return (lv && !rv);
187 if (op == "<=") return lv <= rv;
188 if (op == ">=") return lv >= rv;
189 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
190 << ": WARNING — Unknown operator '" << op << "' for Bool\n";
191 return false;
192 }
193
194 // --- String comparisons ---
196 {
197 const std::string lv = left.AsString();
198 const std::string rv = right.AsString();
199 if (op == "==") return lv == rv;
200 if (op == "!=") return lv != rv;
201 if (op == "<") return lv < rv;
202 if (op == ">") return lv > rv;
203 if (op == "<=") return lv <= rv;
204 if (op == ">=") return lv >= rv;
205 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
206 << ": WARNING — Unknown operator '" << op << "' for String\n";
207 return false;
208 }
209
210 // --- Float comparisons (or Int promoted to Float) ---
213
215 {
216 float lv = 0.0f;
217 float rv = 0.0f;
218
219 if (lt == VariableType::Int) lv = static_cast<float>(left.AsInt());
220 else lv = left.AsFloat();
221
222 if (rt == VariableType::Int) rv = static_cast<float>(right.AsInt());
223 else rv = right.AsFloat();
224
225 if (op == "==") return std::fabs(lv - rv) < 1e-6f;
226 if (op == "!=") return std::fabs(lv - rv) >= 1e-6f;
227 if (op == "<") return lv < rv;
228 if (op == ">") return lv > rv;
229 if (op == "<=") return lv <= rv;
230 if (op == ">=") return lv >= rv;
231 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
232 << ": WARNING — Unknown operator '" << op << "' for numeric\n";
233 return false;
234 }
235
236 // --- Vector comparisons (== and != only) ---
238 {
239 const ::Vector lv = left.AsVector();
240 const ::Vector rv = right.AsVector();
241 const bool eq = (std::fabs(lv.x - rv.x) < 1e-6f &&
242 std::fabs(lv.y - rv.y) < 1e-6f &&
243 std::fabs(lv.z - rv.z) < 1e-6f);
244 if (op == "==") return eq;
245 if (op == "!=") return !eq;
246 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
247 << ": WARNING — Operator '" << op
248 << "' not supported for Vector (only == and != are valid)\n";
249 return false;
250 }
251
252 // --- Type mismatch ---
253 SYSTEM_LOG << "[ConditionEvaluator] Node #" << nodeID
254 << ": WARNING — Type mismatch: cannot compare type "
255 << static_cast<int>(lt) << " with type "
256 << static_cast<int>(rt)
257 << " using operator '" << op << "' (E042)\n";
258 return false;
259}
260
261// ============================================================================
262// ParsePinRef (private helper)
263// ============================================================================
264
267 std::string& outPinName)
268{
269 // Expected format: "Node#<id>.<pinName>"
270 // e.g. "Node#42.Out"
271
272 const std::string prefix = "Node#";
273 if (pinRef.size() <= prefix.size())
274 return false;
275
276 if (pinRef.substr(0, prefix.size()) != prefix)
277 return false;
278
279 const std::string rest = pinRef.substr(prefix.size()); // "42.Out"
280 const size_t dotPos = rest.find('.');
281 if (dotPos == std::string::npos || dotPos == 0 || dotPos + 1 >= rest.size())
282 return false;
283
284 const std::string idStr = rest.substr(0, dotPos);
285 const std::string pinName = rest.substr(dotPos + 1);
286
287 // Convert id string to integer
288 int id = 0;
289 for (size_t i = 0; i < idStr.size(); ++i)
290 {
291 if (idStr[i] < '0' || idStr[i] > '9')
292 return false;
293 id = id * 10 + (idStr[i] - '0');
294 }
295
296 outNodeID = static_cast<int32_t>(id);
297 outPinName = pinName;
298 return true;
299}
300
301} // namespace Olympe
Evaluates structured Condition expressions for Branch/While nodes.
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
static bool GetConditionValue(const std::string &mode, const std::string &pin, const std::string &variable, const TaskValue &constValue, const LocalBlackboard &localBB, const std::unordered_map< std::string, TaskValue > &dataPinCache, int32_t nodeID, TaskValue &outValue)
Resolves the TaskValue for one side of a condition.
static bool EvaluateAll(const std::vector< Condition > &conditions, const LocalBlackboard &localBB, const std::unordered_map< std::string, TaskValue > &dataPinCache, int32_t nodeID)
Evaluates all conditions (implicit AND) on a Branch/While node.
static bool EvaluateCondition(const Condition &cond, const LocalBlackboard &localBB, const std::unordered_map< std::string, TaskValue > &dataPinCache, int32_t nodeID)
Evaluates a single Condition.
static bool CompareValues(const TaskValue &left, const TaskValue &right, const std::string &op, int32_t nodeID)
Compares two TaskValues using the given operator.
static bool ParsePinRef(const std::string &pinRef, int32_t &outNodeID, std::string &outPinName)
Parses "Node#42.Out" -> nodeID=42, pinName="Out".
Simple map-based blackboard for task graph runtime state.
C++14-compliant type-safe value container for task parameters.
int AsInt() const
Returns the int value.
::Vector AsVector() const
Returns the Vector value.
float AsFloat() const
Returns the float value.
std::string AsString() const
Returns the string value.
bool AsBool() const
Returns the bool value.
VariableType GetType() const
Returns the VariableType tag of the stored value.
< Provides AssetID and INVALID_ASSET_ID
VariableType
Type tags used by TaskValue to identify stored data.
@ Int
32-bit signed integer
@ Float
Single-precision float.
@ String
std::string
@ Vector
3-component vector (Vector from vector.h)
Describes a single condition expression for Branch/While nodes.
#define SYSTEM_LOG