Browse Source

Add basic level load/save method
Update prefab diffs on save
Update object from prefab upon instantiate
Moved various prefab specific C# functionality to editor only assembly

Marko Pintera 10 years ago
parent
commit
f85cceb27d

+ 14 - 0
BansheeCore/Include/BsResources.h

@@ -110,6 +110,20 @@ namespace BansheeEngine
 		 */
 		void save(HResource resource, const Path& filePath, bool overwrite);
 
+		/**
+		 * @brief	Saves an existing resource to its previous location.
+		 *
+		 * @param	resource 	Handle to the resource.
+		 *
+		 * @note	If the resource is a GpuResource and you are in some way modifying it from the Core thread, make
+		 * 			sure all those commands are submitted before you call this method. Otherwise an obsolete
+		 * 			version of the resource might get saved.
+		 *
+		 *			If saving a core thread resource this is a potentially very slow operation as we must wait on the
+		 *			core thread and the GPU in order to read the resource.
+		 */
+		void save(HResource resource);
+
 		/**
 		 * @brief	Creates a new resource handle from a resource pointer. 
 		 *

+ 8 - 1
BansheeCore/Source/BsCoreSceneManager.cpp

@@ -20,8 +20,15 @@ namespace BansheeEngine
 
 	void CoreSceneManager::clearScene()
 	{
+		UINT32 numChildren = mRootNode->getNumChildren();
+
+		for (UINT32 i = 0; i < numChildren; i++)
+		{
+			HSceneObject child = mRootNode->getChild(0);
+			child->destroy();
+		}
+
 		GameObjectManager::instance().destroyQueuedObjects();
-		mRootNode->destroy(true);
 	}
 
 	void CoreSceneManager::_update()

+ 4 - 0
BansheeCore/Source/BsPrefab.cpp

@@ -75,6 +75,10 @@ namespace BansheeEngine
 		HSceneObject clone = mRoot->clone();
 		clone->instantiate();
 
+#if BS_EDITOR_BUILD
+		PrefabUtility::updateFromPrefab(clone);
+#endif
+
 		return clone;
 	}
 

+ 10 - 0
BansheeCore/Source/BsResources.cpp

@@ -297,6 +297,16 @@ namespace BansheeEngine
 		fs.encode(resource.get());
 	}
 
+	void Resources::save(HResource resource)
+	{
+		if (resource == nullptr)
+			return;
+
+		Path path;
+		if (getFilePathFromUUID(resource.getUUID(), path))
+			save(resource, path, true);
+	}
+
 	void Resources::registerResourceManifest(const ResourceManifestPtr& manifest)
 	{
 		if(manifest->getName() == "Default")

+ 62 - 0
MBansheeEditor/EditorApplication.cs

@@ -146,6 +146,65 @@ namespace BansheeEditor
             // DEBUG ONLY END
         }
 
+        [MenuItem("File/Save Prefab", ButtonModifier.Ctrl, ButtonCode.S)]
+        private static void SavePrefab()
+        {
+            if (!string.IsNullOrEmpty(Scene.ActiveSceneUUID))
+            {
+                string scenePath = ProjectLibrary.GetPath(Scene.ActiveSceneUUID);
+                Internal_SaveScene(scenePath);
+            }
+            else
+            {
+                string scenePath = "";
+                BrowseDialog.SaveFile(ProjectLibrary.ResourceFolder, "", out scenePath);
+
+                if (!PathEx.IsPartOf(scenePath, ProjectLibrary.ResourceFolder))
+                    DialogBox.Open("Error", "The location must be inside the Resources folder of the project.", DialogBox.Type.OK);
+                else
+                {
+                    // TODO - If path points to an existing non-scene asset or folder I should delete it otherwise
+                    //        Internal_SaveScene will silently fail.
+
+                    Scene.ActiveSceneUUID = Internal_SaveScene(scenePath);
+                }
+            }
+        }
+
+        [MenuItem("File/Load Prefab", ButtonModifier.Ctrl, ButtonCode.L)]
+        private static void LoadPrefab()
+        {
+            Action doLoad =
+                () =>
+                {
+                    string[] scenePaths;
+                    BrowseDialog.OpenFile(ProjectLibrary.ResourceFolder, "", false, out scenePaths);
+
+                    if(scenePaths.Length > 0)
+                        Scene.Load(scenePaths[0]);
+                };
+
+            Action<DialogBox.ResultType> dialogCallback =
+                (result) =>
+                {
+                    if (result == DialogBox.ResultType.Yes)
+                    {
+                        SavePrefab();
+                        doLoad();
+                    }
+                    else if (result == DialogBox.ResultType.No)
+                        doLoad();
+                };
+
+            if (Scene.IsModified())
+            {
+                DialogBox.Open("Warning", "You current scene has modifications. Do you wish to save them first?",
+                    DialogBox.Type.YesNoCancel, dialogCallback);
+            }
+            else
+                doLoad();
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern string Internal_GetProjectPath();
 
@@ -175,5 +234,8 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern string Internal_GetScriptEditorAssemblyName();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_SaveScene(string path);
     }
 }

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -58,6 +58,7 @@
     <Compile Include="FolderMonitor.cs" />
     <Compile Include="GUI\GUISceneTreeView.cs" />
     <Compile Include="HierarchyWindow.cs" />
+    <Compile Include="PrefabUtility.cs" />
     <Compile Include="ProjectDropTarget.cs" />
     <Compile Include="OSDropTarget.cs" />
     <Compile Include="EditorApplication.cs" />

+ 49 - 0
MBansheeEditor/PrefabUtility.cs

@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public static class PrefabUtility
+    {
+        public static void BreakPrefab(SceneObject obj)
+        {
+            if (obj == null)
+                return;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            Internal_BreakPrefab(objPtr);
+        }
+
+        public static void ApplyPrefab(SceneObject obj)
+        {
+            if (obj == null)
+                return;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            Internal_ApplyPrefab(objPtr);
+        }
+
+        public static void RevertPrefab(SceneObject obj)
+        {
+            if (obj == null)
+                return;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            Internal_RevertPrefab(objPtr);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_BreakPrefab(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_ApplyPrefab(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_RevertPrefab(IntPtr nativeInstance);
+    }
+}

+ 8 - 0
MBansheeEditor/ProjectLibrary.cs

@@ -86,6 +86,11 @@ namespace BansheeEditor
             return Internal_GetPath(resource);
         }
 
+        public static string GetPath(string uuid)
+        {
+            return Internal_GetPathFromUUID(uuid);
+        }
+
         public static void Delete(string path)
         {
             Internal_Delete(path);
@@ -201,6 +206,9 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern string Internal_GetPath(Resource resource);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_GetPathFromUUID(string uuid);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_Delete(string path);
 

+ 1 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -114,6 +114,7 @@
     <Compile Include="RenderTexture.cs" />
     <Compile Include="RenderTexture2D.cs" />
     <Compile Include="Resource.cs" />
+    <Compile Include="Scene.cs" />
     <Compile Include="SceneObject.cs" />
     <Compile Include="ScriptCode.cs" />
     <Compile Include="ScriptObject.cs" />

+ 33 - 0
MBansheeEngine/Scene.cs

@@ -0,0 +1,33 @@
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    public static class Scene
+    {
+        internal static string ActiveSceneUUID { get; set; }
+
+        public static bool IsModified()
+        {
+            // TODO - Needs implementing
+            return true;
+        }
+
+        public static void Clear()
+        {
+            Internal_ClearScene();
+            ActiveSceneUUID = null;
+        }
+
+        public static void Load(string path)
+        {
+            Clear();
+            ActiveSceneUUID = Internal_LoadScene(path);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_LoadScene(string path);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_ClearScene();
+    }
+}

+ 0 - 29
MBansheeEngine/SceneObject.cs

@@ -193,26 +193,6 @@ namespace BansheeEngine
             return Internal_GetChild(mCachedPtr, idx);
         }
 
-        public Prefab GetPrefab()
-        {
-            return Internal_GetPrefab(mCachedPtr);
-        }
-
-        public void BreakPrefab()
-        {
-            Internal_BreakPrefab(mCachedPtr);
-        }
-
-        public void ApplyPrefab()
-        {
-            Internal_ApplyPrefab(mCachedPtr);
-        }
-
-        public void RevertPrefab()
-        {
-            Internal_RevertPrefab(mCachedPtr);
-        }
-
         public void LookAt(Vector3 direction)
         {
             Internal_LookAt(mCachedPtr, direction, Vector3.yAxis);
@@ -276,15 +256,6 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern Prefab Internal_GetPrefab(IntPtr nativeInstance);
 
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_BreakPrefab(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_ApplyPrefab(IntPtr nativeInstance);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_RevertPrefab(IntPtr nativeInstance);
-
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_GetPosition(IntPtr nativeInstance, out Vector3 value);
 

+ 1 - 0
SBansheeEditor/Include/BsScriptEditorApplication.h

@@ -23,5 +23,6 @@ namespace BansheeEngine
 		static MonoString* internal_GetEditorAssemblyName();
 		static MonoString* internal_GetScriptGameAssemblyName();
 		static MonoString* internal_GetScriptEditorAssemblyName();
+		static MonoString* internal_SaveScene(MonoString* path);
 	};
 }

+ 20 - 0
SBansheeEditor/Include/BsScriptPrefabUtility.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BED_EXPORT ScriptPrefabUtility : public ScriptObject <ScriptPrefabUtility>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "PrefabUtility")
+
+	private:
+		static void internal_breakPrefab(ScriptSceneObject* nativeInstance);
+		static void internal_applyPrefab(ScriptSceneObject* nativeInstance);
+		static void internal_revertPrefab(ScriptSceneObject* nativeInstance);
+
+		ScriptPrefabUtility(MonoObject* instance);
+	};
+}

+ 1 - 0
SBansheeEditor/Include/BsScriptProjectLibrary.h

@@ -23,6 +23,7 @@ namespace BansheeEngine
 		static MonoObject* internal_GetRoot();
 		static void internal_Reimport(MonoString* path, MonoObject* options, bool force);
 		static MonoObject* internal_GetEntry(MonoString* path);
+		static MonoString* internal_GetPathFromUUID(MonoString* uuid);
 		static MonoString* internal_GetPath(MonoObject* resource);
 		static MonoArray* internal_Search(MonoString* pattern, MonoArray* types);
 		static void internal_Delete(MonoString* path);

+ 2 - 0
SBansheeEditor/SBansheeEditor.vcxproj

@@ -275,6 +275,7 @@
     <ClInclude Include="Include\BsScriptImportOptions.h" />
     <ClInclude Include="Include\BsScriptModalWindow.h" />
     <ClInclude Include="Include\BsScriptPlatformInfo.h" />
+    <ClInclude Include="Include\BsScriptPrefabUtility.h" />
     <ClInclude Include="Include\BsScriptProjectLibrary.h" />
     <ClInclude Include="Include\BsScriptSceneViewHandler.h" />
     <ClInclude Include="Include\BsScriptSelection.h" />
@@ -324,6 +325,7 @@
     <ClCompile Include="Source\BsScriptImportOptions.cpp" />
     <ClCompile Include="Source\BsScriptModalWindow.cpp" />
     <ClCompile Include="Source\BsScriptPlatformInfo.cpp" />
+    <ClCompile Include="Source\BsScriptPrefabUtility.cpp" />
     <ClCompile Include="Source\BsScriptProjectLibrary.cpp" />
     <ClCompile Include="Source\BsScriptSceneViewHandler.cpp" />
     <ClCompile Include="Source\BsScriptSelection.cpp" />

+ 6 - 0
SBansheeEditor/SBansheeEditor.vcxproj.filters

@@ -156,6 +156,9 @@
     <ClInclude Include="Include\BsScriptUnitTests.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptPrefabUtility.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
@@ -299,5 +302,8 @@
     <ClCompile Include="Source\BsScriptUnitTests.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptPrefabUtility.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 37 - 0
SBansheeEditor/Source/BsScriptEditorApplication.cpp

@@ -4,6 +4,12 @@
 #include "BsMonoMethod.h"
 #include "BsMonoUtil.h"
 #include "BsEditorApplication.h"
+#include "BsProjectLibrary.h"
+#include "BsProjectResourceMeta.h"
+#include "BsPrefab.h"
+#include "BsPrefabUtility.h"
+#include "BsSceneManager.h"
+#include "BsResources.h"
 
 namespace BansheeEngine
 {
@@ -23,6 +29,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetEditorAssemblyName", &ScriptEditorApplication::internal_GetEditorAssemblyName);
 		metaData.scriptClass->addInternalCall("Internal_GetScriptGameAssemblyName", &ScriptEditorApplication::internal_GetScriptGameAssemblyName);
 		metaData.scriptClass->addInternalCall("Internal_GetScriptEditorAssemblyName", &ScriptEditorApplication::internal_GetScriptEditorAssemblyName);
+		metaData.scriptClass->addInternalCall("Internal_SaveScene", &ScriptEditorApplication::internal_SaveScene);
 	}
 
 	MonoString* ScriptEditorApplication::internal_GetProjectPath()
@@ -86,4 +93,34 @@ namespace BansheeEngine
 	{
 		return MonoUtil::wstringToMono(MonoManager::instance().getDomain(), toWString(SCRIPT_EDITOR_ASSEMBLY) + L".dll");
 	}
+
+	MonoString* ScriptEditorApplication::internal_SaveScene(MonoString* path)
+	{
+		Path nativePath = MonoUtil::monoToWString(path);
+		HSceneObject sceneRoot = gSceneManager().getRootNode();
+		
+		ProjectLibrary::LibraryEntry* entry = ProjectLibrary::instance().findEntry(nativePath);
+		HPrefab scene;
+		if (entry != nullptr)
+		{
+			if (entry->type == ProjectLibrary::LibraryEntryType::Directory)
+				return nullptr;
+
+			ProjectLibrary::ResourceEntry* resEntry = static_cast<ProjectLibrary::ResourceEntry*>(entry);
+			if (resEntry->meta->getTypeID() != TID_Prefab)
+				return nullptr;
+
+			scene = static_resource_cast<Prefab>(ProjectLibrary::instance().load(nativePath));
+			scene->update(sceneRoot);
+		}
+		else
+		{
+			scene = Prefab::create(sceneRoot);
+		}
+
+		PrefabUtility::recordPrefabDiff(sceneRoot);
+		ProjectLibrary::instance().saveEntry(scene);
+
+		return MonoUtil::stringToMono(MonoManager::instance().getDomain(), scene.getUUID());
+	}
 }

+ 54 - 0
SBansheeEditor/Source/BsScriptPrefabUtility.cpp

@@ -0,0 +1,54 @@
+#include "BsScriptPrefabUtility.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsMonoUtil.h"
+#include "BsPrefabUtility.h"
+#include "BsScriptSceneObject.h"
+#include "BsSceneObject.h"
+#include "BsPrefab.h"
+#include "BsResources.h"
+
+namespace BansheeEngine
+{
+	ScriptPrefabUtility::ScriptPrefabUtility(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptPrefabUtility::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_BreakPrefab", &ScriptPrefabUtility::internal_breakPrefab);
+		metaData.scriptClass->addInternalCall("Internal_ApplyPrefab", &ScriptPrefabUtility::internal_applyPrefab);
+		metaData.scriptClass->addInternalCall("Internal_RevertPrefab", &ScriptPrefabUtility::internal_revertPrefab);
+	}
+
+	void ScriptPrefabUtility::internal_breakPrefab(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return;
+
+		nativeInstance->getNativeSceneObject()->breakPrefabLink();
+	}
+
+	void ScriptPrefabUtility::internal_applyPrefab(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return;
+
+		String prefabLinkUUID = nativeInstance->getNativeSceneObject()->getPrefabLink();
+		HPrefab prefab = static_resource_cast<Prefab>(gResources().loadFromUUID(prefabLinkUUID, false, false));
+
+		if (prefab != nullptr)
+			prefab->update(nativeInstance->getNativeSceneObject());
+
+		gResources().save(prefab);
+	}
+
+	void ScriptPrefabUtility::internal_revertPrefab(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return;
+
+		PrefabUtility::revertToPrefab(nativeInstance->getNativeSceneObject());
+	}
+}

+ 9 - 0
SBansheeEditor/Source/BsScriptProjectLibrary.cpp

@@ -41,6 +41,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_Reimport", &ScriptProjectLibrary::internal_Reimport);
 		metaData.scriptClass->addInternalCall("Internal_GetEntry", &ScriptProjectLibrary::internal_GetEntry);
 		metaData.scriptClass->addInternalCall("Internal_GetPath", &ScriptProjectLibrary::internal_GetPath);
+		metaData.scriptClass->addInternalCall("Internal_GetPathFromUUID", &ScriptProjectLibrary::internal_GetPathFromUUID);
 		metaData.scriptClass->addInternalCall("Internal_Search", &ScriptProjectLibrary::internal_Search);
 		metaData.scriptClass->addInternalCall("Internal_Delete", &ScriptProjectLibrary::internal_Delete);
 		metaData.scriptClass->addInternalCall("Internal_CreateFolder", &ScriptProjectLibrary::internal_CreateFolder);
@@ -140,6 +141,14 @@ namespace BansheeEngine
 			return ScriptDirectoryEntry::create(static_cast<ProjectLibrary::DirectoryEntry*>(entry));
 	}
 
+	MonoString* ScriptProjectLibrary::internal_GetPathFromUUID(MonoString* uuid)
+	{
+		String nativeUUID = MonoUtil::monoToString(uuid);
+		Path nativePath = ProjectLibrary::instance().uuidToPath(nativeUUID);
+
+		return MonoUtil::wstringToMono(MonoManager::instance().getDomain(), nativePath.toWString());
+	}
+
 	MonoString* ScriptProjectLibrary::internal_GetPath(MonoObject* resource)
 	{
 		ScriptResource* srcResource = ScriptResource::toNative(resource);

+ 19 - 0
SBansheeEngine/Include/BsScriptScene.h

@@ -0,0 +1,19 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptScene : public ScriptObject<ScriptScene>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Scene")
+
+	private:
+		static MonoString* internal_LoadScene(MonoString* path);
+		static void internal_ClearScene();
+
+		ScriptScene(MonoObject* instance);
+	};
+}

+ 3 - 7
SBansheeEngine/Include/BsScriptSceneObject.h

@@ -12,6 +12,8 @@ namespace BansheeEngine
 	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "SceneObject")
 
+		static bool checkIfDestroyed(ScriptSceneObject* nativeInstance);
+
 		virtual HGameObject getNativeHandle() const { return mSceneObject; }
 		virtual void setNativeHandle(const HGameObject& gameObject);
 
@@ -28,11 +30,6 @@ namespace BansheeEngine
 		static void internal_getNumChildren(ScriptSceneObject* nativeInstance, UINT32* value);
 		static MonoObject* internal_getChild(ScriptSceneObject* nativeInstance, UINT32 idx);
 
-		static MonoObject* internal_getPrefab(ScriptSceneObject* nativeInstance);
-		static void internal_breakPrefab(ScriptSceneObject* nativeInstance);
-		static void internal_applyPrefab(ScriptSceneObject* nativeInstance);
-		static void internal_revertPrefab(ScriptSceneObject* nativeInstance);
-
 		static void internal_getPosition(ScriptSceneObject* nativeInstance, Vector3* value);
 		static void internal_getLocalPosition(ScriptSceneObject* nativeInstance, Vector3* value);
 		static void internal_getRotation(ScriptSceneObject* nativeInstance, Quaternion* value);
@@ -61,8 +58,7 @@ namespace BansheeEngine
 		static void internal_getRight(ScriptSceneObject* nativeInstance, Vector3* value);
 
 		static void internal_destroy(ScriptSceneObject* nativeInstance, bool immediate);
-		static bool checkIfDestroyed(ScriptSceneObject* nativeInstance);
-
+		
 		ScriptSceneObject(MonoObject* instance, const HSceneObject& sceneObject);
 
 		void _onManagedInstanceDeleted();

+ 2 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -304,6 +304,7 @@
     <ClInclude Include="Include\BsScriptRenderTexture2D.h" />
     <ClInclude Include="Include\BsScriptResource.h" />
     <ClInclude Include="Include\BsScriptResourceManager.h" />
+    <ClInclude Include="Include\BsScriptScene.h" />
     <ClInclude Include="Include\BsScriptSceneObject.h" />
     <ClInclude Include="Include\BsManagedSerializableObjectInfoRTTI.h" />
     <ClInclude Include="Include\BsManagedSerializableObjectRTTI.h" />
@@ -388,6 +389,7 @@
     <ClCompile Include="Source\BsScriptRenderTexture2D.cpp" />
     <ClCompile Include="Source\BsScriptResource.cpp" />
     <ClCompile Include="Source\BsScriptResourceManager.cpp" />
+    <ClCompile Include="Source\BsScriptScene.cpp" />
     <ClCompile Include="Source\BsScriptSceneObject.cpp" />
     <ClCompile Include="Source\BsManagedSerializableArray.cpp" />
     <ClCompile Include="Source\BsManagedSerializableDictionary.cpp" />

+ 6 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -321,6 +321,9 @@
     <ClInclude Include="Include\BsScriptPrefab.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptScene.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -578,5 +581,8 @@
     <ClCompile Include="Source\BsScriptPrefab.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptScene.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 40 - 0
SBansheeEngine/Source/BsScriptScene.cpp

@@ -0,0 +1,40 @@
+#include "BsScriptScene.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsMonoUtil.h"
+#include "BsSceneManager.h"
+#include "BsResources.h"
+#include "BsPrefab.h"
+#include "BsSceneObject.h"
+
+namespace BansheeEngine
+{
+	ScriptScene::ScriptScene(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptScene::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_LoadScene", &ScriptScene::internal_LoadScene);
+		metaData.scriptClass->addInternalCall("Internal_ClearScene", &ScriptScene::internal_ClearScene);
+	}
+
+	MonoString* ScriptScene::internal_LoadScene(MonoString* path)
+	{
+		Path nativePath = MonoUtil::monoToWString(path);
+
+		HPrefab prefab = gResources().load<Prefab>(nativePath);
+		HSceneObject root = prefab->instantiate();
+
+		MonoString* uuid = MonoUtil::stringToMono(MonoManager::instance().getDomain(), prefab.getUUID());
+		gResources().unload(prefab);
+
+		return uuid;
+	}
+
+	void ScriptScene::internal_ClearScene()
+	{
+		gSceneManager().clearScene();
+	}
+}

+ 0 - 53
SBansheeEngine/Source/BsScriptSceneObject.cpp

@@ -28,11 +28,6 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetNumChildren", &ScriptSceneObject::internal_getNumChildren);
 		metaData.scriptClass->addInternalCall("Internal_GetChild", &ScriptSceneObject::internal_getChild);
 
-		metaData.scriptClass->addInternalCall("Internal_GetPrefab", &ScriptSceneObject::internal_getPrefab);
-		metaData.scriptClass->addInternalCall("Internal_BreakPrefab", &ScriptSceneObject::internal_breakPrefab);
-		metaData.scriptClass->addInternalCall("Internal_ApplyPrefab", &ScriptSceneObject::internal_applyPrefab);
-		metaData.scriptClass->addInternalCall("Internal_RevertPrefab", &ScriptSceneObject::internal_revertPrefab);
-
 		metaData.scriptClass->addInternalCall("Internal_GetPosition", &ScriptSceneObject::internal_getPosition);
 		metaData.scriptClass->addInternalCall("Internal_GetLocalPosition", &ScriptSceneObject::internal_getLocalPosition);
 		metaData.scriptClass->addInternalCall("Internal_GetRotation", &ScriptSceneObject::internal_getRotation);
@@ -123,54 +118,6 @@ namespace BansheeEngine
 		return childScriptSO->getManagedInstance();
 	}
 
-	MonoObject* ScriptSceneObject::internal_getPrefab(ScriptSceneObject* nativeInstance)
-	{
-		if (checkIfDestroyed(nativeInstance))
-			return nullptr;
-
-		String prefabLinkUUID = nativeInstance->mSceneObject->getPrefabLink();
-		HPrefab prefab = static_resource_cast<Prefab>(gResources().loadFromUUID(prefabLinkUUID, false, false));
-
-		if (prefab != nullptr)
-		{
-			ScriptPrefab* scriptPrefab = ScriptResourceManager::instance().getScriptPrefab(prefab);
-			if (scriptPrefab == nullptr)
-				scriptPrefab = ScriptResourceManager::instance().createScriptPrefab(prefab);
-
-			return scriptPrefab->getManagedInstance();
-		}
-
-		return nullptr;
-	}
-
-	void ScriptSceneObject::internal_breakPrefab(ScriptSceneObject* nativeInstance)
-	{
-		if (checkIfDestroyed(nativeInstance))
-			return;
-
-		nativeInstance->mSceneObject->breakPrefabLink();
-	}
-
-	void ScriptSceneObject::internal_applyPrefab(ScriptSceneObject* nativeInstance)
-	{
-		if (checkIfDestroyed(nativeInstance))
-			return;
-
-		String prefabLinkUUID = nativeInstance->mSceneObject->getPrefabLink();
-		HPrefab prefab = static_resource_cast<Prefab>(gResources().loadFromUUID(prefabLinkUUID, false, false));
-
-		if (prefab != nullptr)
-			prefab->update(nativeInstance->mSceneObject);
-	}
-
-	void ScriptSceneObject::internal_revertPrefab(ScriptSceneObject* nativeInstance)
-	{
-		if (checkIfDestroyed(nativeInstance))
-			return;
-
-		PrefabUtility::revertToPrefab(nativeInstance->mSceneObject);
-	}
-
 	void ScriptSceneObject::internal_getPosition(ScriptSceneObject* nativeInstance, Vector3* value)
 	{
 		if (!checkIfDestroyed(nativeInstance))

+ 17 - 14
TODO.txt

@@ -27,33 +27,36 @@ return them in checkForModifications?
 ---------------------------------------------------------------------
 Prefab diff
 
+TODO - Recursively generating prefab diffs doesn't work. e.g. if one prefab has multiple prefab children we just generate a single
+       diff for the top-most parent but I should probably generate one for each prefab?
+	    - The same issue is with updateFromPrefab - presumably it should update all child prefabs as well
+
+TODO - When clearing a scene I need to be able to persist certain elements (e.g. editor-only stuff)
+
+TODO - How do I mark the scene as modified? I need to know if user made any modifications to the scene to
+       ask him before loading another scene or exiting.
+	     - Just have a EditorUtility.SetDirty for the resource? This means I would need to use this general
+		   approach for all resources, but I probably need that since likely I want to save all modified resources
+		   before editor exits? Think about this.
+
+TODO - I should add a "prefabHash" to each scene object so I know when I need to call updateFromPrefab and when not.
+       Otherwise I need to call it every time I instantiate a prefab.
+
 Level save
- - Entry in File menu (Ctrl + S)
-   - Clicking it opens up a save file dialog unless level is already linked to prefab
  - Drag and drop to project window
    - Automatically creates a new prefab with the same name as the root object
     - Or creates a unique name if an asset with the same name exists
- - Whenever I save I need to go through all prefab instances and update their diffs (Make this editor only, but level saving should be editor only all together)
 
 Level load
- - Entry in File menu (Ctrl + L)
-   - Opens up a file open dialog
  - Drag and drop from project window or double-click in project window
-  - Unloads the current level and loads the new one
-   - TODO - If current level is modified ask the user to confirm?
- - After loading a new scene always perform an "updateFromPrefab" action on all prefab instances (Make this editor only)
-   - TODO - Should I monitor for prefab changes so I don't update unless prefab actually changed? 
-    - Have each scene object have a prefabHash stored, and prefab hash should increase whenever it is saved.
-	  This way I can check if I really need to update the prefab instance.
-
-TODO - Prefabs should be editor only, especially automatic diff creation and updates on load
- - In C# instead of having prefab stuff on SceneObject, move it to BansheeEditor.PrefabUtility
 
 TODO - Add Prefab buttons to Inspector (Apply, Break, Revert)
 
 TODO - Later - When building level for release make sure to clear all prefab diffs (possibly store them elsewhere in the first place)
+       - And all prefab instances should have updateFromPrefab called on them.
 
  Test (likely later once I have more editor functionality working):
+  - If level save/load works
   - Game object handle compare
   - ID restore systems 
   - Native+Managed diff (only the link between the two)