Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
ConditionPresetEvaluator.cpp
Go to the documentation of this file.
1/**
2 * @file ConditionPresetEvaluator.cpp
3 * @brief Implementation of ConditionPresetEvaluator.
4 * @author Olympe Engine
5 * @date 2026-03-17
6 */
7
9
10#include <cmath>
11#include <string>
12#include <sstream>
13#include "../Editor/ConditionPreset/ConditionPresetRegistry.h"
14
15namespace Olympe {
16
17// ---------------------------------------------------------------------------
18// Public interface
19// ---------------------------------------------------------------------------
20
21/*static*/
25 std::string& outErrorMsg)
26{
27 outErrorMsg.clear();
28
29 float leftVal = 0.0f;
30 float rightVal = 0.0f;
31
33 return false;
34
36 return false;
37
39}
40
41/*static*/
43 const std::vector<NodeConditionRef>& conditions,
46 std::string& outErrorMsg)
47{
48 outErrorMsg.clear();
49
50 // ─────────────────────────────────────────────────────────────────────
51 // Validation
52 // ─────────────────────────────────────────────────────────────────────
53
54 if (conditions.empty())
55 {
56 outErrorMsg = "ConditionPresetEvaluator::EvaluateConditionChain: Empty condition chain.";
57 return false;
58 }
59
60 // ─────────────────────────────────────────────────────────────────────
61 // Evaluate each condition and combine with logical operators
62 // ─────────────────────────────────────────────────────────────────────
63
64 // Start with the first condition (LogicalOp::Start is ignored)
65 bool currentResult = true;
66 bool firstCondition = true;
67
68 for (size_t i = 0; i < conditions.size(); ++i)
69 {
70 const NodeConditionRef& condRef = conditions[i];
71
72 // ─────────────────────────────────────────────────────────────────
73 // Resolve the preset from the registry
74 // ─────────────────────────────────────────────────────────────────
75
76 const ConditionPreset* preset = registry.GetPreset(condRef.presetID);
77
78 if (preset == nullptr)
79 {
80 outErrorMsg = "ConditionPresetEvaluator::EvaluateConditionChain: "
81 "Preset not found in registry: '" + condRef.presetID + "'";
82 return false;
83 }
84
85 // ─────────────────────────────────────────────────────────────────
86 // Evaluate this condition
87 // ─────────────────────────────────────────────────────────────────
88
89 bool conditionResult = Evaluate(*preset, env, outErrorMsg);
90 if (!outErrorMsg.empty())
91 {
92 // Evaluation failed
93 return false;
94 }
95
96 // ─────────────────────────────────────────────────────────────────
97 // Apply logical operator (short-circuit evaluation)
98 // ─────────────────────────────────────────────────────────────────
99
100 if (firstCondition)
101 {
102 // First condition: just use its result directly
103 currentResult = conditionResult;
104 firstCondition = false;
105 }
106 else
107 {
108 // Subsequent conditions: combine with logical operator
109 switch (condRef.logicalOp)
110 {
111 case LogicalOp::And:
112 // AND: short-circuit if current is false
113 currentResult = currentResult && conditionResult;
114 if (!currentResult)
115 {
116 // Short-circuit: remaining conditions don't matter
117 return false;
118 }
119 break;
120
121 case LogicalOp::Or:
122 // OR: short-circuit if current is true
123 currentResult = currentResult || conditionResult;
124 if (currentResult)
125 {
126 // Short-circuit: remaining conditions don't matter
127 return true;
128 }
129 break;
130
131 case LogicalOp::Start:
132 // Shouldn't occur for non-first conditions, but treat as AND
133 currentResult = currentResult && conditionResult;
134 if (!currentResult)
135 {
136 return false;
137 }
138 break;
139
140 default:
141 outErrorMsg = "ConditionPresetEvaluator::EvaluateConditionChain: "
142 "Unknown LogicalOp.";
143 return false;
144 }
145 }
146 }
147
148 return currentResult;
149}
150
151
152// ---------------------------------------------------------------------------
153// Private helpers
154// ---------------------------------------------------------------------------
155
156/*static*/
158 const Operand& operand,
160 std::string& outErrorMsg,
161 float& outValue)
162{
163 switch (operand.mode)
164 {
166 outValue = static_cast<float>(operand.constValue);
167 return true;
168
170 {
171 float v = 0.0f;
172 if (!env.GetBlackboardVariable(operand.stringValue, v))
173 {
174 outErrorMsg = "ConditionPresetEvaluator: Blackboard variable not found: '"
175 + operand.stringValue + "'";
176 return false;
177 }
178 outValue = v;
179 return true;
180 }
181
182 case OperandMode::Pin:
183 {
184 float v = 0.0f;
185 if (!env.GetDynamicPinValue(operand.stringValue, v))
186 {
187 outErrorMsg = "ConditionPresetEvaluator: Dynamic pin value not found for pin: '"
188 + operand.stringValue + "'";
189 return false;
190 }
191 outValue = v;
192 return true;
193 }
194
195 default:
196 outErrorMsg = "ConditionPresetEvaluator: Unknown operand mode.";
197 return false;
198 }
199}
200
201/*static*/
203 float left,
204 ComparisonOp op,
205 float right,
206 std::string& outErrorMsg)
207{
208 switch (op)
209 {
210 case ComparisonOp::Equal: return left == right;
211 case ComparisonOp::NotEqual: return left != right;
212 case ComparisonOp::Less: return left < right;
213 case ComparisonOp::LessEqual: return left <= right;
214 case ComparisonOp::Greater: return left > right;
215 case ComparisonOp::GreaterEqual: return left >= right;
216 default:
217 outErrorMsg = "ConditionPresetEvaluator: Unknown ComparisonOp.";
218 return false;
219 }
220}
221
222} // namespace Olympe
223
Stateless runtime evaluator for ConditionPreset expressions.
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
static bool Evaluate(const ConditionPreset &preset, RuntimeEnvironment &env, std::string &outErrorMsg)
Evaluates a single ConditionPreset and returns the boolean result.
static bool EvaluateOperator(float left, ComparisonOp op, float right, std::string &outErrorMsg)
Applies a ComparisonOp to two float values.
static bool EvaluateConditionChain(const std::vector< NodeConditionRef > &conditions, const ConditionPresetRegistry &registry, RuntimeEnvironment &env, std::string &outErrorMsg)
Evaluates a chain of conditions combined with logical operators (AND/OR).
static bool ResolveOperand(const Operand &operand, RuntimeEnvironment &env, std::string &outErrorMsg, float &outValue)
Resolves an Operand to its runtime float value.
Manages the global pool of ConditionPreset objects.
Provides Blackboard variable values and dynamic pin values at runtime.
< Provides AssetID and INVALID_ASSET_ID
@ Or
Combined with OR.
@ Start
First condition in the list (no logical combinator)
@ And
Combined with AND.
@ Variable
References a blackboard variable by ID (string key)
@ Const
Literal numeric constant (double)
@ Pin
External data input pin on the node (identified by label)
ComparisonOp
The relational operator used in a ConditionPreset.
A globally-stored, reusable condition expression.
One entry in a NodeBranch's conditions list.
One side of a ConditionPreset comparison expression.
Definition Operand.h:45