Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
EntityBlackboard.cpp
Go to the documentation of this file.
1/**
2 * @file EntityBlackboard.cpp
3 * @brief Implementation of EntityBlackboard (per-entity global+local blackboard instance)
4 * @author Olympe Engine
5 * @date 2026-03-26
6 */
7
8#include "EntityBlackboard.h"
9#include "../NodeGraphCore/GlobalTemplateBlackboard.h"
10#include "../system/system_utils.h"
11#include "../json_helper.h"
12
13#include <sstream>
14#include <iomanip>
15
16namespace Olympe {
17
22
26
28 const std::unordered_map<std::string, TaskValue>* globalOverrides)
29{
30 SYSTEM_LOG << "[EntityBlackboard] Initialize: entity=" << m_entityID << "\n";
32
33 // Initialize global variables from the global template registry
35 const std::vector<GlobalEntryDefinition>& globalVars = gtb.GetAllVariables();
36
37 for (const auto& globalDef : globalVars)
38 {
39 // Store the variable with its default value
40 TaskValue varValue = globalDef.DefaultValue;
41
42 // Apply override if provided
43 if (globalOverrides != nullptr)
44 {
45 auto overrideIt = globalOverrides->find(globalDef.Key);
46 if (overrideIt != globalOverrides->end())
47 {
48 varValue = overrideIt->second;
49 SYSTEM_LOG << "[EntityBlackboard] Applied override for global '" << globalDef.Key << "'\n";
50 }
51 }
52
55 }
56
57 SYSTEM_LOG << "[EntityBlackboard] Initialized " << m_globalVars.size() << " global variables\n";
58}
59
61{
62 SYSTEM_LOG << "[EntityBlackboard] Reset: entity=" << m_entityID << "\n";
64
65 // Reset global variables to their defaults
67 const std::vector<GlobalEntryDefinition>& globalVars = gtb.GetAllVariables();
68
69 for (const auto& globalDef : globalVars)
70 {
71 m_globalVars[globalDef.Key] = globalDef.DefaultValue;
73 }
74}
75
77{
78 m_globalVars.clear();
79 m_globalTypes.clear();
80}
81
83{
84 std::string prefix, bareVarName;
86
87 if (prefix == "(L)")
88 {
90 }
91 else if (prefix == "(G)")
92 {
94 }
95 else
96 {
97 // Bare name: local-first with fallback to global
99 {
101 }
103 }
104}
105
106void EntityBlackboard::SetValueScoped(const std::string& varName, const TaskValue& value)
107{
108 std::string prefix, bareVarName;
110
111 if (prefix == "(L)")
112 {
114 }
115 else if (prefix == "(G)")
116 {
118 }
119 else
120 {
121 // Bare name: local-first with fallback to global
123 {
125 }
126 else
127 {
129 }
130 }
131}
132
134{
135 auto it = m_globalVars.find(globalKey);
136 if (it == m_globalVars.end())
137 {
138 // Phase 24: Lazy-sync missing global variables from registry
139 // This handles the case where new global variables are added to the registry
140 // after this EntityBlackboard was initialized
142 const GlobalEntryDefinition* globalDef = gtb.GetVariable(globalKey);
143
144 if (globalDef != nullptr)
145 {
146 // Variable exists in registry but not in this instance
147 // Add it with default value (using const_cast for lazy-sync mutation)
148 auto& mutableGlobalVars = const_cast<std::unordered_map<std::string, TaskValue>&>(m_globalVars);
149 auto& mutableGlobalTypes = const_cast<std::unordered_map<std::string, VariableType>&>(m_globalTypes);
150
153
154 SYSTEM_LOG << "[EntityBlackboard] Lazy-synced missing global variable: '" << globalKey
155 << "' (type: " << VariableTypeToString(globalDef->Type) << ")\n";
156
157 // CRITICAL FIX: Re-find the newly added variable
158 // After insertion, the old iterator 'it' is stale. We must find the variable again.
159 it = m_globalVars.find(globalKey);
160 return it->second;
161 }
162
163 SYSTEM_LOG << "[EntityBlackboard] ERROR: Global variable not found: '" << globalKey << "'\n";
164 throw std::runtime_error("Global variable not found: " + globalKey);
165 }
166 return it->second;
167}
168
169void EntityBlackboard::SetGlobalValue(const std::string& globalKey, const TaskValue& value)
170{
171 auto typeIt = m_globalTypes.find(globalKey);
172 if (typeIt == m_globalTypes.end())
173 {
174 // Phase 24: Lazy-sync missing global variables from registry
175 // This handles the case where new global variables are added to the registry
176 // after this EntityBlackboard was initialized
178 const GlobalEntryDefinition* globalDef = gtb.GetVariable(globalKey);
179
180 if (globalDef != nullptr)
181 {
182 // Variable exists in registry but not in this instance
183 // Add it with the provided value
185 m_globalVars[globalKey] = value;
186
187 SYSTEM_LOG << "[EntityBlackboard] Lazy-synced missing global variable for set: '" << globalKey
188 << "' (type: " << VariableTypeToString(globalDef->Type) << ")\n";
189 return;
190 }
191
192 SYSTEM_LOG << "[EntityBlackboard] ERROR: Global variable not found for set: '" << globalKey << "'\n";
193 throw std::runtime_error("Global variable not found: " + globalKey);
194 }
195
196 // Type compatibility check
197 VariableType expectedType = typeIt->second;
199
200 // Allow None type (for initialization) or exact match
201 if (providedType != VariableType::None && providedType != expectedType)
202 {
203 SYSTEM_LOG << "[EntityBlackboard] WARNING: Type mismatch for global '" << globalKey
204 << "' (expected " << VariableTypeToString(expectedType)
205 << ", got " << VariableTypeToString(providedType) << ")\n";
206 }
207
208 m_globalVars[globalKey] = value;
209}
210
215
216void EntityBlackboard::SetLocalValue(const std::string& localKey, const TaskValue& value)
217{
219}
220
221bool EntityBlackboard::HasVariableScoped(const std::string& varName) const
222{
223 std::string prefix, bareVarName;
225
226 if (prefix == "(L)")
227 {
229 }
230 else if (prefix == "(G)")
231 {
233 }
234 else
235 {
237 }
238}
239
240bool EntityBlackboard::HasGlobalVariable(const std::string& globalKey) const
241{
242 return m_globalVars.find(globalKey) != m_globalVars.end();
243}
244
245bool EntityBlackboard::HasLocalVariable(const std::string& localKey) const
246{
248}
249
254
256{
257 return m_globalVars.size();
258}
259
261{
262 // TODO: Call appropriate LocalBlackboard method once interface is known
263 return 0; // Placeholder
264}
265
270
272{
273 std::ostringstream oss;
274 oss << "EntityBlackboard(id=" << m_entityID
275 << ", locals=" << GetLocalVariableCount()
276 << ", globals=" << GetGlobalVariableCount() << ")";
277 return oss.str();
278}
279
281{
282 SYSTEM_LOG << "=== " << DebugSummary() << " ===\n";
283 SYSTEM_LOG << "Local variables: " << GetLocalVariableCount() << "\n";
284 SYSTEM_LOG << "Global variables: " << GetGlobalVariableCount() << "\n";
285}
286
288{
289 json obj = json::object();
290
291 for (auto it = m_globalVars.begin(); it != m_globalVars.end(); ++it)
292 {
293 const std::string& varName = it->first;
294 const TaskValue& value = it->second;
295 if (value.IsNone())
296 {
297 obj[varName] = nullptr;
298 }
299 else
300 {
301 switch (value.GetType())
302 {
304 obj[varName] = value.AsBool();
305 break;
307 obj[varName] = value.AsInt();
308 break;
310 obj[varName] = value.AsFloat();
311 break;
313 obj[varName] = value.AsString();
314 break;
316 {
317 const ::Vector v = value.AsVector();
318 json vecObj;
319 vecObj["x"] = v.x;
320 vecObj["y"] = v.y;
321 vecObj["z"] = v.z;
322 obj[varName] = vecObj;
323 break;
324 }
326 obj[varName] = static_cast<int>(value.AsEntityID());
327 break;
328 default:
329 obj[varName] = nullptr;
330 break;
331 }
332 }
333 }
334
335 return obj;
336}
337
339{
340 if (!data.is_object())
341 {
342 return false;
343 }
344
345 bool success = true;
346
347 for (auto it = data.begin(); it != data.end(); ++it)
348 {
349 const std::string& key = it.key();
350 const json& valueNode = it.value();
351
352 auto typeIt = m_globalTypes.find(key);
353 if (typeIt == m_globalTypes.end())
354 {
355 SYSTEM_LOG << "[EntityBlackboard] WARNING: Global variable '" << key << "' not found in registry\n";
356 success = false;
357 continue;
358 }
359
360 VariableType varType = typeIt->second;
361
362 try
363 {
364 TaskValue value;
365 if (valueNode.is_null())
366 {
367 value = TaskValue();
368 }
369 else if (varType == VariableType::Bool && valueNode.is_boolean())
370 {
371 value = TaskValue(valueNode.get<bool>());
372 }
373 else if (varType == VariableType::Int && valueNode.is_number_integer())
374 {
375 value = TaskValue(valueNode.get<int>());
376 }
377 else if (varType == VariableType::Float && valueNode.is_number())
378 {
379 value = TaskValue(static_cast<float>(valueNode.get<double>()));
380 }
381 else if (varType == VariableType::String && valueNode.is_string())
382 {
383 value = TaskValue(valueNode.get<std::string>());
384 }
385 else if (varType == VariableType::Vector && valueNode.is_object() &&
386 valueNode.contains("x") && valueNode.contains("y") && valueNode.contains("z"))
387 {
388 const float x = valueNode["x"].get<float>();
389 const float y = valueNode["y"].get<float>();
390 const float z = valueNode["z"].get<float>();
391 value = TaskValue(::Vector{x, y, z});
392 }
393 else if (varType == VariableType::EntityID && valueNode.is_number_integer())
394 {
395 value = TaskValue(valueNode.get<int>());
396 }
397 else
398 {
399 SYSTEM_LOG << "[EntityBlackboard] WARNING: Type mismatch for global '" << key << "'\n";
400 success = false;
401 continue;
402 }
403
404 m_globalVars[key] = value;
405 }
406 catch (const std::exception& e)
407 {
408 SYSTEM_LOG << "[EntityBlackboard] EXCEPTION importing global '" << key << "': " << e.what() << "\n";
409 success = false;
410 }
411 }
412
413 return success;
414}
415
417 std::string& outPrefix,
418 std::string& outName)
419{
420 // Check for (L) or (G) prefix
421 if (scopedName.length() >= 3 && scopedName[0] == '(' && scopedName[2] == ')')
422 {
423 char scope = scopedName[1];
424 if (scope == 'L' || scope == 'G')
425 {
426 outPrefix = std::string(1, '(') + scope + ")";
427 outName = scopedName.substr(3);
428 return;
429 }
430 }
431
432 // No prefix: bare name
433 outPrefix = "";
435}
436
437} // namespace Olympe
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
Per-entity instance of global blackboard.
TaskValue GetValueScoped(const std::string &varName) const
void Initialize(const TaskGraphTemplate &tmpl, const std::unordered_map< std::string, TaskValue > *globalOverrides=nullptr)
TaskValue GetLocalValue(const std::string &localKey) const
bool HasVariableScoped(const std::string &varName) const
std::string DebugSummary() const
EntityBlackboard(uint32_t entityID=0)
void SetLocalValue(const std::string &localKey, const TaskValue &value)
std::unordered_map< std::string, VariableType > m_globalTypes
void SetValueScoped(const std::string &varName, const TaskValue &value)
TaskValue GetGlobalValue(const std::string &globalKey) const
size_t GetGlobalVariableCount() const
bool ImportGlobalsFromJson(const json &data)
std::unordered_map< std::string, TaskValue > m_globalVars
static void ParseScopedName(const std::string &scopedName, std::string &outPrefix, std::string &outName)
bool HasGlobalVariable(const std::string &globalKey) const
bool HasLocalVariable(const std::string &localKey) const
void SetGlobalValue(const std::string &globalKey, const TaskValue &value)
static GlobalTemplateBlackboard & Get()
void Reset()
Resets all variables to their default values.
void Initialize(const TaskGraphTemplate &tmpl)
Initialises the blackboard from a template.
bool HasVariable(const std::string &varName) const
Returns true if a variable with the given name is registered.
void SetValue(const std::string &varName, const TaskValue &value)
Sets the value of a variable.
TaskValue GetValue(const std::string &varName) const
Returns the current value of a variable.
Immutable, shareable task graph asset.
C++14-compliant type-safe value container for task parameters.
int AsInt() const
Returns the int value.
::Vector AsVector() const
Returns the Vector value.
EntityID AsEntityID() const
Returns the EntityID value.
float AsFloat() const
Returns the float value.
bool IsNone() const
Returns true if the value has not been set (type == None).
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.
float x
Definition vector.h:25
< Provides AssetID and INVALID_ASSET_ID
nlohmann::json json
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)
@ None
Uninitialized / empty value.
@ EntityID
Entity identifier (uint64_t)
static std::string VariableTypeToString(VariableType type)
Converts a VariableType to its canonical string representation.
#define SYSTEM_LOG