Added rudimentary prefabs (no resolution) #367

Merged
srishamharan merged 3 commits from SP3-8-serialization into main 2023-02-27 11:53:46 +08:00
10 changed files with 292 additions and 26 deletions

View File

@ -1,4 +0,0 @@
Start Maximized: true
Working Scene ID: 97158628
Window Size: {x: 1920, y: 1013}
Style: 0

View File

@ -0,0 +1,147 @@
- EID: 0
PrefabID: 117058283
Name: ====Raccoon====
IsActive: true
NumberOfChildren: 2
Components: ~
Scripts: ~
- EID: 1
Name: Player
IsActive: true
NumberOfChildren: 3
Components:
Transform Component:
Translate: {x: 2.35245037, y: 0.38365531, z: 7.10571432}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 0.999999881, y: 1, z: 0.999999881}
IsActive: true
Renderable Component:
Mesh: 149697411
Material: 126974645
IsActive: true
RigidBody Component:
Type: Dynamic
Drag: 0.00999999978
Angular Drag: 0.100000001
Use Gravity: false
Interpolate: false
Sleeping Enabled: true
Freeze Position X: false
Freeze Position Y: true
Freeze Position Z: false
Freeze Rotation X: true
Freeze Rotation Y: true
Freeze Rotation Z: true
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 0
Type: Box
Half Extents: {x: 0.400000006, y: 0.5, z: 0.300000012}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0.25, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts:
- Type: PlayerController
Enabled: true
respawnPoint: 239
currentState: 0
maxMoveVel: 3
moveForce: 50
sprintMultiplier: 1.5
rotationFactorPerFrame: 5
maxJumpHeight: 2
maxJumpTime: 0.75
fallMultipler: 3
lightMultiper: 0.899999976
mediumMultiper: 0.699999988
heavyMultiper: 0.5
- Type: PickAndThrow
Enabled: true
throwForce: [10, 8, 10]
cameraArmOffSet: [0.25, 0.600000024, 0.200000003]
delayTimer: 1
aimingLength: 1
throwItem: false
rayDistance: 0.75
rayHeight: 0.100000001
- EID: 2
Name: HoldingPoint
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 0.899999976, z: 0.200000286}
Rotate: {x: 0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
Scripts: ~
- EID: 3
Name: PlayerCamera
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: -5.96046448e-08, z: 0}
Rotate: {x: 0, y: 6.28318548, z: 2.23517329e-08}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
Camera Component:
Position: {x: 2.12735963, y: 0.362327784, z: 7.98933029}
Pitch: 0
Yaw: 360
Roll: 1.28065994e-06
Width: 2560
Near: 0.00999999978
Far: 10000
Perspective: true
FOV: 45
IsActive: true
Camera Arm Component:
Arm Pitch: 0
Arm Yaw: 0
Arm Length: 3
Look At Camera Origin: true
Target Offset: {x: 0, y: 0.75, z: 0}
Camera Collision: true
IsActive: true
Scripts:
- Type: SHADE_Scripting.ThirdPersonCamera
Enabled: true
armLength: 3
turnSpeedPitch: 0.200000003
turnSpeedYaw: 0.400000006
pitchClamp: 45
inverseXControls: false
inverseYControls: false
lowerClamp: 5
- EID: 4
Name: PlayerBag
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: -2.98023224e-08, z: 4.76837158e-07}
Rotate: {x: 0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
Renderable Component:
Mesh: 144838771
Material: 123745521
IsActive: true
Scripts: ~
- EID: 5
Name: RespawnPoint
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 2.5, y: 0.660660267, z: 7}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
Scripts: ~

View File

@ -0,0 +1,3 @@
Name: ====Raccoon====
ID: 117058283
Type: 6

View File

