Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
BehaviorTreeEditorPlugin.cpp
Go to the documentation of this file.
1/*
2 * Olympe Blueprint Editor - Behavior Tree Plugin Implementation
3 */
4
6#include "../../Source/third_party/imgui/imgui.h"
7#include <chrono>
8#include <sstream>
9#include <iomanip>
10
12
13namespace Olympe
14{
18
22
24 {
25 auto now = std::chrono::system_clock::now();
26 auto time = std::chrono::system_clock::to_time_t(now);
27 std::stringstream ss;
28
29 // Use localtime_s for MSVC, localtime_r for other platforms
30 #ifdef _MSC_VER
31 std::tm timeinfo;
33 ss << std::put_time(&timeinfo, "%Y-%m-%dT%H:%M:%S");
34 #else
35 ss << std::put_time(std::localtime(&time), "%Y-%m-%dT%H:%M:%S");
36 #endif
37
38 return ss.str();
39 }
40
42 {
43 json bt;
44 bt["schema_version"] = 2;
45 bt["blueprintType"] = "BehaviorTree";
46 bt["name"] = name;
47 bt["description"] = "";
48 bt["metadata"]["author"] = "Atlasbruce";
49 bt["metadata"]["created"] = GetCurrentTimestamp();
50 bt["metadata"]["lastModified"] = GetCurrentTimestamp();
51 bt["metadata"]["tags"] = json::array();
52 bt["editorState"]["zoom"] = 1.0;
53 bt["editorState"]["scrollOffset"] = nlohmann::json::object();
54 bt["editorState"]["scrollOffset"]["x"] = 0;
55 bt["editorState"]["scrollOffset"]["y"] = 0;
56
57 // Root node by default
58 bt["data"]["rootNodeId"] = 1;
60 rootNode["id"] = 1;
61 rootNode["name"] = "Root Selector";
62 rootNode["type"] = "Selector";
63 nlohmann::json position = nlohmann::json::object();
64 position["x"] = 400;
65 position["y"] = 300;
66 rootNode["position"] = position;
67 rootNode["children"] = json::array();
68 rootNode["parameters"] = json::object();
69 bt["data"]["nodes"] = json::array();
70 bt["data"]["nodes"].push_back(rootNode);
71
72 return bt;
73 }
74
76 {
77 // V2 format check
78 if (blueprint.contains("blueprintType") &&
79 blueprint["blueprintType"].get<std::string>() == "BehaviorTree")
80 {
81 return true;
82 }
83
84 // V1 format heuristic
85 return blueprint.contains("rootNodeId") &&
86 blueprint.contains("nodes") &&
87 !blueprint.contains("states"); // Not an HFSM
88 }
89
90 std::vector<ValidationError> BehaviorTreeEditorPlugin::Validate(const json& blueprint)
91 {
92 std::vector<ValidationError> errors;
93
94 // Check if data section exists
95 if (!blueprint.contains("data"))
96 {
97 errors.push_back(ValidationError(-1, "", "Missing 'data' section", ErrorSeverity::Error));
98 return errors;
99 }
100
101 const json& data = blueprint["data"];
102
103 // Check root node exists
104 int rootId = data.contains("rootNodeId") ? data["rootNodeId"].get<int>() : -1;
105 if (rootId == -1)
106 {
107 errors.push_back(ValidationError(-1, "", "Missing rootNodeId", ErrorSeverity::Error));
108 return errors;
109 }
110
111 bool rootFound = false;
112
113 if (data.contains("nodes") && data["nodes"].is_array())
114 {
115 for (size_t i = 0; i < data["nodes"].size(); ++i)
116 {
117 const nlohmann::json& nodeObj = data["nodes"][i];
118 int nodeId = nodeObj.contains("id") && nodeObj["id"].is_number() ? nodeObj["id"].get<int>() : -1;
119 if (nodeId == rootId)
120 {
121 rootFound = true;
122 break;
123 }
124 }
125 }
126
127 if (!rootFound)
128 {
129 errors.push_back(ValidationError(-1, "", "Root node not found in nodes list", ErrorSeverity::Error));
130 }
131
132 // Verify all children exist
133 if (data.contains("nodes") && data["nodes"].is_array())
134 {
135 for (size_t i = 0; i < data["nodes"].size(); ++i)
136 {
137 const nlohmann::json& node = data["nodes"][i];
138 if (node.contains("children") && node["children"].is_array())
139 {
140 for (size_t j = 0; j < node["children"].size(); ++j)
141 {
142 const nlohmann::json& childIdJson = node["children"][j];
143 int cid = childIdJson.is_number() ? childIdJson.get<int>() : -1;
144 bool found = false;
145
146 for (size_t k = 0; k < data["nodes"].size(); ++k)
147 {
148 const nlohmann::json& n = data["nodes"][k];
149 if (n.is_object() && n.contains("id") && n["id"].is_number() && n["id"].get<int>() == cid)
150 {
151 found = true;
152 break;
153 }
154 }
155
156 if (!found)
157 {
158 int nodeId = node.contains("id") && node["id"].is_number() ? node["id"].get<int>() : -1;
159 std::string nodeIdStr = std::to_string(nodeId);
160 errors.push_back(ValidationError(-1,
161 nodeIdStr,
162 "Child node " + std::to_string(cid) + " not found",
164 ));
165 }
166 }
167 }
168 }
169 }
170
171 return errors;
172 }
173
175 {
176 if (!blueprintData.contains("data"))
177 {
178 ImGui::Text("Invalid blueprint: missing 'data' section");
179 return;
180 }
181
182 RenderBehaviorTreeGraph(blueprintData["data"], ctx);
183 }
184
186 {
187 ImGui::Text("Type: Behavior Tree");
188
189 if (blueprintData.contains("data") && blueprintData["data"].contains("nodes"))
190 {
191 ImGui::Text("Nodes: %d", (int)blueprintData["data"]["nodes"].size());
192 }
193 else
194 {
195 ImGui::Text("Nodes: 0");
196 }
197
198 ImGui::Separator();
199
200 if (ImGui::Button("Validate Tree", ImVec2(-1, 0)))
201 {
202 // Validation logic would go here
203 ImGui::OpenPopup("Validation Results");
204 }
205 }
206
208 {
209 if (ImGui::Button("Add Node"))
210 {
211 ImGui::OpenPopup("AddNodePopup");
212 }
213
214 ImGui::SameLine();
215
216 if (ImGui::Button("Validate"))
217 {
218 // Trigger validation
219 }
220 }
221
223 {
224 // This would integrate with the existing NodeGraphPanel
225 // For now, just show a placeholder
226 ImGui::Text("Behavior Tree Graph");
227 ImGui::Text("Root Node ID: %d", data.value("rootNodeId", -1));
228
229 if (data.contains("nodes") && data["nodes"].is_array())
230 {
231 ImGui::Separator();
232 ImGui::Text("Nodes:");
233
234 for (size_t i = 0; i < data["nodes"].size(); ++i)
235 {
236 const nlohmann::json& node = data["nodes"][i];
237 std::string nodeName = node.is_object() && node.contains("name") ? node["name"].get<std::string>() : "Unnamed";
238 std::string nodeType = node.is_object() && node.contains("type") ? node["type"].get<std::string>() : "Unknown";
239 int nodeId = node.value("id", -1);
240
241 ImGui::BulletText("[%d] %s (%s)", nodeId, nodeName.c_str(), nodeType.c_str());
242 }
243 }
244 }
245}
nlohmann::json json
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
void RenderToolbar(nlohmann::json &blueprintData) override
void RenderProperties(const nlohmann::json &blueprintData) override
nlohmann::json CreateNew(const std::string &name) override
std::vector< ValidationError > Validate(const nlohmann::json &blueprint) override
void RenderEditor(nlohmann::json &blueprintData, EditorContext_st &ctx) override
bool CanHandle(const nlohmann::json &blueprint) const override
void RenderBehaviorTreeGraph(nlohmann::json &data, EditorContext_st &ctx)
nlohmann::json json
nlohmann::json json