Added Copy/Paste of Component Values

- Command should fail if deserialization fails
This commit is contained in:
SHAM-DP 2022-12-28 21:23:34 +08:00
parent 51c9058ab8
commit 16d34c6478
9 changed files with 197 additions and 68 deletions

4
.gitignore vendored
View File

@ -364,3 +364,7 @@ MigrationBackup/
*.filters *.filters
Assets/Editor/Layouts/UserLayout.ini Assets/Editor/Layouts/UserLayout.ini
JSON/Schemas/Catalog/
Assets/Editor/Editor.SHConfig

View File

@ -18,11 +18,17 @@ namespace SHADE
SHCommandManager::CommandStackPtr SHCommandManager::pCurrUndoStack(&undoStack); SHCommandManager::CommandStackPtr SHCommandManager::pCurrUndoStack(&undoStack);
SHCommandManager::CommandStackPtr SHCommandManager::pCurrRedoStack(&redoStack); SHCommandManager::CommandStackPtr SHCommandManager::pCurrRedoStack(&redoStack);
bool SHCommandManager::failedExecution(false);
void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue) void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue)
{ {
*pCurrRedoStack = CommandStack(defaultStackSize);
commandPtr->Execute(); commandPtr->Execute();
if(failedExecution)
{
failedExecution = false;
return;
}
*pCurrRedoStack = CommandStack(defaultStackSize);
if (overrideValue && !pCurrUndoStack->Empty()) if (overrideValue && !pCurrUndoStack->Empty())
{ {
pCurrUndoStack->Top()->Merge(commandPtr); pCurrUndoStack->Top()->Merge(commandPtr);
@ -68,11 +74,13 @@ namespace SHADE
void SHCommandManager::PopLatestCommandFromRedoStack() void SHCommandManager::PopLatestCommandFromRedoStack()
{ {
if(!pCurrRedoStack->Empty())
pCurrRedoStack->Pop(); pCurrRedoStack->Pop();
} }
void SHCommandManager::PopLatestCommandFromUndoStack() void SHCommandManager::PopLatestCommandFromUndoStack()
{ {
if(!pCurrUndoStack->Empty())
pCurrUndoStack->Pop(); pCurrUndoStack->Pop();
} }

View File

@ -39,6 +39,7 @@ namespace SHADE
static void SwapStacks(); static void SwapStacks();
static void ClearAll(); static void ClearAll();
static bool failedExecution;
static constexpr CommandStack::SizeType defaultStackSize = 100; static constexpr CommandStack::SizeType defaultStackSize = 100;
private: private:
static CommandStackPtr pCurrUndoStack; static CommandStackPtr pCurrUndoStack;

View File

@ -19,6 +19,9 @@
#include "Reflection/SHReflectionMetadata.h" #include "Reflection/SHReflectionMetadata.h"
#include "Resource/SHResourceManager.h" #include "Resource/SHResourceManager.h"
#include "Physics/Collision/SHCollisionTagMatrix.h" #include "Physics/Collision/SHCollisionTagMatrix.h"
#include "Serialization/SHSerializationHelper.hpp"
#include "Tools/Utilities/SHClipboardUtilities.h"
#include "SHInspectorCommands.h"
namespace SHADE namespace SHADE
{ {
template<typename T> template<typename T>
@ -46,11 +49,12 @@ namespace SHADE
if (ImGui::Selectable(std::format("{} Copy {}", ICON_MD_CONTENT_COPY, componentName.data()).data())) if (ImGui::Selectable(std::format("{} Copy {}", ICON_MD_CONTENT_COPY, componentName.data()).data()))
{ {
//SHClipboardUtil::WriteStringToClipboard(SHClipboardUtil::CFNAME::CFCOMPONENT, SHComponentToString(component)); SHClipboardUtilities::WriteToClipboard(SHSerializationHelper::SerializeComponentToString<T>(component->GetEID()));
} }
if (ImGui::Selectable(std::format("{} Paste {}", ICON_MD_CONTENT_PASTE, componentName.data()).data())) if (ImGui::Selectable(std::format("{} Paste {}", ICON_MD_CONTENT_PASTE, componentName.data()).data()))
{ {
//SHStringToComponent(component, SHClipboardUtil::ReadStringFromClipboard(SHClipboardUtil::CFNAME::CFCOMPONENT)); //SHSerializationHelper::DeserializeComponentFromString<T>(SHClipboardUtilities::GetDataFromClipboard(), component->GetEID());
SHCommandManager::PerformCommand(std::reinterpret_pointer_cast<SHBaseCommand>( std::make_shared<SHPasteComponentCommand<T>>(component->GetEID(), SHClipboardUtilities::GetDataFromClipboard())));
} }
if (ImGui::Selectable(std::format("{} Delete {}", ICON_MD_DELETE, componentName.data()).data())) if (ImGui::Selectable(std::format("{} Delete {}", ICON_MD_DELETE, componentName.data()).data()))
{ {

View File

@ -0,0 +1,27 @@
#pragma once
#include "Editor/Command/SHCommand.hpp"
namespace SHADE
{
template<typename T>
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"

View File

@ -0,0 +1,26 @@
#pragma once
#include "SHInspectorCommands.h"
namespace SHADE
{
template<typename T>
SHPasteComponentCommand<T>::SHPasteComponentCommand(EntityID eid, std::string const& newComponentData)
:data(eid, {}, newComponentData)
{
data.oldComponentData = SHSerializationHelper::SerializeComponentToString<T>(eid);
}
template<typename T>
void SHPasteComponentCommand<T>::Execute()
{
bool result = SHSerializationHelper::DeserializeComponentFromString<T>(data.newComponentData, data.eid);
if(!result)
SHCommandManager::failedExecution = true;
}
template<typename T>
void SHPasteComponentCommand<T>::Undo()
{
SHSerializationHelper::DeserializeComponentFromString<T>(data.oldComponentData, data.eid);
}
}

View File

@ -171,24 +171,14 @@ namespace SHADE
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid)
{ {
if (const ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid)) YAML::Node node{};
{
componentsNode[rttr::type::get<ComponentType>().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(component);
}
}
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void AddConvComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid)
{
if (ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid)) if (ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid))
{ {
auto componentNode = YAML::convert<ComponentType>::encode(*component); node = SHSerializationHelper::SerializeComponentToNode(component);
componentNode[IsActive.data()] = component->isActive;
componentsNode[rttr::type::get<ComponentType>().get_name().data()] = componentNode;
} }
componentsNode[rttr::type::get<ComponentType>().get_name().data()] = node;
} }
YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode) YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode)
{ {
YAML::Node node; YAML::Node node;
@ -211,15 +201,15 @@ namespace SHADE
AddComponentToComponentNode<SHTransformComponent>(components, eid); AddComponentToComponentNode<SHTransformComponent>(components, eid);
AddComponentToComponentNode<SHCameraComponent>(components, eid); AddComponentToComponentNode<SHCameraComponent>(components, eid);
AddComponentToComponentNode<SHCameraArmComponent>(components, eid); AddComponentToComponentNode<SHCameraArmComponent>(components, eid);
AddConvComponentToComponentNode<SHRenderable>(components, eid); AddComponentToComponentNode<SHRenderable>(components, eid);
AddComponentToComponentNode<SHLightComponent>(components, eid); AddComponentToComponentNode<SHLightComponent>(components, eid);
AddComponentToComponentNode<SHRigidBodyComponent>(components, eid); AddComponentToComponentNode<SHRigidBodyComponent>(components, eid);
AddConvComponentToComponentNode<SHColliderComponent>(components, eid); AddComponentToComponentNode<SHColliderComponent>(components, eid);
AddComponentToComponentNode<SHCanvasComponent>(components, eid); AddComponentToComponentNode<SHCanvasComponent>(components, eid);
AddComponentToComponentNode<SHButtonComponent>(components, eid); AddComponentToComponentNode<SHButtonComponent>(components, eid);
AddConvComponentToComponentNode<SHTextRenderableComponent>(components, eid); AddComponentToComponentNode<SHTextRenderableComponent>(components, eid);
node[ComponentsNode] = components; node[ComponentsNode] = components;
@ -351,12 +341,12 @@ namespace SHADE
SHSerializationHelper::InitializeComponentFromNode<SHCameraComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHCameraComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHCameraArmComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHCameraArmComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHRigidBodyComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHRigidBodyComponent>(componentsNode, eid);
SHSerializationHelper::ConvertNodeToComponent<SHRenderable>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHRenderable>(componentsNode, eid);
SHSerializationHelper::ConvertNodeToComponent<SHColliderComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHColliderComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHCanvasComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHCanvasComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHButtonComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHButtonComponent>(componentsNode, eid);
SHSerializationHelper::ConvertNodeToComponent<SHTextRenderableComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHTextRenderableComponent>(componentsNode, eid);
SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode<SHLightComponent>(componentsNode, eid);
} }
} }

View File

@ -103,12 +103,6 @@ namespace SHADE
return node; return node;
} }
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static std::string SerializeComponentToString(ComponentType* component)
{
return std::string();
}
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path) static void SerializeComponentToFile(ComponentType* component, std::filesystem::path const& path)
{ {
@ -117,14 +111,29 @@ namespace SHADE
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static YAML::Node SerializeComponentToNode(ComponentType* component) static YAML::Node SerializeComponentToNode(ComponentType* component)
{ {
YAML::Node node{}; if constexpr (YAML::HasYAMLConv<ComponentType>())
{
if (component)
{
auto componentNode = YAML::convert<ComponentType>::encode(*component);
componentNode[IsActive.data()] = component->isActive;
return componentNode;
}
}
else
{
if (component)
{
YAML::Node compNode{};
if (!component) if (!component)
return node; return compNode;
auto componentType = rttr::type::get<ComponentType>(); auto componentType = rttr::type::get<ComponentType>();
node = RTTRToNode(*component); compNode = RTTRToNode(*component);
node[IsActive.data()] = component->isActive; compNode[IsActive.data()] = component->isActive;
return compNode;
return node; }
}
} }
template <typename Type> template <typename Type>
@ -191,16 +200,31 @@ namespace SHADE
} }
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid) static bool InitializeComponentFromNode(YAML::Node const& componentsNode, EntityID const& eid)
{
if constexpr (YAML::HasYAMLConv<ComponentType>())
{
auto component = SHComponentManager::GetComponent_s<ComponentType>(eid);
if (componentsNode.IsNull() || !component)
return false;
auto componentNode = GetComponentNode<ComponentType>(componentsNode, eid);
if (componentNode.IsNull() || !componentNode.IsDefined())
return false;
if (componentNode[IsActive.data()].IsDefined())
component->isActive = componentNode[IsActive.data()].as<bool>();
YAML::convert<ComponentType>::decode(componentNode, *component);
return true;
}
else
{ {
ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid); ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid);
if (componentsNode.IsNull() && !component) if (componentsNode.IsNull() && !component)
return; return false;
auto rttrType = rttr::type::get<ComponentType>(); auto rttrType = rttr::type::get<ComponentType>();
auto componentNode = componentsNode[rttrType.get_name().data()]; auto componentNode = componentsNode[rttrType.get_name().data()];
if (!componentNode.IsDefined()) if (!componentNode.IsDefined())
return; return false;
if(componentNode[IsActive.data()].IsDefined()) if (componentNode[IsActive.data()].IsDefined())
component->isActive = componentNode[IsActive.data()].as<bool>(); component->isActive = componentNode[IsActive.data()].as<bool>();
auto properties = rttrType.get_properties(); auto properties = rttrType.get_properties();
@ -212,6 +236,8 @@ namespace SHADE
} }
} }
} }
return true;
}
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static YAML::Node GetComponentNode(YAML::Node const& componentsNode, EntityID const& eid) static YAML::Node GetComponentNode(YAML::Node const& componentsNode, EntityID const& eid)
@ -226,16 +252,49 @@ namespace SHADE
return componentNode; return componentNode;
} }
//template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
//static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid)
//{
// if constexpr (YAML::HasYAMLConv<ComponentType>())
// {
// if (ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid))
// {
// auto componentNode = YAML::convert<ComponentType>::encode(*component);
// componentNode[IsActive.data()] = component->isActive;
// componentsNode[rttr::type::get<ComponentType>().get_name().data()] = componentNode;
// }
// }
// else
// {
// if (const ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid))
// {
// componentsNode[rttr::type::get<ComponentType>().get_name().data()] = SHSerializationHelper::SerializeComponentToNode(component);
// }
// }
//}
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void ConvertNodeToComponent(YAML::Node const& componentsNode, EntityID const& eid) static std::string SerializeComponentToString(EntityID const& eid)
{ {
auto component = SHComponentManager::GetComponent_s<ComponentType>(eid); if (ComponentType* component = SHComponentManager::GetComponent_s<ComponentType>(eid))
if (componentsNode.IsNull() && !component) {
return; YAML::Emitter out;
auto componentNode = GetComponentNode<ComponentType>(componentsNode, eid); YAML::Node node{};
if (componentNode[IsActive.data()].IsDefined())
component->isActive = componentNode[IsActive.data()].as<bool>(); node[rttr::type::get<ComponentType>().get_name().data()] = SerializeComponentToNode(component);
YAML::convert<ComponentType>::decode(componentNode, *component); out << node;
return out.c_str();
}
return std::string();
}
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static bool DeserializeComponentFromString(std::string data, EntityID const& eid)
{
YAML::Node node = YAML::Load(data);
return InitializeComponentFromNode<ComponentType>(node, eid);
} }
template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template <typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>

View File

@ -20,6 +20,16 @@ namespace YAML
{ {
using namespace SHADE; using namespace SHADE;
template<typename T>
struct HasYAMLConv : std::false_type{};
template<>
struct HasYAMLConv<SHColliderComponent> : std::true_type {};
template<>
struct HasYAMLConv<SHRenderable> : std::true_type {};
template<>
struct HasYAMLConv<SHTextRenderableComponent> : std::true_type {};
template<> template<>
struct convert<SHVec4> struct convert<SHVec4>
{ {