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