@ -19,6 +19,10 @@
#include "Tools/Utilities/SHStringUtilities.h" #include "Tools/Utilities/SHStringUtilities.h"
#include <filesystem> #include <filesystem>
#include <rttr/type> #include <rttr/type>
#include "Assets/Asset Types/SHPrefabAsset.h"
#include "Serialization/SHSerialization.h"
#include <Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h>
#include "Serialization/Prefab/SHPrefabManager.h"
namespace SHADE namespace SHADE
{ {
@ -247,6 +251,7 @@ namespace SHADE
const ImRect childRect = DrawAsset(file.assetMeta, file.ext); const ImRect childRect = DrawAsset(file.assetMeta, file.ext);
return childRect; return childRect;
} }
return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
} }
ImRect SHAssetBrowser::DrawAsset(SHAsset const* const asset, FileExt const& ext /*= ""*/) noexcept ImRect SHAssetBrowser::DrawAsset(SHAsset const* const asset, FileExt const& ext /*= ""*/) noexcept
@ -365,6 +370,35 @@ namespace SHADE
} }
} }
if(ImGui::BeginPopupContextItem())
{
switch (asset->type)
{
case AssetType::INVALID: break;
case AssetType::SHADER: break;
case AssetType::SHADER_BUILT_IN: break;
case AssetType::TEXTURE: break;
case AssetType::MESH: break;
case AssetType::SCENE:
break;
case AssetType::PREFAB:
{
if(ImGui::Selectable("Insert into scene"))
{
auto createdEntitiesList = SHSerialization::DeserializeEntitiesFromString(SHAssetManager::GetData<SHPrefabAsset>(asset->id)->data);
SHEditorWindowManager::GetEditorWindow<SHHierarchyPanel>()->SetScrollTo(createdEntitiesList.begin()->second);
SHPrefabManager::AddEntity(asset->id, createdEntitiesList.begin()->second);
}
}
break;
case AssetType::MATERIAL: break;
case AssetType::SCRIPT: break;
case AssetType::MAX_COUNT: break;
default:;
}
ImGui::EndPopup();
}
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();

View File

