Repository: TheCenturiaGames/Sobrassada_Engine
Pull request #142: THO-464 Prefab fixing
Author: login: IDarkgenesis
Created: 2025-05-01T17:10:14Z | Merged: 2025-05-04T13:00:13Z

Now updating a prefab overwrites the existing one. Also added capability to delete prefabs from the load prefab menu.

Also fixed an issue that made prefabs spawn at 000 when loading a scene


Diff:
diff --git a/SobrassadaEngine/FileSystem/PrefabManager.cpp b/SobrassadaEngine/FileSystem/PrefabManager.cpp
index 8ac15ed5c..306cc88a3 100644
--- a/SobrassadaEngine/FileSystem/PrefabManager.cpp
+++ b/SobrassadaEngine/FileSystem/PrefabManager.cpp
@@ -32,25 +32,7 @@ namespace PrefabManager
         const std::string& savePath = App->GetProjectModule()->GetLoadedProjectPath() + PREFABS_LIB_PATH +
                                       std::to_string(finalPrefabUID) + PREFAB_EXTENSION;
 
-        const std::string& originalName = gameObject->GetName();
-
-        int numRepeated                 = 0;
-        bool updateName                 = true;
-        std::string name                = std::string(originalName);
-        while (updateName)
-        {
-            updateName = false;
-            for (const auto& savedPrefab : App->GetLibraryModule()->GetPrefabMap())
-            {
-                if (savedPrefab.first == name)
-                {
-                    updateName = true;
-                    ++numRepeated;
-                    name = originalName + "(" + std::to_string(numRepeated) + ")";
-                    break;
-                }
-            }
-        }
+        std::string name = gameObject->GetName();
 
         // Create structure
         prefab.AddMember("UID", finalPrefabUID, allocator);
diff --git a/SobrassadaEngine/Modules/EditorUIModule.cpp b/SobrassadaEngine/Modules/EditorUIModule.cpp
index 6e2bf8546..e5bb76001 100644
--- a/SobrassadaEngine/Modules/EditorUIModule.cpp
+++ b/SobrassadaEngine/Modules/EditorUIModule.cpp
@@ -25,7 +25,6 @@
 #include "TextureEditor.h"
 #include "TextureImporter.h"
 #include "WindowModule.h"
-#include "ScriptModule.h"
 
 #include "Math/Quat.h"
 #include "SDL.h"
@@ -511,13 +510,13 @@ void EditorUIModule::Navmesh(bool& navmesh)
             ImGui::End();
         }
 
-       if (!open)
+        if (!open)
         {
             showNavLoadDialog    = false;
 
             // Reset search and selection
             searchTextNavmesh[0] = '\0';
-            selectedNavmesh      = -1;          
+            selectedNavmesh      = -1;
             navmeshUID           = INVALID_UID;
         }
     }
@@ -547,7 +546,7 @@ void EditorUIModule::LoadPrefabDialog(bool& loadPrefab)
     ImGui::InputText("Search", searchTextPrefab, IM_ARRAYSIZE(searchTextPrefab));
 
     ImGui::Separator();
-    if (ImGui::BeginListBox("##PrefabsList", ImVec2(-FLT_MIN, -40)))
+    if (ImGui::BeginListBox("##PrefabsList", ImVec2(-FLT_MIN, -65)))
     {
         int i = 0;
         for (const auto& valuePair : App->GetLibraryModule()->GetPrefabMap())
@@ -573,6 +572,10 @@ void EditorUIModule::LoadPrefabDialog(bool& loadPrefab)
 
     if (ImGui::Button("Cancel", ImVec2(0, 0))) loadPrefab = false;
 
+    ImGui::Dummy(ImVec2(0, 5));
+
+    if (ImGui::Button("DELETE!", ImVec2(0, 0))) App->GetLibraryModule()->DeletePrefabFiles(prefabUID);
+
     ImGui::End();
 
     if (!loadPrefab) searchTextPrefab[0] = '\0';
diff --git a/SobrassadaEngine/Modules/LibraryModule.cpp b/SobrassadaEngine/Modules/LibraryModule.cpp
index 91dc879c1..75d08cd71 100644
--- a/SobrassadaEngine/Modules/LibraryModule.cpp
+++ b/SobrassadaEngine/Modules/LibraryModule.cpp
@@ -7,6 +7,7 @@
 #include "FileSystem/StateMachineManager.h"
 #include "GameObject.h"
 #include "ProjectModule.h"
+#include "Resource.h"
 #include "SceneImporter.h"
 #include "SceneModule.h"
 #include "TextureImporter.h"
@@ -219,7 +220,7 @@ bool LibraryModule::LoadLibraryMaps(const std::string& projectPath)
         }
     }
 
-    //GLOG("MODELS MAP SIZE: %d", modelMap.size());
+    // GLOG("MODELS MAP SIZE: %d", modelMap.size());
 
     return true;
 }
@@ -310,6 +311,30 @@ UID LibraryModule::AssignFiletypeUID(UID originalUID, FileType fileType)
     return final;
 }
 
