Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
BTGraphDocumentConverter.cpp
Go to the documentation of this file.
1/**
2 * @file BTGraphDocumentConverter.cpp
3 * @brief Implementation of BehaviorTreeAsset -> Olympe::NodeGraph conversion
4 *
5 * @details
6 * Converts a runtime BehaviorTreeAsset into an Olympe::NodeGraph by building
7 * an intermediate JSON document and using NodeGraph::FromJson() to preserve
8 * original BT node IDs. This ensures that NodeGraphPanel::SetActiveDebugNode()
9 * can highlight the correct node using the BT runtime node index directly.
10 *
11 * Layout positions are computed via BTGraphLayoutEngine when nodes have no
12 * stored positions (all zeros).
13 */
14
16#include "../BlueprintEditor/BTNodeGraphManager.h" // NodeGraph, NodeType, NodeTypeToString
17#include "../AI/BTGraphLayoutEngine.h"
18#include "../third_party/nlohmann/json.hpp"
19#include <iostream>
20
22
23namespace Olympe {
24namespace NodeGraphShared {
25
26// Map BTNodeType (runtime) to NodeType (Blueprint Editor) for visual consistency.
40
42{
43 if (!tree)
44 {
45 std::cerr << "[BTGraphDocumentConverter] ERROR: null BehaviorTreeAsset\n";
46 return nullptr;
47 }
48
49 if (tree->nodes.empty())
50 {
51 std::cerr << "[BTGraphDocumentConverter] WARNING: empty BehaviorTreeAsset '"
52 << tree->name << "'\n";
54 emptyGraph->name = tree->name;
55 emptyGraph->type = "BehaviorTree";
56 return emptyGraph;
57 }
58
59 // Priority 1: Load directly from the JSON source file so that the saved visual
60 // positions are preserved — identical to the Blueprint Editor standalone view.
61 const std::string filepath = BehaviorTreeManager::Get().GetTreePathFromId(tree->id);
62 if (!filepath.empty() && filepath.rfind("TreeName:", 0) != 0)
63 {
64 const int tempId = NodeGraphManager::Get().LoadGraph(filepath);
65 if (tempId != -1)
66 {
68 if (loadedGraph)
69 {
70 // Clone the graph so we can close the temporary slot immediately.
71 NodeGraph* result = new NodeGraph(*loadedGraph);
72 // The debugger is read-only: clear dirty so no accidental saves.
73 result->ClearDirty();
75 std::cout << "[BTGraphDocumentConverter] Loaded BT '" << tree->name
76 << "' from JSON (saved positions preserved)\n";
77 return result;
78 }
80 }
81 }
82
83 // Priority 2: Fallback — filepath unknown or LoadGraph failed.
84 // Compute BFS layout positions and build the graph from the runtime asset.
87
88 // Build a v2-format JSON document that NodeGraph::FromJson() can parse.
89 // This preserves BT node IDs in the resulting NodeGraph.
90 json j;
91 j["schema_version"] = 2;
92 j["name"] = tree->name;
93 j["blueprintType"] = "BehaviorTree";
94
95 json& data = j["data"];
96 data["rootNodeId"] = static_cast<int>(tree->rootNodeId);
97 data["nodes"] = json::array();
98
99 for (const auto& btNode : tree->nodes)
100 {
101 json nj;
102 nj["id"] = static_cast<int>(btNode.id);
103 nj["type"] = NodeTypeToString(MapBTToEditor(btNode.type));
104 nj["name"] = btNode.name.empty() ? NodeTypeToString(MapBTToEditor(btNode.type))
105 : btNode.name;
106
107 // Position from layout engine
108 float posX = 0.0f;
109 float posY = 0.0f;
110 const BTNodeLayout* layout = layoutEngine.GetNodeLayout(btNode.id);
111 if (layout)
112 {
113 posX = layout->position.x;
114 posY = layout->position.y;
115 }
116 nj["position"]["x"] = posX;
117 nj["position"]["y"] = posY;
118
119 // Parameters from BTNode flexible params
120 nj["parameters"] = json::object();
121 for (const auto& kv : btNode.stringParams)
122 nj["parameters"][kv.first] = kv.second;
123
124 // Children (composite nodes)
125 nj["children"] = json::array();
126 for (uint32_t childId : btNode.childIds)
127 nj["children"].push_back(static_cast<int>(childId));
128
129 // Decorator child (single child for Inverter / Repeater)
130 if (btNode.decoratorChildId != 0)
131 nj["decoratorChild"] = static_cast<int>(btNode.decoratorChildId);
132
133 data["nodes"].push_back(nj);
134 }
135
136 // FromJson is a friend of NodeGraph and preserves the node IDs from JSON.
137 NodeGraph converted = NodeGraph::FromJson(j);
138
139 NodeGraph* result = new NodeGraph(std::move(converted));
140
141 std::cout << "[BTGraphDocumentConverter] Converted BT '" << tree->name
142 << "': " << tree->nodes.size() << " nodes (BFS fallback layout)\n";
143
144 return result;
145}
146
148{
149 // Active node highlighting is driven externally by
150 // NodeGraphPanel::SetActiveDebugNode(). Nothing to do here.
151}
152
153} // namespace NodeGraphShared
154} // namespace Olympe
Conversion BehaviorTreeAsset -> Olympe::NodeGraph (Blueprint Editor pipeline)
nlohmann::json json
BTNodeType
Behavior tree node types.
@ Action
Leaf node - performs an action.
@ Selector
OR node - succeeds if any child succeeds.
@ Sequence
AND node - succeeds if all children succeed.
@ Inverter
Decorator - inverts child result.
@ Condition
Leaf node - checks a condition.
@ Repeater
Decorator - repeats child N times.
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
std::string GetTreePathFromId(uint32_t treeId) const
static BehaviorTreeManager & Get()
Computes clean hierarchical layouts for behavior trees.
std::vector< BTNodeLayout > ComputeLayout(const BehaviorTreeAsset *tree, float nodeSpacingX=320.0f, float nodeSpacingY=180.0f, float zoomFactor=1.0f)
Compute layout for a behavior tree.
int LoadGraph(const std::string &filepath)
NodeGraph * GetGraph(int graphId)
static NodeGraphManager & Get()
static NodeGraph * FromBehaviorTree(const BehaviorTreeAsset *tree)
Converts a BehaviorTreeAsset into a heap-allocated NodeGraph.
static void SyncActiveNode(NodeGraph *graph, uint32_t currentNodeId)
Synchronises the active-node metadata in an existing NodeGraph.
float x
Definition vector.h:25
nlohmann::json json
Definition Serializer.h:12
static NodeType MapBTToEditor(BTNodeType t)
< Provides AssetID and INVALID_ASSET_ID
const char * NodeTypeToString(NodeType type)
nlohmann::json json
Layout information for a single behavior tree node.
Vector position
Final position (x, y)