@ -26,6 +26,9 @@
#include "Serialization/SHSerialization.h" #include "Serialization/SHSerialization.h"
#include "Tools/Utilities/SHClipboardUtilities.h" #include "Tools/Utilities/SHClipboardUtilities.h"
#include "Tools/Utilities/SHStringUtilities.h" #include "Tools/Utilities/SHStringUtilities.h"
#include "Serialization/Prefab/SHPrefabManager.h"
#include "../SHEditorWindowManager.h"
#include "../AssetBrowser/SHAssetBrowser.h"
namespace SHADE namespace SHADE
@ -315,7 +318,7 @@ namespace SHADE
const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow); const ImGuiTreeNodeFlags nodeFlags = ((isSelected) ? ImGuiTreeNodeFlags_Selected : 0) | ((children.empty()) ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_OpenOnArrow);
//Draw Node //Draw Node
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(eid), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str()); bool isNodeOpen = ImGui::TreeNodeEx((void*)(eid), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str());
if(!filter.empty()) if(!filter.empty())
{ {
@ -388,6 +391,11 @@ namespace SHADE
//SHEntityManager::DestroyEntity(eid); //SHEntityManager::DestroyEntity(eid);
DeleteSelectedEntities(); DeleteSelectedEntities();
} }
if(ImGui::Selectable("Save entity as Prefab"))
{
SHPrefabManager::SaveEntityAsPrefab(eid);
SHEditorWindowManager::GetEditorWindow<SHAssetBrowser>()->QueueRefresh();
}
if ((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data())) if ((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
{ {

View File

@ -1,13 +1,29 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHPrefabManager.h" #include "SHPrefabManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Assets/SHAssetManager.h"
#include "Assets/Asset Types/SHPrefabAsset.h"
#include "Serialization/SHSerialization.h"
namespace SHADE namespace SHADE
{ {
SHPrefabManager::PrefabMap SHPrefabManager::prefabMap{}; SHPrefabManager::PrefabMap SHPrefabManager::prefabMap{};
AssetID SHPrefabManager::GetPrefabAssetID(EntityID eid) noexcept
{
for(auto const& [assetId, entityList] : prefabMap)
{
if(std::ranges::find(entityList, eid) != entityList.end())
{
return assetId;
}
}
return 0;
}
void SHPrefabManager::AddPrefab(AssetID const& prefabAssetID) noexcept void SHPrefabManager::AddPrefab(AssetID const& prefabAssetID) noexcept
{ {
prefabMap.insert({ prefabAssetID, {} }); prefabMap[prefabAssetID] = {};
} }
void SHPrefabManager::RemovePrefab(AssetID const& prefabAssetID) noexcept void SHPrefabManager::RemovePrefab(AssetID const& prefabAssetID) noexcept
@ -30,20 +46,30 @@ namespace SHADE
void SHPrefabManager::AddEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept void SHPrefabManager::AddEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept
{ {
if (prefabMap.contains(prefabAssetID))
{ prefabMap[prefabAssetID].push_back(eid);
prefabMap[prefabAssetID].insert(eid);
}
} }
void SHPrefabManager::RemoveEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept void SHPrefabManager::RemoveEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept
{ {
if (prefabMap.contains(prefabAssetID)) if (prefabMap.contains(prefabAssetID))
{ {
prefabMap[prefabAssetID].erase(eid); (void)std::ranges::remove(prefabMap[prefabAssetID], eid);
} }
} }
void SHPrefabManager::SaveEntityAsPrefab(EntityID const& eid) noexcept
{
SHEntity* const entity = SHEntityManager::GetEntityByID(eid);
AssetID const assetID = SHAssetManager::CreateNewAsset(AssetType::PREFAB, entity->name);
AddEntity(assetID, eid);
auto assetData = SHAssetManager::GetData<SHPrefabAsset>(assetID);
assetData->data = SHSerialization::SerializeEntityToString(eid);
SHAssetManager::SaveAsset(assetID);
}
void SHPrefabManager::Clear() noexcept void SHPrefabManager::Clear() noexcept
{ {
prefabMap.clear(); prefabMap.clear();

View File

@ -2,7 +2,8 @@
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
#include <unordered_set> #include "ECS_Base/General/SHFamily.h"
#include "ECS_Base/Components/SHComponent.h"
#include <unordered_map> #include <unordered_map>
@ -11,18 +12,34 @@ namespace SHADE
class SHPrefabManager class SHPrefabManager
{ {
public: public:
using PrefabMap = std::unordered_map<AssetID, std::unordered_set<EntityID>>;
enum class PrefabEntityComponentStatus : uint8_t
{
PES_UNCHANGED = 0,
PES_MODIFIED,
PES_ADDED,
PES_REMOVED
};
using PrefabMap = std::unordered_map<AssetID, std::vector<EntityID>>;
using PrefabEntitiesComponentStatusData = std::unordered_map<EntityID, std::unordered_map<SHFamilyID<SHComponent>,PrefabEntityComponentStatus>>;
static AssetID GetPrefabAssetID(EntityID eid) noexcept;
static void AddPrefab(AssetID const& prefabAssetID) noexcept; static void AddPrefab(AssetID const& prefabAssetID) noexcept;
static void RemovePrefab(AssetID const& prefabAssetID) noexcept; static void RemovePrefab(AssetID const& prefabAssetID) noexcept;
static void ClearPrefab(AssetID const& prefabAssetID) noexcept; static void ClearPrefab(AssetID const& prefabAssetID) noexcept;
static void UpdateAllPrefabEntities(AssetID const& prefabAssetID) noexcept; static void UpdateAllPrefabEntities(AssetID const& prefabAssetID) noexcept;
static void AddEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept; static void AddEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept;
static void RemoveEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept; static void RemoveEntity(AssetID const& prefabAssetID, EntityID const& eid) noexcept;
static void SaveEntityAsPrefab(EntityID const& eid) noexcept;
static void Clear() noexcept; static void Clear() noexcept;
static bool Empty() noexcept; static bool Empty() noexcept;
private: private:
static PrefabMap prefabMap; static PrefabMap prefabMap;
static PrefabEntitiesComponentStatusData prefabEntitiesComponentStatusData;
friend class SHSerialization;
friend struct SHSerializationHelper;
}; };
} }

View File

@ -15,6 +15,7 @@
#include "ECS_Base/Managers/SHSystemManager.h" #include "ECS_Base/Managers/SHSystemManager.h"
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "Tools/FileIO/SHFileIO.h" #include "Tools/FileIO/SHFileIO.h"
#include "Prefab/SHPrefabManager.h"
namespace SHADE namespace SHADE
{ {
@ -23,7 +24,7 @@ namespace SHADE
auto assetData = SHAssetManager::GetData<SHSceneAsset>(sceneAssetID); auto assetData = SHAssetManager::GetData<SHSceneAsset>(sceneAssetID);
if(!assetData) if(!assetData)
{ {
SHLOG_ERROR("Asset does not exist: {}", sceneAssetID); SHLOG_ERROR("Serialization: Asset does not exist: {}", sceneAssetID);
return false; return false;
} }
YAML::Emitter out; YAML::Emitter out;
@ -45,7 +46,7 @@ namespace SHADE
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
auto root = sceneGraph.GetRoot(); auto root = sceneGraph.GetRoot();
SHASSERT(root != nullptr, "Root is null. Failed to serialize scene to node."); SHASSERT(root != nullptr, "Serialization: Root is null. Failed to serialize scene to node.");
auto const& children = root->GetChildren(); auto const& children = root->GetChildren();
out << YAML::BeginSeq; out << YAML::BeginSeq;
@ -62,6 +63,7 @@ namespace SHADE
EntityID eid{MAX_EID}, oldEID{MAX_EID}; EntityID eid{MAX_EID}, oldEID{MAX_EID};
if (!node) if (!node)
return eid; return eid;
if (node[EIDNode]) if (node[EIDNode])
oldEID = eid = node[EIDNode].as<EntityID>(); oldEID = eid = node[EIDNode].as<EntityID>();
std::string name = "UnnamedEntitiy"; std::string name = "UnnamedEntitiy";
@ -105,7 +107,7 @@ namespace SHADE
auto assetData = SHAssetManager::GetData<SHSceneAsset>(sceneAssetID); auto assetData = SHAssetManager::GetData<SHSceneAsset>(sceneAssetID);
if(!assetData) if(!assetData)
{ {
SHLOG_ERROR("Attempted to load scene that doesn't exist {}", sceneAssetID) SHLOG_ERROR("Serialization: Attempted to load scene that doesn't exist {}", sceneAssetID)
SHSceneManager::SetCurrentSceneAssetID(0); SHSceneManager::SetCurrentSceneAssetID(0);
return NewSceneName.data(); return NewSceneName.data();
} }
@ -119,7 +121,7 @@ namespace SHADE
} }
if (createdEntities.empty()) if (createdEntities.empty())
{ {
SHLOG_ERROR("Failed to create entities from deserializaiton") SHLOG_ERROR("Serialization: Failed to create entities from deserialization")
return NewSceneName.data(); return NewSceneName.data();
} }
auto entityVecIt = createdEntities.begin(); auto entityVecIt = createdEntities.begin();
@ -139,13 +141,16 @@ namespace SHADE
return assetData->name; return assetData->name;
} }
void SHSerialization::EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out) void SHSerialization::EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out, bool isPrefab /*= false*/, EntityID* entityIndex /*= nullptr*/)
{ {
out << SerializeEntityToNode(entityNode); out << SerializeEntityToNode(entityNode, isPrefab, entityIndex);
if(isPrefab)
++(*entityIndex);
auto const& children = entityNode->GetChildren(); auto const& children = entityNode->GetChildren();
for (auto const& child : children) for (auto const& child : children)
{ {
EmitEntity(child, out); EmitEntity(child, out, isPrefab, entityIndex);
} }
} }
@ -155,6 +160,7 @@ namespace SHADE
YAML::Node node; YAML::Node node;
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph(); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
out << YAML::BeginSeq; out << YAML::BeginSeq;
EntityID entityIndex = 0;
for (auto const& eid : entities) for (auto const& eid : entities)
{ {
auto entityNode = sceneGraph.GetNode(eid); auto entityNode = sceneGraph.GetNode(eid);
@ -164,6 +170,21 @@ namespace SHADE
return std::string(out.c_str()); return std::string(out.c_str());
} }
std::string SHSerialization::SerializeEntityToString(EntityID eid) noexcept
{
YAML::Emitter out;
YAML::Node node;
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
out << YAML::BeginSeq;
EntityID entityIndex = 0;
auto entityNode = sceneGraph.GetNode(eid);
EmitEntity(entityNode, out, true, &entityIndex);
out << YAML::EndSeq;
return std::string(out.c_str());
}
//void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path) //void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path)
//{ //{
//} //}
@ -179,8 +200,11 @@ namespace SHADE
} }
} }
YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode) YAML::Node SHSerialization::SerializeEntityToNode(SHSceneNode* sceneNode, bool isPrefab /*= false*/, EntityID* entityIndex /*= nullptr*/)
{ {
if(!sceneNode)
return YAML::Node();
YAML::Node node; YAML::Node node;
auto eid = sceneNode->GetEntityID(); auto eid = sceneNode->GetEntityID();
auto entity = SHEntityManager::GetEntityByID(eid); auto entity = SHEntityManager::GetEntityByID(eid);
@ -190,7 +214,15 @@ namespace SHADE
return node; return node;
} }
node.SetStyle(YAML::EmitterStyle::Block); node.SetStyle(YAML::EmitterStyle::Block);
node[EIDNode] = eid;
node[EIDNode] = (entityIndex) ? *entityIndex : eid;
AssetID prefabAssetID = SHPrefabManager::GetPrefabAssetID(eid);
if(prefabAssetID != 0)
{
node[PrefabID] = prefabAssetID;
}
node[EntityNameNode] = entity->name; node[EntityNameNode] = entity->name;
node[IsActiveNode] = sceneNode->IsActive(); node[IsActiveNode] = sceneNode->IsActive();
auto const& children = sceneNode->GetChildren(); auto const& children = sceneNode->GetChildren();
@ -236,7 +268,7 @@ namespace SHADE
} }
if (createdEntities.empty()) if (createdEntities.empty())
{ {
SHLOG_ERROR("Failed to create entities from deserializaiton") SHLOG_ERROR("Failed to create entities from deserialization")
return createdEntities; return createdEntities;
} }
//auto entityVecIt = createdEntities.begin(); //auto entityVecIt = createdEntities.begin();