+void LibraryModule::DeletePrefabFiles(UID prefabUID)
+{
+    const std::string metaPath = App->GetProjectModule()->GetLoadedProjectPath() + METADATA_PATH +
+                           std::to_string((int)ResourceType::Prefab) + FILENAME_SEPARATOR + GetResourceName(prefabUID) +
+                           META_EXTENSION;
+    
+    FileSystem::Delete(metaPath.c_str());
+
+    const std::string assetPath = App->GetProjectModule()->GetLoadedProjectPath() + PREFABS_ASSETS_PATH +
+                            GetResourceName(prefabUID) + PREFAB_EXTENSION;
+    
+    FileSystem::Delete(assetPath.c_str());
+
+    const std::string& resourcePath = App->GetProjectModule()->GetLoadedProjectPath() + PREFABS_LIB_PATH +
+                                      std::to_string(prefabUID) + PREFAB_EXTENSION;
+    FileSystem::Delete(resourcePath.c_str());
+
+    prefabMap.erase(GetResourceName(prefabUID));
+    namesMap.erase(prefabUID);
+    resourcePathsMap.erase(prefabUID);
+
+    App->GetSceneModule()->GetScene()->OverridePrefabs(prefabUID);
+}
+
 void LibraryModule::AddTexture(UID textureUID, const std::string& textureName)
 {
     textureMap[textureName] = textureUID;
@@ -459,7 +484,7 @@ const std::string& LibraryModule::GetResourceName(UID resourceID) const
         // GLOG("obtained name: %s", it->second.c_str());
         return it->second;
     }
-    
+
     return emptyString;
 }
 
diff --git a/SobrassadaEngine/Modules/LibraryModule.h b/SobrassadaEngine/Modules/LibraryModule.h
index 6fc5b4e82..b760fd96a 100644
--- a/SobrassadaEngine/Modules/LibraryModule.h
+++ b/SobrassadaEngine/Modules/LibraryModule.h
@@ -47,6 +47,7 @@ class LibraryModule : public Module
         UID uid, const std::string& path, rapidjson::Document& doc, rapidjson::Value& importOptions
     ) const;
     UID AssignFiletypeUID(UID originalUID, FileType fileType);
+    void DeletePrefabFiles(UID prefabUID);
 
     void AddTexture(UID textureUID, const std::string& ddsPath);
     void AddMesh(UID meshUID, const std::string& matPath);
diff --git a/SobrassadaEngine/Scene/Components/Standalone/MeshComponent.cpp b/SobrassadaEngine/Scene/Components/Standalone/MeshComponent.cpp
index 4acb8d683..1c654a05d 100644
--- a/SobrassadaEngine/Scene/Components/Standalone/MeshComponent.cpp
+++ b/SobrassadaEngine/Scene/Components/Standalone/MeshComponent.cpp
@@ -108,8 +108,11 @@ void MeshComponent::Clone(const Component* other)
         const MeshComponent* otherMesh = static_cast<const MeshComponent*>(other);
         enabled                        = otherMesh->enabled;
 
-        AddMesh(otherMesh->currentMesh->GetUID());
-        AddMaterial(otherMesh->currentMaterial->GetUID());
+        UID otherMeshUID               = otherMesh->currentMesh ? otherMesh->currentMesh->GetUID() : INVALID_UID;
+        UID otherMatUID = otherMesh->currentMaterial ? otherMesh->currentMaterial->GetUID() : INVALID_UID;
+
+        AddMesh(otherMeshUID);
+        AddMaterial(otherMatUID);
 
         modelUID     = otherMesh->modelUID;
         skinIndex    = otherMesh->skinIndex;
diff --git a/SobrassadaEngine/Scene/Scene.cpp b/SobrassadaEngine/Scene/Scene.cpp
index 8dd797baa..f340bab95 100644
--- a/SobrassadaEngine/Scene/Scene.cpp
+++ b/SobrassadaEngine/Scene/Scene.cpp
@@ -1273,7 +1273,8 @@ void Scene::OverridePrefabs(const UID prefabUID)
     {
         for (const auto& gameObject : gameObjectsContainer)
         {
-            if (gameObject.second != nullptr) gameObject.second->SetPrefabUID(INVALID_UID);
+            if (gameObject.second != nullptr && gameObject.second->GetPrefabUID() == prefabUID)
+                gameObject.second->SetPrefabUID(INVALID_UID);
         }
         return;
     }
@@ -1289,7 +1290,7 @@ void Scene::OverridePrefabs(const UID prefabUID)
             if (gameObject.second->GetPrefabUID() == prefabUID)
             {
                 updatedObjects.push_back(gameObject.first);
-                transforms.emplace_back(gameObject.second->GetGlobalTransform());
+                transforms.emplace_back(gameObject.second->GetLocalTransform());
             }
         }
     }


