mirror of
https://github.com/antopilo/Nuake.git
synced 2026-09-15 20:08:54 +03:00
Prefab editor now somewhat works with live-reload
This commit is contained in:
@@ -975,7 +975,7 @@ namespace Nuake {
|
||||
|
||||
if (!savePath.empty())
|
||||
{
|
||||
newPrefab->SaveAs(savePath);
|
||||
newPrefab->SaveAs(FileSystem::AbsoluteToRelative(savePath));
|
||||
Selection.Entity.AddComponent<PrefabComponent>().PrefabInstance = newPrefab;
|
||||
FileSystem::Scan();
|
||||
FileSystemUI::m_CurrentDirectory = FileSystem::RootDirectory;
|
||||
@@ -2282,7 +2282,9 @@ namespace Nuake {
|
||||
char* file = (char*)payload->Data;
|
||||
std::string fullPath = std::string(file, 256);
|
||||
std::string relPath = FileSystem::AbsoluteToRelative(fullPath);
|
||||
Prefab::New(relPath);
|
||||
auto newPrefabInstance = Prefab::New(relPath);
|
||||
newPrefabInstance->Root.GetComponent<PrefabComponent>().SetPrefab(newPrefabInstance);
|
||||
newPrefabInstance->Root.GetComponent<NameComponent>().IsPrefab = true;
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "Prefab.h"
|
||||
#include "src/Scene/Components/ParentComponent.h"
|
||||
#include <src/Scene/Components/PrefabComponent.h>
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
@@ -27,7 +28,7 @@ namespace Nuake
|
||||
|
||||
if (!prefabTextContent.empty())
|
||||
{
|
||||
newPrefab->Deserialize(json::parse(prefabTextContent));
|
||||
newPrefab->Deserialize(json::parse(prefabTextContent), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +53,153 @@ namespace Nuake
|
||||
return newPrefab;
|
||||
}
|
||||
|
||||
void Prefab::ReInstance()
|
||||
{
|
||||
if (FileSystem::FileExists(Path, false))
|
||||
{
|
||||
for (auto& c : Entities)
|
||||
{
|
||||
if (c.IsValid() && c != Root)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::string prefabTextContent = FileSystem::ReadFile(Path);
|
||||
if (!prefabTextContent.empty())
|
||||
{
|
||||
Deserialize(json::parse(prefabTextContent), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Prefab::Deserialize(const json & j, bool skipRoot)
|
||||
{
|
||||
if (j == "")
|
||||
return false;
|
||||
|
||||
Path = j["Path"];
|
||||
|
||||
if (j.contains("DisplayName"))
|
||||
{
|
||||
DisplayName = j["DisplayName"];
|
||||
}
|
||||
|
||||
if (j.contains("Description"))
|
||||
{
|
||||
Description = j["Description"];
|
||||
}
|
||||
|
||||
if (j.contains("Entities"))
|
||||
{
|
||||
auto scene = Engine::GetCurrentScene();
|
||||
|
||||
std::map<uint32_t, uint32_t> newIdsLut;
|
||||
for (json e : j["Entities"])
|
||||
{
|
||||
if (e["NameComponent"]["ID"] == j["Root"] && skipRoot)
|
||||
{
|
||||
newIdsLut[e["NameComponent"]["ID"]] = e["NameComponent"]["ID"];
|
||||
continue;
|
||||
}
|
||||
|
||||
Entity entity = { scene->m_Registry.create(), scene.get() };
|
||||
entity.Deserialize(e); // Id gets overriden by serialized id.
|
||||
|
||||
auto& nameComponent = entity.GetComponent<NameComponent>();
|
||||
bool isRoot = false;
|
||||
if (nameComponent.ID == j["Root"])
|
||||
{
|
||||
isRoot = true; // We found the root entity of the prefab.
|
||||
auto& parentComponent = entity.GetComponent<ParentComponent>();
|
||||
parentComponent.HasParent = false;
|
||||
parentComponent.ParentID = 0;
|
||||
}
|
||||
|
||||
uint32_t oldId = nameComponent.ID;
|
||||
uint32_t newId = OS::GetTime();
|
||||
nameComponent.Name = nameComponent.Name;
|
||||
nameComponent.ID = newId;
|
||||
|
||||
newIdsLut[oldId] = newId;
|
||||
if (isRoot)
|
||||
{
|
||||
Root = entity;
|
||||
entity.AddComponent<PrefabComponent>();
|
||||
}
|
||||
else
|
||||
{
|
||||
entity.AddComponent<PrefabMember>();
|
||||
}
|
||||
|
||||
AddEntity(entity);
|
||||
}
|
||||
|
||||
// Set reference to the parent entity to children
|
||||
for (auto& e : Entities)
|
||||
{
|
||||
if (!e.IsValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e.GetID() == Root.GetID())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& parentC = e.GetComponent<ParentComponent>();
|
||||
auto parent = Engine::GetCurrentScene()->GetEntityByID(newIdsLut[parentC.ParentID]);
|
||||
if (parent.GetHandle() == 0)
|
||||
{
|
||||
Root.AddChild(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.AddChild(e);
|
||||
}
|
||||
|
||||
e.GetComponent<PrefabMember>().owner = Root;
|
||||
}
|
||||
|
||||
// Since the bones point to an entity, and we are instancing a prefab, the new skeleton is gonna be pointing to the wrong
|
||||
// bones, we need to remap the skeleton to the new entities. We are simply reussing the same map we are using for the
|
||||
// reparenting. Pretty neat.
|
||||
std::function<void(SkeletonNode&)> recursiveBoneRemapping = [&recursiveBoneRemapping, &newIdsLut](SkeletonNode& currentBone)
|
||||
{
|
||||
currentBone.EntityHandle = newIdsLut[currentBone.EntityHandle];
|
||||
for (SkeletonNode& bone : currentBone.Children)
|
||||
{
|
||||
recursiveBoneRemapping(bone);
|
||||
}
|
||||
};
|
||||
|
||||
// Do the remapping of the skeleton
|
||||
for (auto& e : Entities)
|
||||
{
|
||||
if (!e.IsValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e.GetID() == Root.GetID() || !e.HasComponent<SkinnedModelComponent>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& skinnedModelComponent = e.GetComponent<SkinnedModelComponent>();
|
||||
if (!skinnedModelComponent.ModelResource)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SkeletonNode& currentBone = skinnedModelComponent.ModelResource->GetSkeletonRootNode();
|
||||
recursiveBoneRemapping(currentBone);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Prefab::EntityWalker(Entity entity)
|
||||
{
|
||||
Root = entity;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "src/Resource/Serializable.h"
|
||||
#include "Engine.h"
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@@ -35,6 +36,8 @@ namespace Nuake {
|
||||
Entities.push_back(entity);
|
||||
}
|
||||
|
||||
void ReInstance();
|
||||
|
||||
void SaveAs(const std::string& path)
|
||||
{
|
||||
Path = path;
|
||||
@@ -169,101 +172,11 @@ namespace Nuake {
|
||||
|
||||
bool Deserialize(const json& j)
|
||||
{
|
||||
if (j == "")
|
||||
return false;
|
||||
|
||||
Path = j["Path"];
|
||||
|
||||
if (j.contains("DisplayName"))
|
||||
{
|
||||
DisplayName = j["DisplayName"];
|
||||
}
|
||||
|
||||
if (j.contains("Description"))
|
||||
{
|
||||
Description = j["Description"];
|
||||
}
|
||||
|
||||
if (j.contains("Entities"))
|
||||
{
|
||||
auto scene = Engine::GetCurrentScene();
|
||||
|
||||
std::map<uint32_t, uint32_t> newIdsLut;
|
||||
for (json e : j["Entities"])
|
||||
{
|
||||
Entity entity = { scene->m_Registry.create(), scene.get() };
|
||||
entity.Deserialize(e); // Id gets overriden by serialized id.
|
||||
|
||||
auto& nameComponent = entity.GetComponent<NameComponent>();
|
||||
bool isRoot = false;
|
||||
if (nameComponent.ID == j["Root"])
|
||||
{
|
||||
isRoot = true; // We found the root entity of the prefab.
|
||||
auto& parentComponent = entity.GetComponent<ParentComponent>();
|
||||
parentComponent.HasParent = false;
|
||||
parentComponent.ParentID = 0;
|
||||
}
|
||||
|
||||
uint32_t oldId = nameComponent.ID;
|
||||
uint32_t newId = OS::GetTime();
|
||||
nameComponent.Name = nameComponent.Name;
|
||||
nameComponent.ID = newId;
|
||||
|
||||
newIdsLut[oldId] = newId;
|
||||
if (isRoot)
|
||||
{
|
||||
Root = entity;
|
||||
}
|
||||
|
||||
AddEntity(entity);
|
||||
}
|
||||
|
||||
// Set reference to the parent entity to children
|
||||
for (auto& e : Entities)
|
||||
{
|
||||
if (e.GetID() == Root.GetID())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& parentC = e.GetComponent<ParentComponent>();
|
||||
auto parent = Engine::GetCurrentScene()->GetEntityByID(newIdsLut[parentC.ParentID]);
|
||||
parent.AddChild(e);
|
||||
}
|
||||
|
||||
// Since the bones point to an entity, and we are instancing a prefab, the new skeleton is gonna be pointing to the wrong
|
||||
// bones, we need to remap the skeleton to the new entities. We are simply reussing the same map we are using for the
|
||||
// reparenting. Pretty neat.
|
||||
std::function<void(SkeletonNode&)> recursiveBoneRemapping = [&recursiveBoneRemapping, &newIdsLut](SkeletonNode& currentBone)
|
||||
{
|
||||
currentBone.EntityHandle = newIdsLut[currentBone.EntityHandle];
|
||||
for (SkeletonNode& bone : currentBone.Children)
|
||||
{
|
||||
recursiveBoneRemapping(bone);
|
||||
}
|
||||
};
|
||||
|
||||
// Do the remapping of the skeleton
|
||||
for (auto& e : Entities)
|
||||
{
|
||||
if (e.GetID() == Root.GetID() || !e.HasComponent<SkinnedModelComponent>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& skinnedModelComponent = e.GetComponent<SkinnedModelComponent>();
|
||||
if (!skinnedModelComponent.ModelResource)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SkeletonNode& currentBone = skinnedModelComponent.ModelResource->GetSkeletonRootNode();
|
||||
recursiveBoneRemapping(currentBone);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return Deserialize(j, false);
|
||||
}
|
||||
|
||||
bool Deserialize(const json& j, bool skipRoot = false);
|
||||
|
||||
private:
|
||||
void EntityWalker(Entity entity);
|
||||
};
|
||||
|
||||
@@ -13,4 +13,10 @@ namespace Nuake {
|
||||
PrefabInstance = prefab;
|
||||
}
|
||||
};
|
||||
|
||||
class PrefabMember
|
||||
{
|
||||
public:
|
||||
Entity owner;
|
||||
};
|
||||
}
|
||||
@@ -296,6 +296,67 @@ namespace Nuake
|
||||
builder.BuildQuakeMap(entity, map.HasCollisions);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, Ref<File>> prefabToReimport;
|
||||
const auto& prefabView = m_Registry.view<PrefabComponent>();
|
||||
for (const auto& e : prefabView)
|
||||
{
|
||||
auto& prefabComponent = prefabView.get<PrefabComponent>(e);
|
||||
|
||||
const std::string& filePath = prefabComponent.PrefabInstance->Path;
|
||||
if (!FileSystem::FileExists(filePath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Ref<File> file = FileSystem::GetFile(filePath);
|
||||
if (file->GetHasBeenModified())
|
||||
{
|
||||
prefabToReimport[filePath] = file;
|
||||
}
|
||||
}
|
||||
|
||||
if (prefabToReimport.size() > 0)
|
||||
{
|
||||
for (const auto& e : prefabView)
|
||||
{
|
||||
auto& prefabComponent = prefabView.get<PrefabComponent>(e);
|
||||
auto& prefabInstance = prefabComponent.PrefabInstance;
|
||||
|
||||
if (prefabInstance == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// We don't need to reimport that one
|
||||
if (!prefabToReimport.contains(prefabInstance->Path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
for (auto& ent : prefabInstance->Entities)
|
||||
{
|
||||
// Destroy all children, not the root!
|
||||
if (ent.IsValid() && ent != prefabInstance->Root)
|
||||
{
|
||||
this->DestroyEntity(ent);
|
||||
}
|
||||
}
|
||||
|
||||
std::remove_if(prefabInstance->Entities.begin(), prefabInstance->Entities.end(), [](const Entity& entity)
|
||||
{
|
||||
return !entity.IsValid();
|
||||
});
|
||||
|
||||
prefabInstance->ReInstance();
|
||||
}
|
||||
|
||||
for (auto& [path, prefabFile] : prefabToReimport)
|
||||
{
|
||||
prefabFile->SetHasBeenModified(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& system : m_Systems)
|
||||
|
||||
Reference in New Issue
Block a user