View File

@ -24,6 +24,7 @@ namespace SHADE
constexpr const char* IsActiveNode = "IsActive"; constexpr const char* IsActiveNode = "IsActive";
constexpr const char* NumberOfChildrenNode = "NumberOfChildren"; constexpr const char* NumberOfChildrenNode = "NumberOfChildren";
constexpr const char* ScriptsNode = "Scripts"; constexpr const char* ScriptsNode = "Scripts";
constexpr const char* PrefabID = "PrefabID";
class SH_API SHSerialization class SH_API SHSerialization
{ {
@ -37,12 +38,13 @@ namespace SHADE
static std::string DeserializeSceneFromFile(AssetID const& sceneAssetID) noexcept; static std::string DeserializeSceneFromFile(AssetID const& sceneAssetID) noexcept;
static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out, bool isPrefab = false, EntityID* entityIndex = nullptr);
static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out);
static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept; static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept;
static std::string SerializeEntityToString(EntityID eid) noexcept;
//static void SerializeEntityToFile(std::filesystem::path const& path); //static void SerializeEntityToFile(std::filesystem::path const& path);
static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode); static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode, bool isPrefab = false, EntityID* entityIndex = nullptr);
static CreatedEntitiesList DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept; static CreatedEntitiesList DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept;

View File

@ -135,6 +135,7 @@ namespace SHADE
} }
} }
return YAML::Node();
} }
template <typename Type> template <typename Type>