Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
VisualScriptEditorPanel_Blackboard.cpp
Go to the documentation of this file.
1/**
2 * @file VisualScriptEditorPanel_Blackboard.cpp
3 * @brief Blackboard and variables panel rendering (Phase 12).
4 * @author Olympe Engine
5 * @date 2026-03-09
6 *
7 * Extracted methods:
8 * - RenderBlackboard() ~150 LOC
9 * - RenderLocalVariablesPanel() ~120 LOC
10 * - RenderGlobalVariablesPanel() ~80 LOC
11 */
12
14#include "../system/system_utils.h"
15#include "../NodeGraphCore/GlobalTemplateBlackboard.h"
16#include "../third_party/imgui/imgui.h"
17#include <sstream>
18#include <iomanip>
19#include <cstring>
20#include <unordered_map>
21#include <algorithm>
22
23namespace Olympe {
24
26{
27 ImGui::TextDisabled("Local Blackboard");
28 ImGui::Separator();
29
30 bool hasInvalid = false;
31 for (size_t i = 0; i < m_template.Blackboard.size(); ++i)
32 {
33 const BlackboardEntry& entry = m_template.Blackboard[static_cast<size_t>(i)];
34 if (entry.Key.empty() || entry.Type == VariableType::None)
35 {
36 hasInvalid = true;
37 break;
38 }
39 }
40 if (hasInvalid)
41 {
42 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
43 ImGui::TextUnformatted("[!] Invalid entries will be skipped on save");
44 ImGui::PopStyleColor();
45 }
46
47 if (ImGui::Button("+##vsbbAdd"))
48 {
49 BlackboardEntry entry;
50 entry.Key = "NewVariable";
53 entry.IsGlobal = false;
54 m_template.Blackboard.push_back(entry);
55 m_dirty = true;
56 }
57 ImGui::SameLine();
58 ImGui::TextDisabled("Add key");
59
60 for (int idx = static_cast<int>(m_template.Blackboard.size()) - 1; idx >= 0; --idx)
61 {
62 BlackboardEntry& entry = m_template.Blackboard[static_cast<size_t>(idx)];
63
64 ImGui::PushID(idx);
65
66 char keyBuf[64];
67 strncpy_s(keyBuf, sizeof(keyBuf), entry.Key.c_str(), _TRUNCATE);
68 ImGui::SetNextItemWidth(120.0f);
69 if (ImGui::InputText("##bbkey", keyBuf, sizeof(keyBuf)))
70 {
71 entry.Key = keyBuf;
72 m_dirty = true;
73 }
74 ImGui::SameLine();
75
76 const char* typeLabels[] = {"Bool","Int","Float","Vector","EntityID","String"};
77 int typeIdx = static_cast<int>(entry.Type) - 1;
79 {
80 typeIdx = 1;
82 }
83 ImGui::SetNextItemWidth(80.0f);
84 if (ImGui::Combo("##bbtype", &typeIdx, typeLabels, 6))
85 {
86 VariableType newType = static_cast<VariableType>(typeIdx + 1);
87 entry.Type = newType;
89 m_dirty = true;
90 }
91 ImGui::SameLine();
92
93 ImGui::Checkbox("G##bbglob", &entry.IsGlobal);
94 ImGui::SameLine();
95
96 if (ImGui::SmallButton("x##bbdel"))
97 {
100 m_dirty = true;
101 ImGui::PopID();
102 continue;
103 }
104
105 ImGui::TextDisabled("Default:");
106 ImGui::SameLine();
107 switch (entry.Type)
108 {
110 {
111 bool bVal = entry.Default.IsNone() ? false : entry.Default.AsBool();
112 if (ImGui::Checkbox("##bbval", &bVal))
113 {
114 entry.Default = TaskValue(bVal);
115 m_dirty = true;
116 }
117 break;
118 }
120 {
121 int iVal = entry.Default.IsNone() ? 0 : entry.Default.AsInt();
122 ImGui::SetNextItemWidth(70.0f);
123 if (ImGui::InputInt("##bbval", &iVal))
124 {
125 entry.Default = TaskValue(iVal);
126 m_dirty = true;
127 }
128 break;
129 }
131 {
132 float fVal = entry.Default.IsNone() ? 0.0f : entry.Default.AsFloat();
133 ImGui::SetNextItemWidth(70.0f);
134 if (ImGui::InputFloat("##bbval", &fVal, 0.0f, 0.0f, "%.3f"))
135 {
136 entry.Default = TaskValue(fVal);
137 m_dirty = true;
138 }
139 break;
140 }
142 {
143 std::string sVal = entry.Default.IsNone() ? "" : entry.Default.AsString();
144 char sBuf[128];
145 strncpy_s(sBuf, sizeof(sBuf), sVal.c_str(), _TRUNCATE);
146 ImGui::SetNextItemWidth(100.0f);
147 if (ImGui::InputText("##bbval", sBuf, sizeof(sBuf)))
148 {
149 entry.Default = TaskValue(std::string(sBuf));
150 m_dirty = true;
151 }
152 break;
153 }
155 {
156 ImGui::BeginDisabled(true);
157 float vecVal[3] = { 0.0f, 0.0f, 0.0f };
158 ImGui::SetNextItemWidth(140.0f);
159 ImGui::DragFloat3("##bbval", vecVal, 0.1f);
160 ImGui::EndDisabled();
161 ImGui::SameLine();
162 ImGui::TextDisabled("(auto from entity position)");
163 break;
164 }
166 {
167 ImGui::BeginDisabled(true);
168 int entityId = 0;
169 ImGui::SetNextItemWidth(70.0f);
170 ImGui::InputInt("##bbval", &entityId);
171 ImGui::EndDisabled();
172 ImGui::SameLine();
173 ImGui::TextDisabled("(assigned at runtime)");
174 break;
175 }
176 default:
177 ImGui::TextDisabled("(n/a)");
178 break;
179 }
180
181 ImGui::PopID();
182 }
183}
184
186{
187 ImGui::TextDisabled("Local Blackboard");
188 ImGui::Separator();
189
190 bool hasInvalid = false;
191 for (size_t i = 0; i < m_template.Blackboard.size(); ++i)
192 {
193 const BlackboardEntry& entry = m_template.Blackboard[static_cast<size_t>(i)];
194 if (entry.Key.empty() || entry.Type == VariableType::None)
195 {
196 hasInvalid = true;
197 break;
198 }
199 }
200 if (hasInvalid)
201 {
202 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
203 ImGui::TextUnformatted("[!] Invalid entries will be skipped on save");
204 ImGui::PopStyleColor();
205 }
206
207 if (ImGui::Button("+##vsbbAdd"))
208 {
209 BlackboardEntry entry;
210 entry.Key = "NewVariable";
213 entry.IsGlobal = false;
214 m_template.Blackboard.push_back(entry);
215 m_dirty = true;
216 }
217 ImGui::SameLine();
218 ImGui::TextDisabled("Add key");
219
220 for (int idx = static_cast<int>(m_template.Blackboard.size()) - 1; idx >= 0; --idx)
221 {
222 BlackboardEntry& entry = m_template.Blackboard[static_cast<size_t>(idx)];
223
224 ImGui::PushID(idx);
225
226 char keyBuf[64];
227 strncpy_s(keyBuf, sizeof(keyBuf), entry.Key.c_str(), _TRUNCATE);
228
229 // ====== VALIDATION: Key input with error feedback ======
230 ImGui::SetNextItemWidth(140.0f);
231 if (ImGui::InputText("##bbkey", keyBuf, sizeof(keyBuf)))
232 {
233 std::string newKey(keyBuf);
234 BlackboardValidationResult validation = ValidateBlackboardKey(newKey, entry.IsGlobal, idx);
235
236 if (validation.IsValid)
237 {
238 entry.Key = newKey;
240 m_dirty = true;
241 }
242 // If invalid, we display the error below but don't update entry.Key
243 }
244
245 // Display validation feedback
246 if (!entry.Key.empty() && entry.Type != VariableType::None)
247 {
248 BlackboardValidationResult validation = ValidateBlackboardKey(entry.Key, entry.IsGlobal, idx);
249
250 if (!validation.IsValid)
251 {
252 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f)); // Red for error
253 ImGui::SameLine();
254 ImGui::TextDisabled("/!\\ %s", validation.ErrorMessage.c_str());
255 ImGui::PopStyleColor();
256 }
257 else if (!validation.WarningMessage.empty())
258 {
259 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.85f, 0.0f, 1.0f)); // Yellow for warning
260 ImGui::SameLine();
261 ImGui::TextDisabled("[i] %s", validation.WarningMessage.c_str());
262 ImGui::PopStyleColor();
263 }
264 }
265
266 ImGui::SameLine();
267
268 const char* typeNames[] = { "None", "Bool", "Int", "Float", "String", "Vector" };
269 const VariableType typeValues[] = {
272 };
273 int curTypeIdx = 0;
274 for (int ti = 0; ti < 6; ++ti)
275 if (entry.Type == typeValues[ti])
276 { curTypeIdx = ti; break; }
277
278 ImGui::SetNextItemWidth(80.0f);
279 if (ImGui::Combo("##bbtype", &curTypeIdx, typeNames, 6))
280 {
282 entry.Default = GetDefaultValueForType(entry.Type);
283 m_dirty = true;
284 }
285
286 if (entry.Type != VariableType::None)
287 {
288 ImGui::SameLine();
289 ImGui::TextDisabled("Default:");
290 ImGui::SameLine();
291 RenderConstValueInput(entry.Default, entry.Type, "##bbdefault");
292 }
293
294 ImGui::SameLine();
295 bool isGlobal = entry.IsGlobal;
296 if (ImGui::Checkbox("G##bbglobal", &isGlobal))
297 {
298 entry.IsGlobal = isGlobal;
299 m_dirty = true;
300 }
301 if (ImGui::IsItemHovered())
302 ImGui::SetTooltip("Mark as global variable");
303
304 ImGui::SameLine();
305 if (ImGui::Button("X##bbdel"))
306 {
309 m_dirty = true;
310 }
311
312 ImGui::PopID();
313 }
314}
315
317{
318 ImGui::TextDisabled("Global Variables (Editor Instance)");
319 ImGui::Separator();
320
321 GlobalTemplateBlackboard& gtb = GlobalTemplateBlackboard::Get();
322 const std::vector<GlobalEntryDefinition>& globalVars = gtb.GetAllVariables();
323
324 if (ImGui::Button("+##globalVarAdd", ImVec2(30, 0)))
325 {
326 ImGui::OpenPopup("AddGlobalVariablePopup");
327 }
328 ImGui::SameLine();
329 ImGui::TextDisabled("Add global variable");
330
331 if (ImGui::BeginPopupModal("AddGlobalVariablePopup", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
332 {
333 static char newVarName[128] = "newGlobal";
334 static int newVarTypeIdx = 2;
335 static char newVarDescription[256] = "Enter description...";
336
337 ImGui::InputText("Variable Name##new", newVarName, sizeof(newVarName));
338
339 // Validate global variable name
340 std::string globalName(newVarName);
341 BlackboardValidationResult validation = ValidateBlackboardKey(globalName, true);
342
343 if (strlen(newVarName) > 0)
344 {
345 if (!validation.IsValid)
346 {
347 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f)); // Red
348 ImGui::TextUnformatted(validation.ErrorMessage.c_str());
349 ImGui::PopStyleColor();
350 }
351 else if (!validation.WarningMessage.empty())
352 {
353 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.85f, 0.0f, 1.0f)); // Yellow
354 ImGui::TextUnformatted(validation.WarningMessage.c_str());
355 ImGui::PopStyleColor();
356 }
357
358 // Also check if already exists in global blackboard
359 if (gtb.HasVariable(globalName))
360 {
361 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
362 ImGui::TextUnformatted("/!\\ Variable already exists in global registry");
363 ImGui::PopStyleColor();
364 }
365 }
366
367 const char* typeOptions[] = { "Bool", "Int", "Float", "String", "Vector", "EntityID" };
368 const VariableType typeValues[] = {
371 };
372 ImGui::Combo("Type##new", &newVarTypeIdx, typeOptions, 6);
373
374 ImGui::InputTextMultiline("Description##new", newVarDescription, sizeof(newVarDescription), ImVec2(0, 60));
375
376 // Disable Create button if validation fails
377 bool canCreate = strlen(newVarName) > 0 && validation.IsValid && !gtb.HasVariable(newVarName);
378
379 if (!canCreate)
380 ImGui::BeginDisabled(true);
381
382 if (ImGui::Button("Create", ImVec2(120, 0)))
383 {
384 if (strlen(newVarName) > 0 && !gtb.HasVariable(newVarName))
385 {
388 {
389 SYSTEM_LOG << "[VSEditor] Created new global variable: " << newVarName << "\n";
390 gtb.SaveToFile();
391
393
394 m_dirty = true;
395
396 memset(newVarName, 0, sizeof(newVarName));
397 strcpy_s(newVarName, sizeof(newVarName), "newGlobal");
398 newVarTypeIdx = 2;
400 strcpy_s(newVarDescription, sizeof(newVarDescription), "Enter description...");
401
402 ImGui::CloseCurrentPopup();
403 }
404 }
405 }
406 ImGui::SameLine();
407 if (ImGui::Button("Cancel", ImVec2(120, 0)))
408 {
409 ImGui::CloseCurrentPopup();
410 }
411
412 if (!canCreate)
413 ImGui::EndDisabled();
414
415 ImGui::EndPopup();
416 }
417
418 ImGui::Separator();
419
420 if (globalVars.empty())
421 {
422 ImGui::TextDisabled("(no global variables defined)");
423 ImGui::TextDisabled("Click [+] above to create new global variables");
424 return;
425 }
426
427 ImGui::TextDisabled("Global variables from project registry");
428 ImGui::TextDisabled("Values shown are editor-specific (persisted with graph)");
429 ImGui::Separator();
430
432 {
433 ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.5f, 1.0f), "[ERROR] EntityBlackboard not initialized");
434 return;
435 }
436
437 for (size_t gi = 0; gi < globalVars.size(); ++gi)
438 {
439 const GlobalEntryDefinition& globalDef = globalVars[gi];
440
441 ImGui::PushID(static_cast<int>(gi));
442
443 ImGui::TextColored(ImVec4(0.8f, 0.95f, 1.0f, 1.0f), "(%s) %s",
444 VariableTypeToString(globalDef.Type).c_str(),
445 globalDef.Key.c_str());
446
447 ImGui::SameLine();
448 ImGui::TextDisabled("(%.1f KB)", 0.1f);
449 ImGui::SameLine();
450
451 if (ImGui::SmallButton("Delete##globalvar"))
452 {
453 std::string varToDelete = globalDef.Key;
454 if (gtb.RemoveVariable(varToDelete))
455 {
456 SYSTEM_LOG << "[VSEditor] Deleted global variable: " << varToDelete << "\n";
457 gtb.SaveToFile();
458
460
461 m_dirty = true;
462 }
463 ImGui::PopID();
464 continue;
465 }
466
467 if (!globalDef.Description.empty())
468 {
469 ImGui::TextDisabled(" %s", globalDef.Description.c_str());
470 }
471
472 std::string tableId = "##GlobalVarTable_" + std::to_string(gi);
473 if (ImGui::BeginTable(tableId.c_str(), 2, ImGuiTableFlags_SizingStretchSame, ImVec2(0, 0)))
474 {
475 ImGui::TableSetupColumn("Label", 0);
476 ImGui::TableSetupColumn("Value", 0);
477
478 ImGui::TableNextRow();
479 ImGui::TableSetColumnIndex(0);
480 ImGui::TextDisabled("Default:");
481 ImGui::TableSetColumnIndex(1);
482
483 const TaskValue& defaultValue = globalDef.DefaultValue;
484 std::string defaultStr;
485 switch (globalDef.Type)
486 {
488 defaultStr = defaultValue.IsNone() ? "false" : (defaultValue.AsBool() ? "true" : "false");
489 break;
491 defaultStr = defaultValue.IsNone() ? "0" : std::to_string(defaultValue.AsInt());
492 break;
494 {
495 std::ostringstream oss;
496 oss << std::fixed << std::setprecision(2);
497 oss << (defaultValue.IsNone() ? 0.0f : defaultValue.AsFloat());
498 defaultStr = oss.str();
499 break;
500 }
502 defaultStr = defaultValue.IsNone() ? "" : defaultValue.AsString();
503 break;
505 defaultStr = "(vector)";
506 break;
508 defaultStr = defaultValue.IsNone() ? "0" : std::to_string(static_cast<int>(defaultValue.AsEntityID()));
509 break;
510 default:
511 defaultStr = "(unknown)";
512 break;
513 }
514 ImGui::TextDisabled("%s", defaultStr.c_str());
515
516 ImGui::TableNextRow();
517 ImGui::TableSetColumnIndex(0);
518 ImGui::TextDisabled("Current:");
519 ImGui::TableSetColumnIndex(1);
520
521 std::string scopedVarName = "(G)" + globalDef.Key;
522 TaskValue currentValue = m_entityBlackboard->GetValueScoped(scopedVarName);
523
524 bool valueChanged = false;
525 switch (globalDef.Type)
526 {
528 {
529 bool bVal = currentValue.IsNone() ? false : currentValue.AsBool();
530 if (ImGui::Checkbox("##bool_val", &bVal))
531 {
532 m_entityBlackboard->SetValueScoped(scopedVarName, TaskValue(bVal));
533 m_dirty = true;
534 valueChanged = true;
535 }
536 break;
537 }
539 {
540 int iVal = currentValue.IsNone() ? 0 : currentValue.AsInt();
541 if (ImGui::InputInt("##int_val", &iVal))
542 {
543 m_entityBlackboard->SetValueScoped(scopedVarName, TaskValue(iVal));
544 m_dirty = true;
545 valueChanged = true;
546 }
547 break;
548 }
550 {
551 float fVal = currentValue.IsNone() ? 0.0f : currentValue.AsFloat();
552 if (ImGui::InputFloat("##float_val", &fVal))
553 {
554 m_entityBlackboard->SetValueScoped(scopedVarName, TaskValue(fVal));
555 m_dirty = true;
556 valueChanged = true;
557 }
558 break;
559 }
561 {
562 static std::unordered_map<size_t, std::vector<char>> stringBuffers;
563 size_t bufKey = gi;
564 if (stringBuffers.find(bufKey) == stringBuffers.end())
565 {
566 std::string initialStr = currentValue.IsNone() ? "" : currentValue.AsString();
567 stringBuffers[bufKey] = std::vector<char>(initialStr.begin(), initialStr.end());
568 stringBuffers[bufKey].push_back('\0');
569 stringBuffers[bufKey].resize(256);
570 }
571
572 ImGui::SetNextItemWidth(-1.0f);
573 if (ImGui::InputText("##string_val", stringBuffers[bufKey].data(), 256, ImGuiInputTextFlags_EnterReturnsTrue))
574 {
575 std::string newStr(stringBuffers[bufKey].data());
576 m_entityBlackboard->SetValueScoped(scopedVarName, TaskValue(newStr));
577 m_dirty = true;
578 valueChanged = true;
579 }
580 break;
581 }
583 {
584 Vector vVal = currentValue.IsNone() ? Vector{0.0f, 0.0f, 0.0f} : currentValue.AsVector();
585 float vArray[3] = {vVal.x, vVal.y, vVal.z};
586 if (ImGui::InputFloat3("##vector_val", vArray))
587 {
588 Vector newVec{vArray[0], vArray[1], vArray[2]};
589 m_entityBlackboard->SetValueScoped(scopedVarName, TaskValue(newVec));
590 m_dirty = true;
591 valueChanged = true;
592 }
593 break;
594 }
596 {
597 int eID = currentValue.IsNone() ? 0 : static_cast<int>(currentValue.AsEntityID());
598 if (ImGui::InputInt("##entityid_val", &eID))
599 {
600 m_entityBlackboard->SetValueScoped(scopedVarName, TaskValue(eID >= 0 ? eID : 0));
601 m_dirty = true;
602 valueChanged = true;
603 }
604 break;
605 }
606 default:
607 ImGui::TextDisabled("(unsupported type)");
608 break;
609 }
610
611 if (globalDef.IsPersistent)
612 {
613 ImGui::TableNextRow();
614 ImGui::TableSetColumnIndex(0);
615 ImGui::TextDisabled("Flags:");
616 ImGui::TableSetColumnIndex(1);
617 ImGui::TextColored(ImVec4(0.7f, 0.9f, 0.5f, 1.0f), "[Persistent]");
618 }
619
620 ImGui::EndTable();
621 }
622 ImGui::Separator();
623 ImGui::PopID();
624 }
625}
626
627// ============================================================================
628// Phase 26 — Tab-based panel system for right side
629// ============================================================================
630
632{
633 /// Renders the tab bar for selecting between Presets, Local Variables, and Global Variables
634 /// Uses a horizontal button group with visual feedback for the active tab
635
636 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f));
637 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2.0f, 0.0f));
638
639 // Tab 0: Presets
640 {
641 bool isActive = (m_rightPanelTabSelection == 0);
642 if (isActive)
643 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.4f, 0.8f, 1.0f));
644 else
645 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.25f, 0.25f, 0.25f, 0.7f));
646
647 if (ImGui::Button("Presets##tab0", ImVec2(0, 0)))
649
650 ImGui::PopStyleColor();
651 }
652
653 ImGui::SameLine();
654
655 // Tab 1: Local Variables
656 {
657 bool isActive = (m_rightPanelTabSelection == 1);
658 if (isActive)
659 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.4f, 0.8f, 1.0f));
660 else
661 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.25f, 0.25f, 0.25f, 0.7f));
662
663 if (ImGui::Button("Local Variables##tab1", ImVec2(0, 0)))
665
666 ImGui::PopStyleColor();
667 }
668
669 ImGui::SameLine();
670
671 // Tab 2: Global Variables
672 {
673 bool isActive = (m_rightPanelTabSelection == 2);
674 if (isActive)
675 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.4f, 0.8f, 1.0f));
676 else
677 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.25f, 0.25f, 0.25f, 0.7f));
678
679 if (ImGui::Button("Global Variables##tab2", ImVec2(0, 0)))
681
682 ImGui::PopStyleColor();
683 }
684
685 ImGui::PopStyleVar(2);
686 ImGui::Separator();
687}
688
690{
691 /// Renders the content of the currently selected tab
692 /// Dispatches to the appropriate render function based on m_rightPanelTabSelection
693
695 {
696 case 0:
697 // Tab 0: Presets
699 break;
700
701 case 1:
702 // Tab 1: Local Variables
704 break;
705
706 case 2:
707 // Tab 2: Global Variables
709 break;
710
711 default:
712 // Fallback: show presets
714 break;
715 }
716}
717
718} // namespace Olympe
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
ImNodes-based graph editor for ATS Visual Script graphs (Phase 5).
static void Reload()
Force reload of the registry from file (useful for hot reload)
static GlobalTemplateBlackboard & Get()
std::vector< BlackboardEntry > Blackboard
Local blackboard declared in this graph.
TaskGraphTemplate m_template
The template currently being edited.
void RenderRightPanelTabs()
Phase 26 — Tab system: Renders the tab bar for the 3-panel right section Displays tabs for Presets,...
std::unique_ptr< EntityBlackboard > m_entityBlackboard
Per-entity blackboard instance (combines local + global variables) Created in Initialize() and manage...
std::unordered_map< int, std::string > m_pendingBlackboardEdits
Deferred key-name edits for blackboard entries: index -> pending new key.
void RenderGlobalVariablesPanel()
Phase 24 Global Blackboard — Renders global variables panel.
void RenderLocalVariablesPanel()
Part C: Local Variables reference panel (bottom of right panel)
void RenderConstValueInput(TaskValue &value, VariableType varType, const char *label)
Renders a type-aware const value input widget.
void RenderRightPanelTabContent()
Phase 26 — Tab system: Renders the content of the active tab Dispatches to appropriate render functio...
BlackboardValidationResult ValidateBlackboardKey(const std::string &key, bool isGlobal, int excludeIndex=-1)
Validates a blackboard key according to schema rules.
int m_rightPanelTabSelection
Phase 26 — Right panel tab selection 0 = Presets, 1 = Local Variables, 2 = Global Variables.
void RenderPresetBankPanel()
Part B: Preset Bank panel (middle of right panel)
float x
Definition vector.h:25
< 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)
@ None
Uninitialized / empty value.
@ EntityID
Entity identifier (uint64_t)
static std::string VariableTypeToString(VariableType type)
Converts a VariableType to its canonical string representation.
static TaskValue GetDefaultValueForType(VariableType type)
Returns a correctly-typed default TaskValue for the given VariableType.
#define SYSTEM_LOG