Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
CommandSystem.cpp
Go to the documentation of this file.
1/*
2 * Olympe Blueprint Editor - Command System Implementation
3 */
4
5#include "CommandSystem.h"
6#include "NodeGraphManager.h"
7#include <iostream>
8
9namespace Olympe
10{
11 // ========================================================================
12 // CommandStack Implementation
13 // ========================================================================
14
16 : m_MaxStackSize(100) // Limit to 100 commands
17 {
18 }
19
24
25 void CommandStack::ExecuteCommand(std::unique_ptr<EditorCommand> cmd)
26 {
27 if (!cmd)
28 {
29 return;
30 }
31
32 // Execute the command
33 cmd->Execute();
34
35 // Add to undo stack
36 m_UndoStack.push_back(std::move(cmd));
37
38 // Clear redo stack (new action invalidates redo history)
39 m_RedoStack.clear();
40
41 // Enforce stack size limit
42 if (m_UndoStack.size() > m_MaxStackSize)
43 {
44 m_UndoStack.erase(m_UndoStack.begin());
45 }
46
47 std::cout << "Command executed: " << m_UndoStack.back()->GetDescription() << std::endl;
48 }
49
51 {
52 if (m_UndoStack.empty())
53 {
54 return;
55 }
56
57 // Get last command
58 auto cmd = std::move(m_UndoStack.back());
59 m_UndoStack.pop_back();
60
61 // Undo the command
62 cmd->Undo();
63
64 // Move to redo stack
65 m_RedoStack.push_back(std::move(cmd));
66
67 std::cout << "Command undone: " << m_RedoStack.back()->GetDescription() << std::endl;
68 }
69
71 {
72 if (m_RedoStack.empty())
73 {
74 return;
75 }
76
77 // Get last undone command
78 auto cmd = std::move(m_RedoStack.back());
79 m_RedoStack.pop_back();
80
81 // Re-execute the command
82 cmd->Execute();
83
84 // Move back to undo stack
85 m_UndoStack.push_back(std::move(cmd));
86
87 std::cout << "Command redone: " << m_UndoStack.back()->GetDescription() << std::endl;
88 }
89
91 {
92 if (m_UndoStack.empty())
93 {
94 return nullptr;
95 }
96 return m_UndoStack.back().get();
97 }
98
100 {
101 if (m_UndoStack.empty())
102 {
103 return "";
104 }
105 return m_UndoStack.back()->GetDescription();
106 }
107
109 {
110 if (m_RedoStack.empty())
111 {
112 return "";
113 }
114 return m_RedoStack.back()->GetDescription();
115 }
116
117 std::vector<std::string> CommandStack::GetUndoStackDescriptions() const
118 {
119 std::vector<std::string> descriptions;
120 for (const auto& cmd : m_UndoStack)
121 {
122 descriptions.push_back(cmd->GetDescription());
123 }
124 return descriptions;
125 }
126
127 std::vector<std::string> CommandStack::GetRedoStackDescriptions() const
128 {
129 std::vector<std::string> descriptions;
130 for (const auto& cmd : m_RedoStack)
131 {
132 descriptions.push_back(cmd->GetDescription());
133 }
134 return descriptions;
135 }
136
138 {
139 m_UndoStack.clear();
140 m_RedoStack.clear();
141 }
142
143 // ========================================================================
144 // CreateNodeCommand Implementation
145 // ========================================================================
146
147 CreateNodeCommand::CreateNodeCommand(const std::string& graphId,
148 const std::string& nodeType,
149 float posX, float posY,
150 const std::string& nodeName)
151 : m_GraphId(graphId)
152 , m_NodeType(nodeType)
153 , m_NodeName(nodeName)
154 , m_PosX(posX)
155 , m_PosY(posY)
156 , m_CreatedNodeId(-1)
157 {
158 }
159
161 {
162 // Get the graph
164 if (!graph)
165 {
166 std::cerr << "CreateNodeCommand: Graph not found: " << m_GraphId << std::endl;
167 return;
168 }
169
170 // Create the node
172 m_CreatedNodeId = graph->CreateNode(type, m_PosX, m_PosY, m_NodeName);
173 }
174
176 {
177 // Get the graph
179 if (!graph)
180 {
181 std::cerr << "CreateNodeCommand::Undo: Graph not found: " << m_GraphId << std::endl;
182 return;
183 }
184
185 // Delete the created node
186 if (m_CreatedNodeId != -1)
187 {
189 }
190 }
191
193 {
194 return "Create " + m_NodeType + " Node";
195 }
196
197 // ========================================================================
198 // DeleteNodeCommand Implementation
199 // ========================================================================
200
201 DeleteNodeCommand::DeleteNodeCommand(const std::string& graphId, int nodeId)
202 : m_GraphId(graphId)
203 , m_NodeId(nodeId)
204 {
205 }
206
208 {
209 // Get the graph
211 if (!graph)
212 {
213 std::cerr << "DeleteNodeCommand: Graph not found: " << m_GraphId << std::endl;
214 return;
215 }
216
217 // Save node data for undo
218 const GraphNode* node = graph->GetNode(m_NodeId);
219 if (node)
220 {
221 m_NodeData = json::object();
222 m_NodeData["id"] = node->id;
223 m_NodeData["type"] = NodeTypeToString(node->type);
224 m_NodeData["name"] = node->name;
225 m_NodeData["posX"] = node->posX;
226 m_NodeData["posY"] = node->posY;
227 // TODO: Save additional node data as needed
228 }
229
230 // Delete the node
231 graph->DeleteNode(m_NodeId);
232 }
233
235 {
236 // Get the graph
237 NodeGraph* graph = NodeGraphManager::Get().GetGraph(std::stoi(m_GraphId));
238 if (!graph)
239 {
240 std::cerr << "DeleteNodeCommand::Undo: Graph not found: " << m_GraphId << std::endl;
241 return;
242 }
243
244 // Recreate the node from saved data
245 if (m_NodeData.contains("type") && m_NodeData.contains("posX") && m_NodeData.contains("posY"))
246 {
248 std::string name = m_NodeData.contains("name") ? m_NodeData["name"].get<std::string>() : "";
249
250 int nodeId = graph->CreateNode(type,
251 m_NodeData["posX"].get<float>(),
252 m_NodeData["posY"].get<float>(),
253 name);
254
255 // TODO: Restore additional node properties
256 }
257 }
258
259 std::string DeleteNodeCommand::GetDescription() const
260 {
261 return "Delete Node " + std::to_string(m_NodeId);
262 }
263
264 // ========================================================================
265 // MoveNodeCommand Implementation
266 // ========================================================================
267
268 MoveNodeCommand::MoveNodeCommand(const std::string& graphId, int nodeId,
269 float oldX, float oldY, float newX, float newY)
270 : m_GraphId(graphId)
271 , m_NodeId(nodeId)
272 , m_OldX(oldX)
273 , m_OldY(oldY)
274 , m_NewX(newX)
275 , m_NewY(newY)
276 {
277 }
278
280 {
281 // Get the graph
283 if (!graph)
284 {
285 return;
286 }
287
288 // Move the node
289 GraphNode* node = graph->GetNode(m_NodeId);
290 if (node)
291 {
292 node->posX = m_NewX;
293 node->posY = m_NewY;
294 }
295 }
296
298 {
299 // Get the graph
300 NodeGraph* graph = NodeGraphManager::Get().GetGraph(std::stoi(m_GraphId));
301 if (!graph)
302 {
303 return;
304 }
305
306 // Restore old position
307 GraphNode* node = graph->GetNode(m_NodeId);
308 if (node)
309 {
310 node->posX = m_OldX;
311 node->posY = m_OldY;
312 }
313 }
314
315 std::string MoveNodeCommand::GetDescription() const
316 {
317 return "Move Node " + std::to_string(m_NodeId);
318 }
319
320 // ========================================================================
321 // LinkNodesCommand Implementation
322 // ========================================================================
323
324 LinkNodesCommand::LinkNodesCommand(const std::string& graphId, int parentId, int childId)
325 : m_GraphId(graphId)
326 , m_ParentId(parentId)
327 , m_ChildId(childId)
328 {
329 }
330
332 {
334 if (graph)
335 {
337 }
338 }
339
341 {
343 if (graph)
344 {
346 }
347 }
348
350 {
351 return "Link Nodes " + std::to_string(m_ParentId) + " -> " + std::to_string(m_ChildId);
352 }
353
354 // ========================================================================
355 // UnlinkNodesCommand Implementation
356 // ========================================================================
357
358 UnlinkNodesCommand::UnlinkNodesCommand(const std::string& graphId, int parentId, int childId)
359 : m_GraphId(graphId)
360 , m_ParentId(parentId)
361 , m_ChildId(childId)
362 {
363 }
364
366 {
368 if (graph)
369 {
371 }
372 }
373
375 {
377 if (graph)
378 {
380 }
381 }
382
384 {
385 return "Unlink Nodes " + std::to_string(m_ParentId) + " -> " + std::to_string(m_ChildId);
386 }
387
388 // ========================================================================
389 // SetParameterCommand Implementation
390 // ========================================================================
391
392 SetParameterCommand::SetParameterCommand(const std::string& graphId, int nodeId,
393 const std::string& paramName,
394 const std::string& oldValue,
395 const std::string& newValue)
396 : m_GraphId(graphId)
397 , m_NodeId(nodeId)
398 , m_ParamName(paramName)
399 , m_OldValue(oldValue)
400 , m_NewValue(newValue)
401 {
402 }
403
412
421
423 {
424 return "Set " + m_ParamName + " = " + m_NewValue;
425 }
426
427 // ========================================================================
428 // DuplicateNodeCommand Implementation
429 // ========================================================================
430
432 : m_GraphId(graphId)
433 , m_SourceNodeId(sourceNodeId)
434 , m_CreatedNodeId(-1)
435 {
436 }
437
439 {
441 if (!graph)
442 {
443 std::cerr << "DuplicateNodeCommand: Graph not found: " << m_GraphId << std::endl;
444 return;
445 }
446
447 // Get source node
448 const GraphNode* sourceNode = graph->GetNode(m_SourceNodeId);
449 if (!sourceNode)
450 {
451 std::cerr << "DuplicateNodeCommand: Source node not found: " << m_SourceNodeId << std::endl;
452 return;
453 }
454
455 // Create a duplicate node at an offset position
456 m_CreatedNodeId = graph->CreateNode(sourceNode->type,
457 sourceNode->posX + 50.0f,
458 sourceNode->posY + 50.0f,
459 sourceNode->name + " Copy");
460
462 if (newNode)
463 {
464 // Copy all properties
465 newNode->actionType = sourceNode->actionType;
466 newNode->conditionType = sourceNode->conditionType;
467 newNode->decoratorType = sourceNode->decoratorType;
468 newNode->parameters = sourceNode->parameters;
469
470 // Save node data for undo
471 m_NodeData = json::object();
472 m_NodeData["id"] = newNode->id;
473 m_NodeData["type"] = NodeTypeToString(newNode->type);
474 m_NodeData["name"] = newNode->name;
475 }
476
477 std::cout << "Duplicated node " << m_SourceNodeId << " to " << m_CreatedNodeId << std::endl;
478 }
479
481 {
483 if (!graph)
484 {
485 return;
486 }
487
488 // Delete the created node
489 if (m_CreatedNodeId >= 0)
490 {
492 }
493 }
494
496 {
497 return "Duplicate Node " + std::to_string(m_SourceNodeId);
498 }
499
500 // ========================================================================
501 // EditNodeCommand Implementation
502 // ========================================================================
503
504 EditNodeCommand::EditNodeCommand(const std::string& graphId, int nodeId,
505 const std::string& oldName, const std::string& newName,
506 const std::string& oldSubtype, const std::string& newSubtype)
507 : m_GraphId(graphId)
508 , m_NodeId(nodeId)
509 , m_OldName(oldName)
510 , m_NewName(newName)
511 , m_OldSubtype(oldSubtype)
512 , m_NewSubtype(newSubtype)
513 {
514 }
515
517 {
519 if (!graph)
520 {
521 return;
522 }
523
524 GraphNode* node = graph->GetNode(m_NodeId);
525 if (node)
526 {
528
529 // Update subtype based on node type
530 if (node->type == NodeType::BT_Action)
531 {
532 node->actionType = m_NewSubtype;
533 }
534 else if (node->type == NodeType::BT_Condition)
535 {
536 node->conditionType = m_NewSubtype;
537 }
538 else if (node->type == NodeType::BT_Decorator)
539 {
540 node->decoratorType = m_NewSubtype;
541 }
542 }
543 }
544
546 {
548 if (!graph)
549 {
550 return;
551 }
552
553 GraphNode* node = graph->GetNode(m_NodeId);
554 if (node)
555 {
557
558 // Restore old subtype
559 if (node->type == NodeType::BT_Action)
560 {
561 node->actionType = m_OldSubtype;
562 }
563 else if (node->type == NodeType::BT_Condition)
564 {
565 node->conditionType = m_OldSubtype;
566 }
567 else if (node->type == NodeType::BT_Decorator)
568 {
569 node->decoratorType = m_OldSubtype;
570 }
571 }
572 }
573
575 {
576 return "Edit Node " + std::to_string(m_NodeId);
577 }
578}
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
std::string GetNextRedoDescription() const
std::vector< std::unique_ptr< EditorCommand > > m_UndoStack
std::vector< std::string > GetRedoStackDescriptions() const
std::vector< std::unique_ptr< EditorCommand > > m_RedoStack
const EditorCommand * GetLastCommand() const
void ExecuteCommand(std::unique_ptr< EditorCommand > cmd)
std::string GetLastCommandDescription() const
std::vector< std::string > GetUndoStackDescriptions() const
std::string GetDescription() const override
CreateNodeCommand(const std::string &graphId, const std::string &nodeType, float posX, float posY, const std::string &nodeName="")
void Undo() override
Undo the command.
void Execute() override
Execute the command.
std::string GetDescription() const override
Get a human-readable description of the command.
DeleteNodeCommand(BehaviorTreeAsset *tree, uint32_t nodeId)
std::string GetDescription() const override
DuplicateNodeCommand(const std::string &graphId, int sourceNodeId)
std::string GetDescription() const override
EditNodeCommand(const std::string &graphId, int nodeId, const std::string &oldName, const std::string &newName, const std::string &oldSubtype, const std::string &newSubtype)
EditorCommand - Base class for all undoable editor commands Implements command pattern for undo/redo ...
virtual std::string GetDescription() const =0
std::string GetDescription() const override
LinkNodesCommand(const std::string &graphId, int parentId, int childId)
std::string GetDescription() const override
Get a human-readable description of the command.
void Undo() override
Undo the command.
MoveNodeCommand(BehaviorTreeAsset *tree, uint32_t nodeId, const Vector &oldPos, const Vector &newPos)
void Execute() override
Execute the command.
NodeGraph * GetGraph(int graphId)
static NodeGraphManager & Get()
bool UnlinkNodes(int parentId, int childId)
bool DeleteNode(int nodeId)
bool LinkNodes(int parentId, int childId)
bool SetNodeParameter(int nodeId, const std::string &paramName, const std::string &value)
std::string GetDescription() const override
SetParameterCommand(const std::string &graphId, int nodeId, const std::string &paramName, const std::string &oldValue, const std::string &newValue)
std::string GetDescription() const override
UnlinkNodesCommand(const std::string &graphId, int parentId, int childId)
const char * NodeTypeToString(NodeType type)
NodeType StringToNodeType(const std::string &str)