From 16d34c647885ed3a56f800a711a3a019d1c29393 Mon Sep 17 00:00:00 2001 From: SHAM-DP Date: Wed, 28 Dec 2022 21:23:34 +0800 Subject: [PATCH] Added Copy/Paste of Component Values - Command should fail if deserialization fails --- .gitignore | 4 + .../src/Editor/Command/SHCommandManager.cpp | 14 +- .../src/Editor/Command/SHCommandManager.h | 3 +- .../Inspector/SHEditorComponentView.hpp | 8 +- .../Inspector/SHInspectorCommands.h | 27 ++++ .../Inspector/SHInspectorCommands.hpp | 26 ++++ .../src/Serialization/SHSerialization.cpp | 42 +++--- .../Serialization/SHSerializationHelper.hpp | 131 +++++++++++++----- .../src/Serialization/SHYAMLConverters.h | 10 ++ 9 files changed, 197 insertions(+), 68 deletions(-) create mode 100644 SHADE_Engine/src/Editor/EditorWindow/Inspector/SHInspectorCommands.h create mode 100644 SHADE_Engine/src/Editor/EditorWindow/Inspector/SHInspectorCommands.hpp diff --git a/.gitignore b/.gitignore index 5d998cfd..06ae45fd 100644 --- a/.gitignore +++ b/.gitignore @@ -364,3 +364,7 @@ MigrationBackup/ *.filters Assets/Editor/Layouts/UserLayout.ini + +JSON/Schemas/Catalog/ + +Assets/Editor/Editor.SHConfig diff --git a/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp b/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp index b86f9247..fec30142 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp +++ b/SHADE_Engine/src/Editor/Command/SHCommandManager.cpp @@ -18,11 +18,17 @@ namespace SHADE SHCommandManager::CommandStackPtr SHCommandManager::pCurrUndoStack(&undoStack); SHCommandManager::CommandStackPtr SHCommandManager::pCurrRedoStack(&redoStack); + bool SHCommandManager::failedExecution(false); void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue) { - *pCurrRedoStack = CommandStack(defaultStackSize); commandPtr->Execute(); + if(failedExecution) + { + failedExecution = false; + return; + } + *pCurrRedoStack = CommandStack(defaultStackSize); if (overrideValue && !pCurrUndoStack->Empty()) { pCurrUndoStack->Top()->Merge(commandPtr); @@ -68,12 +74,14 @@ namespace SHADE void SHCommandManager::PopLatestCommandFromRedoStack() { - pCurrRedoStack->Pop(); + if(!pCurrRedoStack->Empty()) + pCurrRedoStack->Pop(); } void SHCommandManager::PopLatestCommandFromUndoStack() { - pCurrUndoStack->Pop(); + if(!pCurrUndoStack->Empty()) + pCurrUndoStack->Pop(); } void SHCommandManager::SwapStacks() diff --git a/SHADE_Engine/src/Editor/Command/SHCommandManager.h b/SHADE_Engine/src/Editor/Command/SHCommandManager.h index 178347b5..f3574030 100644 --- a/SHADE_Engine/src/Editor/Command/SHCommandManager.h +++ b/SHADE_Engine/src/Editor/Command/SHCommandManager.h @@ -38,7 +38,8 @@ namespace SHADE static void SwapStacks(); static void ClearAll(); - + + static bool failedExecution; static constexpr CommandStack::SizeType defaultStackSize = 100; private: static CommandStackPtr pCurrUndoStack; diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp index e4ec8d58..45964930 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorComponentView.hpp @@ -19,6 +19,9 @@ #include "Reflection/SHReflectionMetadata.h" #include "Resource/SHResourceManager.h" #include "Physics/Collision/SHCollisionTagMatrix.h" +#include "Serialization/SHSerializationHelper.hpp" +#include "Tools/Utilities/SHClipboardUtilities.h" +#include "SHInspectorCommands.h" namespace SHADE { template @@ -46,11 +49,12 @@ namespace SHADE if (ImGui::Selectable(std::format("{} Copy {}", ICON_MD_CONTENT_COPY, componentName.data()).data())) { - //SHClipboardUtil::WriteStringToClipboard(SHClipboardUtil::CFNAME::CFCOMPONENT, SHComponentToString(component)); + SHClipboardUtilities::WriteToClipboard(SHSerializationHelper::SerializeComponentToString(component->GetEID())); } if (ImGui::Selectable(std::format("{} Paste {}", ICON_MD_CONTENT_PASTE, componentName.data()).data())) { - //SHStringToComponent(component, SHClipboardUtil::ReadStringFromClipboard(SHClipboardUtil::CFNAME::CFCOMPONENT)); + //SHSerializationHelper::DeserializeComponentFromString(SHClipboardUtilities::GetDataFromClipboard(), component->GetEID()); + SHCommandManager::PerformCommand(std::reinterpret_pointer_cast( std::make_shared>(component->GetEID(), SHClipboardUtilities::GetDataFromClipboard()))); } if (ImGui::Selectable(std::format("{} Delete {}", ICON_MD_DELETE, componentName.data()).data())) { diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHInspectorCommands.h b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHInspectorCommands.h new file mode 100644 index 00000000..72e2a2e3 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHInspectorCommands.h @@ -0,0 +1,27 @@ +#pragma once +#include "Editor/Command/SHCommand.hpp" + +namespace SHADE +{ + template + class SHPasteComponentCommand final : SHBaseCommand + { + public: + struct Data + { + EntityID eid; + std::string oldComponentData; + std::string newComponentData; + }; + + SHPasteComponentCommand(EntityID eid, std::string const& newComponentData); + + void Execute() override; + void Undo() override; + + private: + Data data; + }; +} + +#include "SHInspectorCommands.hpp" \ No newline at end of file diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHInspectorCommands.hpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHInspectorCommands.hpp new file mode 100644 index 00000000..da006218 --- /dev/null +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHInspectorCommands.hpp @@ -0,0 +1,26 @@ +#pragma once +#include "SHInspectorCommands.h" + +namespace SHADE +{ + template + SHPasteComponentCommand::SHPasteComponentCommand(EntityID eid, std::string const& newComponentData) + :data(eid, {}, newComponentData) + { + data.oldComponentData = SHSerializationHelper::SerializeComponentToString(eid); + } + + template + void SHPasteComponentCommand::Execute() + { + bool result = SHSerializationHelper::DeserializeComponentFromString(data.newComponentData, data.eid); + if(!result) + SHCommandManager::failedExecution = true; + } + + template + void SHPasteComponentCommand::Undo() + { + SHSerializationHelper::DeserializeComponentFromString(data.oldComponentData, data.eid); + } +} \ No newline at end of file diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 99e4fa41..753f2def 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -169,25 +169,15 @@ namespace SHADE //} template, bool> = true> - static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) - { - if (const ComponentType* component = SHComponentManager::GetComponent_s(eid)) - { - componentsNode[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(component); - } - } - - template, bool> = true> - static void AddConvComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) - { - if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) - { - auto componentNode = YAML::convert::encode(*component); - componentNode[IsActive.data()] = component->isActive; - componentsNode[rttr::type::get().get_name().data()] = componentNode; - } - } - + static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) + { + YAML::Node node{}; + if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) + { + node = SHSerializationHelper::SerializeComponentToNode(component); + } + componentsNode[rttr::type::get().get_name().data()] = node; + } YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode) { @@ -211,15 +201,15 @@ namespace SHADE AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); - AddConvComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); - AddConvComponentToComponentNode(components, eid); - + AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); - AddConvComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); node[ComponentsNode] = components; @@ -351,12 +341,12 @@ namespace SHADE SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); - SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); - SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); - SHSerializationHelper::ConvertNodeToComponent(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); } } diff --git a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp index b560acae..624f94e2 100644 --- a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp +++ b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp @@ -103,12 +103,6 @@ namespace SHADE return node; } - template , bool> = true> - static std::string SerializeComponentToString(ComponentType* component) - { - return std::string(); - } - template , bool> = true> static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) { @@ -117,14 +111,29 @@ namespace SHADE template , bool> = true> static YAML::Node SerializeComponentToNode(ComponentType* component) { - YAML::Node node{}; - if (!component) - return node; - auto componentType = rttr::type::get(); - node = RTTRToNode(*component); - node[IsActive.data()] = component->isActive; + if constexpr (YAML::HasYAMLConv()) + { + if (component) + { + auto componentNode = YAML::convert::encode(*component); + componentNode[IsActive.data()] = component->isActive; + return componentNode; + } + } + else + { + if (component) + { + YAML::Node compNode{}; + if (!component) + return compNode; + auto componentType = rttr::type::get(); + compNode = RTTRToNode(*component); + compNode[IsActive.data()] = component->isActive; + return compNode; - return node; + } + } } template @@ -191,26 +200,43 @@ namespace SHADE } template , bool> = true> - static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) + static bool InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) { - ComponentType* component = SHComponentManager::GetComponent_s(eid); - if (componentsNode.IsNull() && !component) - return; - auto rttrType = rttr::type::get(); - auto componentNode = componentsNode[rttrType.get_name().data()]; - if (!componentNode.IsDefined()) - return; - if(componentNode[IsActive.data()].IsDefined()) - component->isActive = componentNode[IsActive.data()].as(); - - auto properties = rttrType.get_properties(); - for (auto const& prop : properties) + if constexpr (YAML::HasYAMLConv()) { - if (componentNode[prop.get_name().data()].IsDefined()) + auto component = SHComponentManager::GetComponent_s(eid); + if (componentsNode.IsNull() || !component) + return false; + auto componentNode = GetComponentNode(componentsNode, eid); + if (componentNode.IsNull() || !componentNode.IsDefined()) + return false; + if (componentNode[IsActive.data()].IsDefined()) + component->isActive = componentNode[IsActive.data()].as(); + YAML::convert::decode(componentNode, *component); + return true; + } + else + { + ComponentType* component = SHComponentManager::GetComponent_s(eid); + if (componentsNode.IsNull() && !component) + return false; + auto rttrType = rttr::type::get(); + auto componentNode = componentsNode[rttrType.get_name().data()]; + if (!componentNode.IsDefined()) + return false; + if (componentNode[IsActive.data()].IsDefined()) + component->isActive = componentNode[IsActive.data()].as(); + + auto properties = rttrType.get_properties(); + for (auto const& prop : properties) { - InitializeProperty(component, prop, componentNode[prop.get_name().data()]); + if (componentNode[prop.get_name().data()].IsDefined()) + { + InitializeProperty(component, prop, componentNode[prop.get_name().data()]); + } } } + return true; } template , bool> = true> @@ -226,16 +252,49 @@ namespace SHADE return componentNode; } + //template, bool> = true> + //static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) + //{ + // if constexpr (YAML::HasYAMLConv()) + // { + // if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) + // { + // auto componentNode = YAML::convert::encode(*component); + // componentNode[IsActive.data()] = component->isActive; + // componentsNode[rttr::type::get().get_name().data()] = componentNode; + // } + // } + // else + // { + // if (const ComponentType* component = SHComponentManager::GetComponent_s(eid)) + // { + // componentsNode[rttr::type::get().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(component); + // } + // } + + //} + template , bool> = true> - static void ConvertNodeToComponent(YAML::Node const& componentsNode, EntityID const& eid) + static std::string SerializeComponentToString(EntityID const& eid) { - auto component = SHComponentManager::GetComponent_s(eid); - if (componentsNode.IsNull() && !component) - return; - auto componentNode = GetComponentNode(componentsNode, eid); - if (componentNode[IsActive.data()].IsDefined()) - component->isActive = componentNode[IsActive.data()].as(); - YAML::convert::decode(componentNode, *component); + if (ComponentType* component = SHComponentManager::GetComponent_s(eid)) + { + YAML::Emitter out; + YAML::Node node{}; + + node[rttr::type::get().get_name().data()] = SerializeComponentToNode(component); + out << node; + + return out.c_str(); + } + return std::string(); + } + + template , bool> = true> + static bool DeserializeComponentFromString(std::string data, EntityID const& eid) + { + YAML::Node node = YAML::Load(data); + return InitializeComponentFromNode(node, eid); } template , bool> = true> diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h index efb49c4b..58268b57 100644 --- a/SHADE_Engine/src/Serialization/SHYAMLConverters.h +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -20,6 +20,16 @@ namespace YAML { using namespace SHADE; + template + struct HasYAMLConv : std::false_type{}; + + template<> + struct HasYAMLConv : std::true_type {}; + template<> + struct HasYAMLConv : std::true_type {}; + template<> + struct HasYAMLConv : std::true_type {}; + template<> struct convert {