Reviews:
user: login: SirKaza
body: Nice changes, all seems to work! 
Take a look at the few comments.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T17:56:04Z
user: login: PolCurto
body: 👍 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T18:22:41Z
user: login: LukasGanter
body: I have to test a bit more, but i found issues with deleting and updating.
@PolCurto @SirKaza Could you test these functionalities on the game repository on the branch verticalSlice/VS3 please. I noticed some issues there
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T18:23:23Z
user: login: LukasGanter
body: Deleting previously duplicated prefabs doesn´t work. Try deleting the prefab "Prefab_CityCenter(1)" in the game repository, branch verticalSlice/VS3
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T18:41:16Z
user: login: LukasGanter
body: In the same project, updating a duplicated prefab (for example "Prefab_Island_2_Lvl_1(3)" duplicates the file once and creates "Prefab_Island_2_Lvl_1".
Solution here can be either that we update all duplicated prefabs once manually and remove the (x) tags, or to add these again to the name when updating. 
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T18:47:33Z
user: login: LukasGanter
body: Issues will be adressed manually in the game repository
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T18:23:03Z

Review comments:
diff_hunk: @@ -32,25 +32,7 @@ namespace PrefabManager
         const std::string& savePath = App->GetProjectModule()->GetLoadedProjectPath() + PREFABS_LIB_PATH +
                                       std::to_string(finalPrefabUID) + PREFAB_EXTENSION;
 
-        const std::string& originalName = gameObject->GetName();
-
-        int numRepeated                 = 0;
-        bool updateName                 = true;
-        std::string name                = std::string(originalName);
-        while (updateName)
-        {
-            updateName = false;
-            for (const auto& savedPrefab : App->GetLibraryModule()->GetPrefabMap())
-            {
-                if (savedPrefab.first == name)
-                {
-                    updateName = true;
-                    ++numRepeated;
-                    name = originalName + "(" + std::to_string(numRepeated) + ")";
-                    break;
-                }
-            }
-        }
+        std::string name = gameObject->GetName();
path: SobrassadaEngine/FileSystem/PrefabManager.cpp
user: login: SirKaza
body: const &
created_at: 2025-05-02T17:35:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -108,8 +108,11 @@ void MeshComponent::Clone(const Component* other)
         const MeshComponent* otherMesh = static_cast<const MeshComponent*>(other);
         enabled                        = otherMesh->enabled;
 
-        AddMesh(otherMesh->currentMesh->GetUID());
-        AddMaterial(otherMesh->currentMaterial->GetUID());
+        UID otherMeshUID               = otherMesh->currentMesh ? otherMesh->currentMesh->GetUID() : INVALID_UID;
path: SobrassadaEngine/Scene/Components/Standalone/MeshComponent.cpp
user: login: SirKaza
body: const
created_at: 2025-05-02T17:40:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -108,8 +108,11 @@ void MeshComponent::Clone(const Component* other)
         const MeshComponent* otherMesh = static_cast<const MeshComponent*>(other);
         enabled                        = otherMesh->enabled;
 
-        AddMesh(otherMesh->currentMesh->GetUID());
-        AddMaterial(otherMesh->currentMaterial->GetUID());
+        UID otherMeshUID               = otherMesh->currentMesh ? otherMesh->currentMesh->GetUID() : INVALID_UID;
+        UID otherMatUID = otherMesh->currentMaterial ? otherMesh->currentMaterial->GetUID() : INVALID_UID;
path: SobrassadaEngine/Scene/Components/Standalone/MeshComponent.cpp
user: login: SirKaza
body: const
created_at: 2025-05-02T17:40:20Z
author_association: CONTRIBUTOR

PR comments:
user: login: IDarkgenesis
created_at: 2025-05-03T16:24:26Z
body: > Deleting previously duplicated prefabs doesn´t work. Try deleting the prefab "Prefab_CityCenter(1)" in the game repository, branch verticalSlice/VS3

Due to the old system Prefab_CityCenter(1) and Prefab_CityCenter share the same UID and the last one to be loaded into the library is Prefab_CityCenter, which overrides the name in the map so it only deletes Prefab_CityCenter. Needs to be deleted manually, in the new version this does not happen since overrides the prefab.
author_association: CONTRIBUTOR
user: login: IDarkgenesis
created_at: 2025-05-03T16:27:04Z
body: > In the same project, updating a duplicated prefab (for example "Prefab_Island_2_Lvl_1(3)" duplicates the file once and creates "Prefab_Island_2_Lvl_1". Solution here can be either that we update all duplicated prefabs once manually and remove the (x) tags, or to add these again to the name when updating.

Similar to the previous comment this is an issue of the old save system, since they have the same UID only the Prefab_Island_2_Lvl_1 will be treated as the real prefab all others must be deleted by hand, from now on it gets overwritten
author_association: CONTRIBUTOR
user: login: IDarkgenesis
created_at: 2025-05-03T16:46:07Z
body: Solution could be to update the current prefabs to genertate the one with the version without brackets and the remove the old ones, from that point on, we shouldn't have this issues
author_association: CONTRIBUTOR