Просмотр исходного кода

Added project-specific properties to EditorSettings
EditorSettings is now serializable and persistent
Added ProjectSettings

Marko Pintera 10 лет назад
Родитель
Сommit
2efd26a9a3
31 измененных файлов с 1192 добавлено и 205 удалено
  1. 1 1
      BansheeCore/Source/BsSceneObject.cpp
  2. 7 0
      BansheeEditor/BansheeEditor.vcxproj
  3. 21 0
      BansheeEditor/BansheeEditor.vcxproj.filters
  4. 3 3
      BansheeEditor/Include/BsDockManagerLayoutRTTI.h
  5. 34 0
      BansheeEditor/Include/BsEditorApplication.h
  6. 7 1
      BansheeEditor/Include/BsEditorPrerequisites.h
  7. 46 67
      BansheeEditor/Include/BsEditorSettings.h
  8. 114 0
      BansheeEditor/Include/BsEditorSettingsRTTI.h
  9. 37 0
      BansheeEditor/Include/BsProjectSettings.h
  10. 36 0
      BansheeEditor/Include/BsProjectSettingsRTTI.h
  11. 102 0
      BansheeEditor/Include/BsSettings.h
  12. 42 0
      BansheeEditor/Include/BsSettingsRTTI.h
  13. 2 2
      BansheeEditor/Source/BsBuiltinEditorResources.cpp
  14. 69 8
      BansheeEditor/Source/BsEditorApplication.cpp
  15. 7 109
      BansheeEditor/Source/BsEditorSettings.cpp
  16. 18 0
      BansheeEditor/Source/BsProjectSettings.cpp
  17. 133 0
      BansheeEditor/Source/BsSettings.cpp
  18. 1 0
      BansheeEngine/Include/BsPrerequisites.h
  19. 2 2
      BansheeEngine/Source/BsBuiltinResources.cpp
  20. 12 0
      BansheeMono/Include/BsMonoArray.h
  21. 3 3
      ExampleProject/Main/Main.cpp
  22. 87 2
      MBansheeEditor/EditorSettings.cs
  23. 1 0
      MBansheeEditor/MBansheeEditor.csproj
  24. 121 0
      MBansheeEditor/ProjectSettings.cs
  25. 8 0
      SBansheeEditor/Include/BsScriptEditorSettings.h
  26. 42 0
      SBansheeEditor/Include/BsScriptProjectSettings.h
  27. 2 0
      SBansheeEditor/SBansheeEditor.vcxproj
  28. 6 0
      SBansheeEditor/SBansheeEditor.vcxproj.filters
  29. 79 4
      SBansheeEditor/Source/BsScriptEditorSettings.cpp
  30. 146 0
      SBansheeEditor/Source/BsScriptProjectSettings.cpp
  31. 3 3
      TODO.txt

+ 1 - 1
BansheeCore/Source/BsSceneObject.cpp

@@ -598,7 +598,7 @@ namespace BansheeEngine
 		UINT32 bufferSize = 0;
 
 		MemorySerializer serializer;
-		UINT8* buffer = serializer.encode(this, bufferSize, &bs_alloc);
+		UINT8* buffer = serializer.encode(this, bufferSize, (void*(*)(UINT32))&bs_alloc);
 
 		GameObjectManager::instance().setDeserializationMode(GODM_UseNewIds | GODM_RestoreExternal);
 		std::shared_ptr<SceneObject> cloneObj = std::static_pointer_cast<SceneObject>(serializer.decode(buffer, bufferSize));

+ 7 - 0
BansheeEditor/BansheeEditor.vcxproj

@@ -282,6 +282,7 @@
     <ClInclude Include="Include\BsEditorApplication.h" />
     <ClInclude Include="Include\BsEditorCommand.h" />
     <ClInclude Include="Include\BsBuiltinEditorResources.h" />
+    <ClInclude Include="Include\BsEditorSettingsRTTI.h" />
     <ClInclude Include="Include\BsEditorTestSuite.h" />
     <ClInclude Include="Include\BsEditorUtility.h" />
     <ClInclude Include="Include\BsEditorWidgetLayout.h" />
@@ -314,6 +315,8 @@
     <ClInclude Include="Include\BsModalWindow.h" />
     <ClInclude Include="Include\BsPlatformInfo.h" />
     <ClInclude Include="Include\BsPlatformInfoRTTI.h" />
+    <ClInclude Include="Include\BsProjectSettings.h" />
+    <ClInclude Include="Include\BsProjectSettingsRTTI.h" />
     <ClInclude Include="Include\BsScenePicking.h" />
     <ClInclude Include="Include\BsProjectLibraryEntriesRTTI.h" />
     <ClInclude Include="Include\BsEditorPrerequisites.h" />
@@ -343,6 +346,8 @@
     <ClInclude Include="Include\BsSceneViewHandler.h" />
     <ClInclude Include="Include\BsSelection.h" />
     <ClInclude Include="Include\BsSelectionRenderer.h" />
+    <ClInclude Include="Include\BsSettings.h" />
+    <ClInclude Include="Include\BsSettingsRTTI.h" />
     <ClInclude Include="Include\BsShaderIncludeHandler.h" />
     <ClInclude Include="Include\BsUndoRedo.h" />
     <ClInclude Include="Include\Win32\BsVSCodeEditor.h" />
@@ -408,6 +413,7 @@
     <ClCompile Include="Source\BsEditorSettings.cpp" />
     <ClCompile Include="Source\BsModalWindow.cpp" />
     <ClCompile Include="Source\BsPlatformInfo.cpp" />
+    <ClCompile Include="Source\BsProjectSettings.cpp" />
     <ClCompile Include="Source\BsScenePicking.cpp" />
     <ClCompile Include="Source\BsProjectLibrary.cpp" />
     <ClCompile Include="Source\BsProjectLibraryEntries.cpp" />
@@ -417,6 +423,7 @@
     <ClCompile Include="Source\BsSceneViewHandler.cpp" />
     <ClCompile Include="Source\BsSelection.cpp" />
     <ClCompile Include="Source\BsSelectionRenderer.cpp" />
+    <ClCompile Include="Source\BsSettings.cpp" />
     <ClCompile Include="Source\BsShaderIncludeHandler.cpp" />
     <ClCompile Include="Source\BsUndoRedo.cpp" />
     <ClCompile Include="Source\BsEditorApplication.cpp" />

+ 21 - 0
BansheeEditor/BansheeEditor.vcxproj.filters

@@ -273,6 +273,21 @@
     <ClInclude Include="Include\BsCmdInstantiateSO.h">
       <Filter>Header Files\Commands</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsEditorSettingsRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsSettings.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsSettingsRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsProjectSettings.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsProjectSettingsRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsEditorCommand.cpp">
@@ -494,5 +509,11 @@
     <ClCompile Include="Source\BsCmdInstantiateSO.cpp">
       <Filter>Source Files\Commands</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsSettings.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsProjectSettings.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 3 - 3
BansheeEditor/Include/BsDockManagerLayoutRTTI.h

@@ -18,18 +18,18 @@ namespace BansheeEngine
 			addPlainField("mRootEntry", 0, &DockManagerLayoutRTTI::getRootEntry, &DockManagerLayoutRTTI::setRootEntry);
 		}
 
-		virtual const String& getRTTIName()
+		virtual const String& getRTTIName() override
 		{
 			static String name = "DockManagerLayout";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId()
+		virtual UINT32 getRTTIId() override
 		{
 			return TID_DockManagerLayout;
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
 			return bs_shared_ptr_new<DockManagerLayout>();
 		}

+ 34 - 0
BansheeEditor/Include/BsEditorApplication.h

@@ -55,6 +55,23 @@ namespace BansheeEngine
 		 */
 		EditorSettingsPtr getEditorSettings() const { return mEditorSettings; }
 
+		/**
+		 * @brief	Returns a set of serializable project settings that contain
+		 *			every customizable property specific to a project.
+		 */
+		ProjectSettingsPtr getProjectSettings() const { return mProjectSettings; }
+
+		/**
+		 * @brief	Saves the current editor settings at the default location.
+		 */
+		void saveEditorSettings();
+
+		/**
+		 * @brief	Saves the current project settings at the default location.
+		 *			Does nothing if no project is loaded.
+		 */
+		void saveProjectSettings();
+
 	private:
 		virtual void onStartUp() override;
 		virtual void onShutDown() override;
@@ -72,6 +89,19 @@ namespace BansheeEngine
 		 */
 		void saveWidgetLayout(const EditorWidgetLayoutPtr& layout);
 
+		/**
+		 * @brief	Loads the previously saved editor settings from the default location.
+		 *			Overwrites any current settings.
+		 */
+		void loadEditorSettings();
+
+		/**
+		 * @brief	Loads the previously saved project settings from the default location
+		 *			within the active project. Loads default settings if no project is active.
+		 *			Overwrites any current settings.
+		 */
+		void loadProjectSettings();
+
 		/**
 		 * @copydoc	Application::getShaderIncludeHandler
 		 */
@@ -80,8 +110,12 @@ namespace BansheeEngine
 	private:
 		static const Path WIDGET_LAYOUT_PATH;
 		static const Path BUILD_DATA_PATH;
+		static const Path EDITOR_SETTINGS_PATH;
+		static const Path PROJECT_SETTINGS_PATH;
+
 		RenderAPIPlugin mActiveRAPIPlugin;
 		EditorSettingsPtr mEditorSettings;
+		ProjectSettingsPtr mProjectSettings;
 
 		DynLib* mSBansheeEditorPlugin;
 

+ 7 - 1
BansheeEditor/Include/BsEditorPrerequisites.h

@@ -67,11 +67,13 @@ namespace BansheeEngine
 	class SceneViewHandler;
 	class SelectionRenderer;
 	class DropDownWindow;
+	class ProjectSettings;
 
 	typedef std::shared_ptr<ProjectResourceMeta> ProjectResourceMetaPtr;
 	typedef std::shared_ptr<DockManagerLayout> DockManagerLayoutPtr;
 	typedef std::shared_ptr<EditorWidgetLayout> EditorWidgetLayoutPtr;
 	typedef std::shared_ptr<EditorSettings> EditorSettingsPtr;
+	typedef std::shared_ptr<ProjectSettings> ProjectSettingsPtr;
 
 	static const char* EDITOR_ASSEMBLY = "MBansheeEditor";
 	static const char* SCRIPT_EDITOR_ASSEMBLY = "MScriptEditor";
@@ -123,6 +125,10 @@ namespace BansheeEngine
 		TID_TestObjectA = 40013,
 		TID_TestObjectB = 40014,
 		TID_TestComponentC = 40015,
-		TID_TestComponentD = 40016
+		TID_TestComponentD = 40016,
+		TID_EditorSettings = 40017,
+		TID_RecentProject = 40018,
+		TID_Settings = 40019,
+		TID_ProjectSettings = 40020
 	};
 }

+ 46 - 67
BansheeEditor/Include/BsEditorSettings.h

@@ -1,14 +1,17 @@
 #pragma once
 
 #include "BsEditorPrerequisites.h"
+#include "BsSettings.h"
 #include "BsDegree.h"
 
 namespace BansheeEngine
 {
+	struct RecentProject;
+
 	/**
 	 * @brief	Contains various globally accessible editor preferences.
 	 */
-	class BS_ED_EXPORT EditorSettings
+	class BS_ED_EXPORT EditorSettings : public Settings
 	{
 	public:
 		EditorSettings();
@@ -65,6 +68,22 @@ namespace BansheeEngine
 		 */
 		UINT32 getActivePivotMode() const { return mActivePivotMode; }
 
+		/**
+		 * @brief	Retrieves the path to the last project open in the editor.
+		 */
+		Path getLastOpenProject() const { return mLastOpenProject; }
+
+		/**
+		 * @brief	Retrieves whether the last open project should be automatically loaded
+		 *			on editor start up.
+		 */
+		bool getAutoLoadLastProject() const { return mAutoLoadLastProject; }
+
+		/**
+		 * @brief	Retrieves a list of most recently loaded project paths and their last access times.
+		 */
+		const Vector<RecentProject>& getRecentProjects() const { return mRecentProjects; }
+
 		/**
 		 * @brief	Enables/disables snapping for move handles in scene view.
 		 */
@@ -116,76 +135,22 @@ namespace BansheeEngine
 		void setActivePivotMode(UINT32 value) { mActivePivotMode = value; markAsDirty(); }
 
 		/**
-		 * @brief	Adds or updates a property key/value pair with a floating point value.
-		 */
-		void setFloat(const String& name, float value);
-
-		/**
-		 * @brief	Adds or updates a property key/value pair with a signed integer value.
-		 */
-		void setInt(const String& name, INT32 value);
-
-		/**
-		 * @brief	Adds or updates a property key/value pair with a boolean value.
-		 */
-		void setBool(const String& name, bool value);
-
-		/**
-		 * @brief	Adds or updates a property key/value pair with a string value.
-		 */
-		void setString(const String& name, const WString& value);
-
-		/**
-		 * @brief	Returns the floating point value of the specified key, or the default value
-		 *			if such key cannot be found.
-		 */
-		float getFloat(const String& name, float defaultValue = 0.0f);
-
-		/**
-		 * @brief	Returns the integer point value of the specified key, or the default value
-		 *			if such key cannot be found.
-		 */
-		INT32 getInt(const String& name, INT32 defaultValue = 0);
-
-		/**
-		 * @brief	Returns the boolean point value of the specified key, or the default value
-		 *			if such key cannot be found.
-		 */
-		bool getBool(const String& name, bool defaultValue = false);
-
-		/**
-		 * @brief	Returns the string point value of the specified key, or the default value
-		 *			if such key cannot be found.
-		 */
-		WString getString(const String& name, const WString& defaultValue = StringUtil::WBLANK);
-
-		/**
-		 * @brief	Returns true if the key with the specified name exists.
+		 * @brief	Sets the path to the last project open in the editor.
 		 */
-		bool hasKey(const String& name);
+		void setLastOpenProject(const Path& value) { mLastOpenProject = value; markAsDirty(); }
 
 		/**
-		 * @brief	Deletes a key with the specified name.
+		 * @brief	Sets whether the last open project should be automatically loaded
+		 *			on editor start up.
 		 */
-		void deleteKey(const String& name);
+		void setAutoLoadLastProject(bool value) { mAutoLoadLastProject = value; markAsDirty(); }
 
 		/**
-		 * @brief	Deletes all key/value pairs.
+		 * @brief	Sets a list of most recently loaded project paths and their last access times.
 		 */
-		void deleteAllKeys();
-
-		/**
-		 * @brief	Returns a hash value that may be used for checking if any internal settings were
-		 *			modified.
-		 */
-		UINT32 getHash() const { return mHash; }
+		void setRecentProjects(const Vector<RecentProject>& value) { mRecentProjects = value; markAsDirty(); }
 
 	private:
-		/**
-		 * @brief	Marks the object as dirty so that outside objects know when to update.
-		 */
-		void markAsDirty() const { mHash++; }
-
 		bool mMoveSnapActive;
 		bool mRotateSnapActive;
 
@@ -201,11 +166,25 @@ namespace BansheeEngine
 
 		float mHandleSize;
 
-		Map<String, float> mFloatProperties;
-		Map<String, INT32> mIntProperties;
-		Map<String, bool> mBoolProperties;
-		Map<String, WString> mStringProperties;
+		Path mLastOpenProject;
+		bool mAutoLoadLastProject;
+		Vector<RecentProject> mRecentProjects;
 
-		mutable UINT32 mHash;
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class EditorSettingsRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/**
+	 * @brief	Data about a recently loaded project.
+	 */
+	struct RecentProject
+	{
+		Path path;
+		UINT64 accessTimestamp;
 	};
 }

+ 114 - 0
BansheeEditor/Include/BsEditorSettingsRTTI.h

@@ -0,0 +1,114 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsEditorSettings.h"
+#include "BsRTTIType.h"
+
+namespace BansheeEngine
+{
+	class EditorSettingsRTTI : public RTTIType <EditorSettings, Settings, EditorSettingsRTTI>
+	{
+	private:
+		BS_PLAIN_MEMBER(mMoveSnapActive);
+		BS_PLAIN_MEMBER(mRotateSnapActive);
+
+		BS_PLAIN_MEMBER(mMoveSnap);
+		BS_PLAIN_MEMBER(mRotationSnap);
+
+		BS_PLAIN_MEMBER(mGridSize);
+		BS_PLAIN_MEMBER(mGridAxisSpacing);
+
+		BS_PLAIN_MEMBER(mActiveSceneTool);
+		BS_PLAIN_MEMBER(mActiveCoordinateMode);
+		BS_PLAIN_MEMBER(mActivePivotMode);
+
+		BS_PLAIN_MEMBER(mHandleSize);
+
+		BS_PLAIN_MEMBER(mLastOpenProject);
+		BS_PLAIN_MEMBER(mAutoLoadLastProject);
+		BS_PLAIN_MEMBER(mRecentProjects);
+
+	public:
+		EditorSettingsRTTI()
+		{
+			BS_ADD_PLAIN_FIELD(mMoveSnapActive, 0);
+			BS_ADD_PLAIN_FIELD(mRotateSnapActive, 1);
+
+			BS_ADD_PLAIN_FIELD(mMoveSnap, 2);
+			BS_ADD_PLAIN_FIELD(mRotationSnap, 3);
+
+			BS_ADD_PLAIN_FIELD(mGridSize, 4);
+			BS_ADD_PLAIN_FIELD(mGridAxisSpacing, 5);
+
+			BS_ADD_PLAIN_FIELD(mActiveSceneTool, 6);
+			BS_ADD_PLAIN_FIELD(mActiveCoordinateMode, 7);
+			BS_ADD_PLAIN_FIELD(mActivePivotMode, 8);
+
+			BS_ADD_PLAIN_FIELD(mHandleSize, 9);
+
+			BS_ADD_PLAIN_FIELD(mLastOpenProject, 10);
+			BS_ADD_PLAIN_FIELD(mAutoLoadLastProject, 11);
+			BS_ADD_PLAIN_FIELD(mRecentProjects, 12);
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "EditorSettings";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_EditorSettings;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<EditorSettings>();
+		}
+	};
+
+	template<> struct RTTIPlainType <RecentProject>
+	{
+		enum { id = TID_RecentProject }; enum { hasDynamicSize = 1 };
+
+		static void toMemory(const RecentProject& data, char* memory)
+		{
+			UINT32 size = 0;
+			char* memoryStart = memory;
+			memory += sizeof(UINT32);
+			size += sizeof(UINT32);
+
+			memory = rttiWriteElem(data.path, memory, size);
+			memory = rttiWriteElem(data.accessTimestamp, memory, size);
+
+			memcpy(memoryStart, &size, sizeof(UINT32));
+		}
+
+		static UINT32 fromMemory(RecentProject& data, char* memory)
+		{
+			UINT32 size = 0;
+			memcpy(&size, memory, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			memory = rttiReadElem(data.path, memory);
+			memory = rttiReadElem(data.accessTimestamp, memory);
+
+			return size;
+		}
+
+		static UINT32 getDynamicSize(const RecentProject& data)
+		{
+			UINT64 dataSize = sizeof(UINT32) + rttiGetElemSize(data.path) + rttiGetElemSize(data.accessTimestamp);
+
+#if BS_DEBUG_MODE
+			if (dataSize > std::numeric_limits<UINT32>::max())
+			{
+				__string_throwDataOverflowException();
+			}
+#endif
+
+			return (UINT32)dataSize;
+		}
+	};
+}

+ 37 - 0
BansheeEditor/Include/BsProjectSettings.h

@@ -0,0 +1,37 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsSettings.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Contains various globally accessible project-specific preferences.
+	 */
+	class BS_ED_EXPORT ProjectSettings : public Settings
+	{
+	public:
+		ProjectSettings();
+
+		/**
+		 * @brief	Retrieves the UUID of the last scene open in the editor.
+		 */
+		String getLastOpenScene() const { return mLastOpenScene; }
+
+		/**
+		 * @brief	Sets the UUID of the last scene open in the editor.
+		 */
+		void setLastOpenScene(const String& value) { mLastOpenScene = value; markAsDirty(); }
+
+	private:
+		String mLastOpenScene;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class ProjectSettingsRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+}

+ 36 - 0
BansheeEditor/Include/BsProjectSettingsRTTI.h

@@ -0,0 +1,36 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsProjectSettings.h"
+#include "BsRTTIType.h"
+
+namespace BansheeEngine
+{
+	class ProjectSettingsRTTI : public RTTIType <ProjectSettings, Settings, ProjectSettingsRTTI>
+	{
+	private:
+		BS_PLAIN_MEMBER(mLastOpenScene);
+
+	public:
+		ProjectSettingsRTTI()
+		{
+			BS_ADD_PLAIN_FIELD(mLastOpenScene, 0);
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "ProjectSettings";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_ProjectSettings;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<ProjectSettings>();
+		}
+	};
+}

+ 102 - 0
BansheeEditor/Include/BsSettings.h

@@ -0,0 +1,102 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsIReflectable.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Contains a serializable set of generic key-value pairs.
+	 */
+	class BS_ED_EXPORT Settings : public IReflectable
+	{
+	public:
+		Settings();
+
+		/**
+		 * @brief	Adds or updates a property key/value pair with a floating point value.
+		 */
+		void setFloat(const String& name, float value);
+
+		/**
+		 * @brief	Adds or updates a property key/value pair with a signed integer value.
+		 */
+		void setInt(const String& name, INT32 value);
+
+		/**
+		 * @brief	Adds or updates a property key/value pair with a boolean value.
+		 */
+		void setBool(const String& name, bool value);
+
+		/**
+		 * @brief	Adds or updates a property key/value pair with a string value.
+		 */
+		void setString(const String& name, const WString& value);
+
+		/**
+		 * @brief	Returns the floating point value of the specified key, or the default value
+		 *			if such key cannot be found.
+		 */
+		float getFloat(const String& name, float defaultValue = 0.0f);
+
+		/**
+		 * @brief	Returns the integer point value of the specified key, or the default value
+		 *			if such key cannot be found.
+		 */
+		INT32 getInt(const String& name, INT32 defaultValue = 0);
+
+		/**
+		 * @brief	Returns the boolean point value of the specified key, or the default value
+		 *			if such key cannot be found.
+		 */
+		bool getBool(const String& name, bool defaultValue = false);
+
+		/**
+		 * @brief	Returns the string point value of the specified key, or the default value
+		 *			if such key cannot be found.
+		 */
+		WString getString(const String& name, const WString& defaultValue = StringUtil::WBLANK);
+
+		/**
+		 * @brief	Returns true if the key with the specified name exists.
+		 */
+		bool hasKey(const String& name);
+
+		/**
+		 * @brief	Deletes a key with the specified name.
+		 */
+		void deleteKey(const String& name);
+
+		/**
+		 * @brief	Deletes all key/value pairs.
+		 */
+		void deleteAllKeys();
+
+		/**
+		 * @brief	Returns a hash value that may be used for checking if any internal settings were
+		 *			modified.
+		 */
+		UINT32 getHash() const { return mHash; }
+
+	protected:
+		/**
+		 * @brief	Marks the object as dirty so that outside objects know when to update.
+		 */
+		void markAsDirty() const { mHash++; }
+
+		Map<String, float> mFloatProperties;
+		Map<String, INT32> mIntProperties;
+		Map<String, bool> mBoolProperties;
+		Map<String, WString> mStringProperties;
+
+		mutable UINT32 mHash;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class SettingsRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+}

+ 42 - 0
BansheeEditor/Include/BsSettingsRTTI.h

@@ -0,0 +1,42 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsSettings.h"
+#include "BsRTTIType.h"
+
+namespace BansheeEngine
+{
+	class SettingsRTTI : public RTTIType <Settings, IReflectable, SettingsRTTI>
+	{
+	private:
+		BS_PLAIN_MEMBER(mFloatProperties);
+		BS_PLAIN_MEMBER(mIntProperties);
+		BS_PLAIN_MEMBER(mBoolProperties);
+		BS_PLAIN_MEMBER(mStringProperties);
+
+	public:
+		SettingsRTTI()
+		{
+			BS_ADD_PLAIN_FIELD(mFloatProperties, 13);
+			BS_ADD_PLAIN_FIELD(mIntProperties, 14);
+			BS_ADD_PLAIN_FIELD(mBoolProperties, 15);
+			BS_ADD_PLAIN_FIELD(mStringProperties, 16);
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "Settings";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_Settings;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<Settings>();
+		}
+	};
+}

+ 2 - 2
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -66,12 +66,12 @@ namespace BansheeEngine
 	const Path BuiltinEditorResources::IconFolder = L"Skin\\Icons";
 	const Path BuiltinEditorResources::ShaderIncludeFolder = L"Includes\\";
 
-	const Path BuiltinEditorResources::BuiltinRawDataFolder = L"..\\..\\..\\..\\Data\\Raw\\Editor\\";
+	const Path BuiltinEditorResources::BuiltinRawDataFolder = RUNTIME_DATA_PATH + L"Raw\\Editor\\";
 	const Path BuiltinEditorResources::EditorRawSkinFolder = BuiltinRawDataFolder + SkinFolder;
 	const Path BuiltinEditorResources::EditorRawShaderFolder = BuiltinRawDataFolder + ShaderFolder;
 	const Path BuiltinEditorResources::EditorRawShaderIncludeFolder = BuiltinRawDataFolder + ShaderIncludeFolder;
 
-	const Path BuiltinEditorResources::BuiltinDataFolder = L"..\\..\\..\\..\\Data\\Editor\\";
+	const Path BuiltinEditorResources::BuiltinDataFolder = RUNTIME_DATA_PATH + L"Editor\\";
 	const Path BuiltinEditorResources::EditorSkinFolder = BuiltinDataFolder + SkinFolder;
 	const Path BuiltinEditorResources::EditorIconFolder = BuiltinDataFolder + IconFolder;
 	const Path BuiltinEditorResources::EditorShaderFolder = BuiltinDataFolder + ShaderFolder;

+ 69 - 8
BansheeEditor/Source/BsEditorApplication.cpp

@@ -19,6 +19,8 @@
 #include "BsDropDownWindowManager.h"
 #include "BsPrefabImporter.h"
 #include "BsProjectLibrary.h"
+#include "BsProjectSettings.h"
+#include "BsEditorSettings.h"
 
 // DEBUG ONLY
 #include "BsResources.h"
@@ -39,7 +41,6 @@
 #include "BsGUILayout.h"
 #include "BsEvent.h"
 #include "BsCoreRenderer.h"
-#include "BsEditorSettings.h"
 #include "BsMesh.h"
 #include "BsMath.h"
 #include "BsDebug.h"
@@ -48,6 +49,8 @@ namespace BansheeEngine
 {
 	const Path EditorApplication::WIDGET_LAYOUT_PATH = L"Internal\\Layout.asset";
 	const Path EditorApplication::BUILD_DATA_PATH = L"Internal\\BuildData.asset";
+	const Path EditorApplication::EDITOR_SETTINGS_PATH = RUNTIME_DATA_PATH + L"Settings.asset";
+	const Path EditorApplication::PROJECT_SETTINGS_PATH = L"Internal\\Settings.asset";
 
 	RENDER_WINDOW_DESC createRenderWindowDesc()
 	{
@@ -98,8 +101,8 @@ namespace BansheeEngine
 	{
 		Application::onStartUp();
 
-		// TODO - Load project settings
-		mEditorSettings = bs_shared_ptr_new<EditorSettings>();
+		loadEditorSettings();
+		loadProjectSettings();
 
 		BuiltinEditorResources::startUp();
 
@@ -151,7 +154,7 @@ namespace BansheeEngine
 		/* 								DEBUG CODE                      		*/
 		/************************************************************************/
 
-		HShader dummyParsedShader = Importer::instance().import<Shader>("..\\..\\..\\..\\Data\\Raw\\Engine\\Shaders\\TestFX.bsl");
+		HShader dummyParsedShader = Importer::instance().import<Shader>(RUNTIME_DATA_PATH + "Raw\\Engine\\Shaders\\TestFX.bsl");
 		assert(dummyParsedShader != nullptr); // Ad hoc unit test
 
 		RenderAPICore* renderAPI = RenderAPICore::instancePtr();
@@ -159,7 +162,7 @@ namespace BansheeEngine
 		HSceneObject testModelGO = SceneObject::create("TestMesh");
 		HRenderable testRenderable = testModelGO->addComponent<Renderable>();
 
-		WString testShaderLoc = L"..\\..\\..\\..\\Data\\Test.bsl";;
+		Path testShaderLoc = RUNTIME_DATA_PATH + L"Test.bsl";;
 		
 		mTestShader = Importer::instance().import<Shader>(testShaderLoc);
 
@@ -169,8 +172,8 @@ namespace BansheeEngine
 
 		mTestMaterial = Material::create(mTestShader);
 
-		mTestTexRef = static_resource_cast<Texture>(Importer::instance().import(L"..\\..\\..\\..\\Data\\Examples\\Dragon.tga"));
-		mDbgMeshRef = static_resource_cast<Mesh>(Importer::instance().import(L"..\\..\\..\\..\\Data\\Examples\\Dragon.fbx"));
+		mTestTexRef = static_resource_cast<Texture>(Importer::instance().import(RUNTIME_DATA_PATH + L"Examples\\Dragon.tga"));
+		mDbgMeshRef = static_resource_cast<Mesh>(Importer::instance().import(RUNTIME_DATA_PATH + L"Examples\\Dragon.fbx"));
 
 		gResources().save(mTestTexRef, L"C:\\ExportTest.tex", true);
 		gResources().save(mDbgMeshRef, L"C:\\ExportMesh.mesh", true);
@@ -218,7 +221,8 @@ namespace BansheeEngine
 		ScenePicking::shutDown();
 
 		saveWidgetLayout(EditorWidgetManager::instance().getLayout());
-		// TODO - Save project settings
+		saveEditorSettings();
+		saveProjectSettings();
 
 		DropDownWindowManager::shutDown();
 		EditorWidgetManager::shutDown();
@@ -315,6 +319,63 @@ namespace BansheeEngine
 		fs.encode(layout.get());
 	}
 
+	void EditorApplication::loadEditorSettings()
+	{
+		Path absoluteDataPath = FileSystem::getWorkingDirectoryPath();
+		absoluteDataPath.append(EDITOR_SETTINGS_PATH);
+
+		if (FileSystem::exists(absoluteDataPath))
+		{
+			FileDecoder fs(absoluteDataPath);
+			mEditorSettings = std::static_pointer_cast<EditorSettings>(fs.decode());
+		}
+		
+		if (mEditorSettings == nullptr)
+			mEditorSettings = bs_shared_ptr_new<EditorSettings>();
+	}
+
+	void EditorApplication::saveEditorSettings()
+	{
+		if (mEditorSettings == nullptr)
+			return;
+
+		Path absoluteDataPath = FileSystem::getWorkingDirectoryPath();
+		absoluteDataPath.append(EDITOR_SETTINGS_PATH);
+
+		FileEncoder fs(absoluteDataPath);
+		fs.encode(mEditorSettings.get());
+	}
+
+	void EditorApplication::loadProjectSettings()
+	{
+		if (isProjectLoaded())
+		{
+			Path absoluteDataPath = getProjectPath();
+			absoluteDataPath.append(PROJECT_SETTINGS_PATH);
+
+			if (FileSystem::exists(absoluteDataPath))
+			{
+				FileDecoder fs(absoluteDataPath);
+				mProjectSettings = std::static_pointer_cast<ProjectSettings>(fs.decode());
+			}
+		}
+
+		if (mProjectSettings == nullptr)
+			mProjectSettings = bs_shared_ptr_new<ProjectSettings>();
+	}
+
+	void EditorApplication::saveProjectSettings()
+	{
+		if (mProjectSettings == nullptr || !isProjectLoaded())
+			return;
+
+		Path absoluteDataPath = getProjectPath();
+		absoluteDataPath.append(PROJECT_SETTINGS_PATH);
+
+		FileEncoder fs(absoluteDataPath);
+		fs.encode(mProjectSettings.get());
+	}
+
 	ShaderIncludeHandlerPtr EditorApplication::getShaderIncludeHandler() const
 	{
 		return bs_shared_ptr_new<EditorShaderIncludeHandler>();

+ 7 - 109
BansheeEditor/Source/BsEditorSettings.cpp

@@ -1,123 +1,21 @@
 #include "BsEditorSettings.h"
+#include "BsEditorSettingsRTTI.h"
 
 namespace BansheeEngine
 {
 	EditorSettings::EditorSettings()
 		:mMoveSnapActive(false), mRotateSnapActive(false), mMoveSnap(0.1f), mRotationSnap(20.0f),
-		mGridSize(256), mGridAxisSpacing(1.0f), mHandleSize(0.10f), mHash(0), mActiveSceneTool(1 /* Move */),
+		mGridSize(256), mGridAxisSpacing(1.0f), mHandleSize(0.10f), mActiveSceneTool(1 /* Move */),
 		mActiveCoordinateMode(0), mActivePivotMode(0)
 	{ }
-
-	void EditorSettings::setFloat(const String& name, float value)
-	{
-		mFloatProperties[name] = value;
-		mIntProperties.erase(name);
-		mBoolProperties.erase(name);
-		mStringProperties.erase(name);
-
-		markAsDirty();
-	}
-
-	void EditorSettings::setInt(const String& name, INT32 value)
+	
+	RTTITypeBase* EditorSettings::getRTTIStatic()
 	{
-		mFloatProperties.erase(name);
-		mIntProperties[name] = value;
-		mBoolProperties.erase(name);
-		mStringProperties.erase(name);
-
-		markAsDirty();
+		return EditorSettingsRTTI::instance();
 	}
 
-	void EditorSettings::setBool(const String& name, bool value)
+	RTTITypeBase* EditorSettings::getRTTI() const
 	{
-		mFloatProperties.erase(name);
-		mIntProperties.erase(name);
-		mBoolProperties[name] = value; 
-		mStringProperties.erase(name);
-
-		markAsDirty();
-	}
-
-	void EditorSettings::setString(const String& name, const WString& value)
-	{
-		mFloatProperties.erase(name);
-		mIntProperties.erase(name);
-		mBoolProperties.erase(name);
-		mStringProperties[name] = value;
-
-		markAsDirty();
-	}
-
-	float EditorSettings::getFloat(const String& name, float defaultValue)
-	{
-		auto iterFind = mFloatProperties.find(name);
-		if (iterFind != mFloatProperties.end())
-			return iterFind->second;
-
-		return defaultValue;
-	}
-
-	INT32 EditorSettings::getInt(const String& name, INT32 defaultValue)
-	{
-		auto iterFind = mIntProperties.find(name);
-		if (iterFind != mIntProperties.end())
-			return iterFind->second;
-
-		return defaultValue;
-	}
-
-	bool EditorSettings::getBool(const String& name, bool defaultValue)
-	{
-		auto iterFind = mBoolProperties.find(name);
-		if (iterFind != mBoolProperties.end())
-			return iterFind->second;
-
-		return defaultValue;
-	}
-
-	WString EditorSettings::getString(const String& name, const WString& defaultValue)
-	{
-		auto iterFind = mStringProperties.find(name);
-		if (iterFind != mStringProperties.end())
-			return iterFind->second;
-
-		return defaultValue;
-	}
-
-	bool EditorSettings::hasKey(const String& name)
-	{
-		if (mFloatProperties.find(name) != mFloatProperties.end())
-			return true;
-		
-		if (mIntProperties.find(name) != mIntProperties.end())
-			return true;
-
-		if (mBoolProperties.find(name) != mBoolProperties.end())
-			return true;
-
-		if (mStringProperties.find(name) != mStringProperties.end())
-			return true;
-
-		return false;
-	}
-
-	void EditorSettings::deleteKey(const String& name)
-	{
-		mFloatProperties.erase(name);
-		mIntProperties.erase(name);
-		mBoolProperties.erase(name);
-		mStringProperties.erase(name);
-
-		markAsDirty();
-	}
-
-	void EditorSettings::deleteAllKeys()
-	{
-		mFloatProperties.clear();
-		mIntProperties.clear();
-		mBoolProperties.clear();
-		mStringProperties.clear();
-
-		markAsDirty();
+		return EditorSettings::getRTTIStatic();
 	}
 }

+ 18 - 0
BansheeEditor/Source/BsProjectSettings.cpp

@@ -0,0 +1,18 @@
+#include "BsProjectSettings.h"
+#include "BsProjectSettingsRTTI.h"
+
+namespace BansheeEngine
+{
+	ProjectSettings::ProjectSettings()
+	{ }
+
+	RTTITypeBase* ProjectSettings::getRTTIStatic()
+	{
+		return ProjectSettingsRTTI::instance();
+	}
+
+	RTTITypeBase* ProjectSettings::getRTTI() const
+	{
+		return ProjectSettings::getRTTIStatic();
+	}
+}

+ 133 - 0
BansheeEditor/Source/BsSettings.cpp

@@ -0,0 +1,133 @@
+#include "BsSettings.h"
+#include "BsSettingsRTTI.h"
+
+namespace BansheeEngine
+{
+	Settings::Settings()
+		:mHash(0)
+	{ }
+
+	void Settings::setFloat(const String& name, float value)
+	{
+		mFloatProperties[name] = value;
+		mIntProperties.erase(name);
+		mBoolProperties.erase(name);
+		mStringProperties.erase(name);
+
+		markAsDirty();
+	}
+
+	void Settings::setInt(const String& name, INT32 value)
+	{
+		mFloatProperties.erase(name);
+		mIntProperties[name] = value;
+		mBoolProperties.erase(name);
+		mStringProperties.erase(name);
+
+		markAsDirty();
+	}
+
+	void Settings::setBool(const String& name, bool value)
+	{
+		mFloatProperties.erase(name);
+		mIntProperties.erase(name);
+		mBoolProperties[name] = value;
+		mStringProperties.erase(name);
+
+		markAsDirty();
+	}
+
+	void Settings::setString(const String& name, const WString& value)
+	{
+		mFloatProperties.erase(name);
+		mIntProperties.erase(name);
+		mBoolProperties.erase(name);
+		mStringProperties[name] = value;
+
+		markAsDirty();
+	}
+
+	float Settings::getFloat(const String& name, float defaultValue)
+	{
+		auto iterFind = mFloatProperties.find(name);
+		if (iterFind != mFloatProperties.end())
+			return iterFind->second;
+
+		return defaultValue;
+	}
+
+	INT32 Settings::getInt(const String& name, INT32 defaultValue)
+	{
+		auto iterFind = mIntProperties.find(name);
+		if (iterFind != mIntProperties.end())
+			return iterFind->second;
+
+		return defaultValue;
+	}
+
+	bool Settings::getBool(const String& name, bool defaultValue)
+	{
+		auto iterFind = mBoolProperties.find(name);
+		if (iterFind != mBoolProperties.end())
+			return iterFind->second;
+
+		return defaultValue;
+	}
+
+	WString Settings::getString(const String& name, const WString& defaultValue)
+	{
+		auto iterFind = mStringProperties.find(name);
+		if (iterFind != mStringProperties.end())
+			return iterFind->second;
+
+		return defaultValue;
+	}
+
+	bool Settings::hasKey(const String& name)
+	{
+		if (mFloatProperties.find(name) != mFloatProperties.end())
+			return true;
+
+		if (mIntProperties.find(name) != mIntProperties.end())
+			return true;
+
+		if (mBoolProperties.find(name) != mBoolProperties.end())
+			return true;
+
+		if (mStringProperties.find(name) != mStringProperties.end())
+			return true;
+
+		return false;
+	}
+
+	void Settings::deleteKey(const String& name)
+	{
+		mFloatProperties.erase(name);
+		mIntProperties.erase(name);
+		mBoolProperties.erase(name);
+		mStringProperties.erase(name);
+
+		markAsDirty();
+	}
+
+	void Settings::deleteAllKeys()
+	{
+		mFloatProperties.clear();
+		mIntProperties.clear();
+		mBoolProperties.clear();
+		mStringProperties.clear();
+
+		markAsDirty();
+	}
+
+
+	RTTITypeBase* Settings::getRTTIStatic()
+	{
+		return SettingsRTTI::instance();
+	}
+
+	RTTITypeBase* Settings::getRTTI() const
+	{
+		return Settings::getRTTIStatic();
+	}
+}

+ 1 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -136,6 +136,7 @@ namespace BansheeEngine
 	static const char* SCRIPT_GAME_ASSEMBLY = "MScriptGame";
 	static const Path ASSEMBLY_PATH = "..\\..\\Assemblies\\";
 	static const Path GAME_RESOURCES_PATH = "..\\..\\..\\Resources\\";
+	static const Path RUNTIME_DATA_PATH = L"..\\..\\..\\..\\Data\\";
 
 	/**
 	 * @brief	RTTI types.

+ 2 - 2
BansheeEngine/Source/BsBuiltinResources.cpp

@@ -42,13 +42,13 @@ namespace BansheeEngine
 	const Path BuiltinResources::SkinFolder = L"Skin\\";
 	const Path BuiltinResources::ShaderIncludeFolder = L"Includes\\";
 
-	const Path BuiltinResources::BuiltinRawDataFolder = L"..\\..\\..\\..\\Data\\Raw\\Engine\\";
+	const Path BuiltinResources::BuiltinRawDataFolder = RUNTIME_DATA_PATH + L"Raw\\Engine\\";
 	const Path BuiltinResources::EngineRawSkinFolder = BuiltinRawDataFolder + SkinFolder;
 	const Path BuiltinResources::EngineRawCursorFolder = BuiltinRawDataFolder + CursorFolder;
 	const Path BuiltinResources::EngineRawShaderFolder = BuiltinRawDataFolder + ShaderFolder;
 	const Path BuiltinResources::EngineRawShaderIncludeFolder = BuiltinRawDataFolder + ShaderIncludeFolder;
 
-	const Path BuiltinResources::BuiltinDataFolder = L"..\\..\\..\\..\\Data\\Engine\\";
+	const Path BuiltinResources::BuiltinDataFolder = RUNTIME_DATA_PATH + L"Engine\\";
 	const Path BuiltinResources::EngineSkinFolder = BuiltinDataFolder + SkinFolder;
 	const Path BuiltinResources::EngineCursorFolder = BuiltinDataFolder + CursorFolder;
 	const Path BuiltinResources::EngineShaderFolder = BuiltinDataFolder + ShaderFolder;

+ 12 - 0
BansheeMono/Include/BsMonoArray.h

@@ -72,6 +72,18 @@ namespace BansheeEngine
 			return ScriptArray(mono_get_int32_class(), size);
 		}
 
+		template<>
+		static ScriptArray create<UINT64>(UINT32 size)
+		{
+			return ScriptArray(mono_get_uint64_class(), size);
+		}
+
+		template<>
+		static ScriptArray create<INT64>(UINT32 size)
+		{
+			return ScriptArray(mono_get_int64_class(), size);
+		}
+
 		template<>
 		static ScriptArray create<WString>(UINT32 size)
 		{

+ 3 - 3
ExampleProject/Main/Main.cpp

@@ -126,9 +126,9 @@ int CALLBACK WinMain(
 
 namespace BansheeEngine
 {
-	Path exampleModelPath = "..\\..\\..\\..\\Data\\Examples\\Dragon.fbx";
-	Path exampleTexturePath = "..\\..\\..\\..\\Data\\Examples\\Dragon.tga";
-	Path exampleShaderPath = "..\\..\\..\\..\\Data\\Examples\\Example.bsl";
+	Path exampleModelPath = RUNTIME_DATA_PATH + "Examples\\Dragon.fbx";
+	Path exampleTexturePath = RUNTIME_DATA_PATH + "Examples\\Dragon.tga";
+	Path exampleShaderPath = RUNTIME_DATA_PATH + "Examples\\Example.bsl";
 
 	GUIButton* toggleFullscreenButton = nullptr;
 	bool fullscreen = false;

+ 87 - 2
MBansheeEditor/EditorSettings.cs

@@ -1,7 +1,9 @@
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Linq;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Text;
 using System.Threading.Tasks;
 using BansheeEngine;
@@ -58,6 +60,58 @@ namespace BansheeEditor
             set { Internal_SetActivePivotMode((int)value); }
         }
 
+        public static string LastOpenProject
+        {
+            get { return Internal_GetLastOpenProject(); }
+            set { Internal_SetLastOpenProject(value); }
+        }
+
+        public static bool AutoLoadLastProject
+        {
+            get { return Internal_GetAutoLoadLastProject(); }
+            set { Internal_SetAutoLoadLastProject(value); }
+        }
+
+        public static RecentProject[] RecentProjects
+        {
+            get
+            {
+                string[] paths;
+                UInt64[] timeStamps;
+
+                Internal_GetRecentProjects(out paths, out timeStamps);
+                RecentProject[] output = new RecentProject[paths.Length];
+
+                for (int i = 0; i < paths.Length; i++)
+                    output[i] = new RecentProject(paths[i], timeStamps[i]);
+
+                return output;
+            }
+
+            set
+            {
+                int numEntries = 0;
+                if (value != null)
+                    numEntries = value.Length;
+
+                string[] paths = new string[numEntries];
+                UInt64[] timeStamps = new UInt64[numEntries];
+
+                for (int i = 0; i < numEntries; i++)
+                {
+                    paths[i] = value[i].path;
+                    timeStamps[i] = value[i].accessTimestamp;
+                }
+
+                Internal_SetRecentProjects(paths, timeStamps);
+            }
+        }
+
+        public static int Hash
+        {
+            get { return Internal_GetHash(); }
+        }
+
         public static void SetFloat(string name, float value)
         {
             Internal_SetFloat(name, value);
@@ -113,9 +167,9 @@ namespace BansheeEditor
             Internal_DeleteAllKeys();
         }
 
-        public static int Hash
+        public static void Save()
         {
-            get { return Internal_GetHash(); }
+            Internal_Save();
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
@@ -158,6 +212,21 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetActivePivotMode(int value);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_GetLastOpenProject();
+        [MethodImpl(MethodImplOptions.InternalCall)]
+         private static extern void Internal_SetLastOpenProject(string value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_GetAutoLoadLastProject();
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetAutoLoadLastProject(bool value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetRecentProjects(out string[] paths, out UInt64[] timestamps);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetRecentProjects(string[] paths, UInt64[] timestamps);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetFloat(string name, float value);
         [MethodImpl(MethodImplOptions.InternalCall)]
@@ -185,5 +254,21 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern int Internal_GetHash();
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Save();
+    }
+
+    // Note: Must match C++ struct RecentProject
+    [StructLayout(LayoutKind.Sequential)]
+    public struct RecentProject
+    {
+        public RecentProject(string path, UInt64 timestamp)
+        {
+            this.path = path;
+            this.accessTimestamp = timestamp;
+        }
+
+        public string path;
+        public UInt64 accessTimestamp;
     }
 }

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -104,6 +104,7 @@
     <Compile Include="MenuItem.cs" />
     <Compile Include="ModalWindow.cs" />
     <Compile Include="ProgressBar.cs" />
+    <Compile Include="ProjectSettings.cs" />
     <Compile Include="ProjectWindow.cs" />
     <Compile Include="Scene\SceneCamera.cs" />
     <Compile Include="Scene\SceneViewHandler.cs" />

+ 121 - 0
MBansheeEditor/ProjectSettings.cs

@@ -0,0 +1,121 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    internal static class ProjectSettings
+    {
+        public static string LastOpenScene
+        {
+            get { return Internal_GetLastOpenScene(); }
+            set { Internal_SetLastOpenScene(value); }
+        }
+
+        public static int Hash
+        {
+            get { return Internal_GetHash(); }
+        }
+
+        public static void SetFloat(string name, float value)
+        {
+            Internal_SetFloat(name, value);
+        }
+
+        public static void SetInt(string name, int value)
+        {
+            Internal_SetInt(name, value);
+        }
+
+        public static void SetBool(string name, bool value)
+        {
+            Internal_SetBool(name, value);
+        }
+
+        public static void SetString(string name, String value)
+        {
+            Internal_SetString(name, value);
+        }
+
+        public static float GetFloat(string name, float defaultValue = 0.0f)
+        {
+            return Internal_GetFloat(name, defaultValue);
+        }
+
+        public static int GetInt(string name, int defaultValue = 0)
+        {
+            return Internal_GetInt(name, defaultValue);
+        }
+
+        public static bool GetBool(string name, bool defaultValue = false)
+        {
+            return Internal_GetBool(name, defaultValue);
+        }
+
+        public static String GetString(string name, string defaultValue = "")
+        {
+            return Internal_GetString(name, defaultValue);
+        }
+
+        public static bool HasKey(string name)
+        {
+            return Internal_HasKey(name);
+        }
+
+        public static void DeleteKey(string name)
+        {
+            Internal_DeleteKey(name);
+        }
+
+        public static void DeleteAllKeys()
+        {
+            Internal_DeleteAllKeys();
+        }
+
+        public static void Save()
+        {
+            Internal_Save();
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_GetLastOpenScene();
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLastOpenScene(string value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetFloat(string name, float value);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetInt(string name, int value);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetBool(string name, bool value);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetString(string name, String value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetFloat(string name, float defaultValue);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetInt(string name, int defaultValue);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_GetBool(string name, bool defaultValue);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_GetString(string name, string defaultValue);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_HasKey(string name);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DeleteKey(string name);
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_DeleteAllKeys();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetHash();
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Save();
+    }
+}

+ 8 - 0
SBansheeEditor/Include/BsScriptEditorSettings.h

@@ -36,6 +36,13 @@ namespace BansheeEngine
 		static UINT32 internal_GetActivePivotMode();
 		static void internal_SetActivePivotMode(UINT32 value);
 
+		static MonoString* internal_GetLastOpenProject();
+		static void internal_SetLastOpenProject(MonoString* value);
+		static bool internal_GetAutoLoadLastProject();
+		static void internal_SetAutoLoadLastProject(bool value);
+		static void internal_GetRecentProjects(MonoArray** paths, MonoArray** timeStamps);
+		static void internal_SetRecentProjects(MonoArray* paths, MonoArray* timeStamps);
+
 		static void internal_SetFloat(MonoString* name, float value);
 		static void internal_SetInt(MonoString* name, int value);
 		static void internal_SetBool(MonoString* name, bool value);
@@ -51,5 +58,6 @@ namespace BansheeEngine
 		static void internal_DeleteAllKeys();
 
 		static UINT32 internal_GetHash();
+		static void internal_Save();
 	};
 }

+ 42 - 0
SBansheeEditor/Include/BsScriptProjectSettings.h

@@ -0,0 +1,42 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Interop class between C++ & CLR for ProjectSettings stored in EditorApplication.
+	 */
+	class BS_SCR_BED_EXPORT ScriptProjectSettings : public ScriptObject <ScriptProjectSettings>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "ProjectSettings")
+
+	private:
+		ScriptProjectSettings(MonoObject* instance);
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static MonoString* internal_GetLastOpenScene();
+		static void internal_SetLastOpenScene(MonoString* value);
+
+		static void internal_SetFloat(MonoString* name, float value);
+		static void internal_SetInt(MonoString* name, int value);
+		static void internal_SetBool(MonoString* name, bool value);
+		static void internal_SetString(MonoString* name, MonoString* value);
+
+		static float internal_GetFloat(MonoString* name, float defaultValue);
+		static int internal_GetInt(MonoString* name, int defaultValue);
+		static bool internal_GetBool(MonoString* name, bool defaultValue);
+		static MonoString* internal_GetString(MonoString* name, MonoString* defaultValue);
+
+		static bool internal_HasKey(MonoString* name);
+		static void internal_DeleteKey(MonoString* name);
+		static void internal_DeleteAllKeys();
+
+		static UINT32 internal_GetHash();
+		static void internal_Save();
+	};
+}

+ 2 - 0
SBansheeEditor/SBansheeEditor.vcxproj

@@ -280,6 +280,7 @@
     <ClInclude Include="Include\BsScriptPlatformInfo.h" />
     <ClInclude Include="Include\BsScriptPrefabUtility.h" />
     <ClInclude Include="Include\BsScriptProjectLibrary.h" />
+    <ClInclude Include="Include\BsScriptProjectSettings.h" />
     <ClInclude Include="Include\BsScriptSceneViewHandler.h" />
     <ClInclude Include="Include\BsScriptSelection.h" />
     <ClInclude Include="Include\BsScriptUndoRedo.h" />
@@ -334,6 +335,7 @@
     <ClCompile Include="Source\BsScriptPlatformInfo.cpp" />
     <ClCompile Include="Source\BsScriptPrefabUtility.cpp" />
     <ClCompile Include="Source\BsScriptProjectLibrary.cpp" />
+    <ClCompile Include="Source\BsScriptProjectSettings.cpp" />
     <ClCompile Include="Source\BsScriptSceneViewHandler.cpp" />
     <ClCompile Include="Source\BsScriptSelection.cpp" />
     <ClCompile Include="Source\BsScriptUndoRedo.cpp" />

+ 6 - 0
SBansheeEditor/SBansheeEditor.vcxproj.filters

@@ -171,6 +171,9 @@
     <ClInclude Include="Include\BsEditorResourceLoader.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptProjectSettings.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
@@ -329,5 +332,8 @@
     <ClCompile Include="Source\BsEditorResourceLoader.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptProjectSettings.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 79 - 4
SBansheeEditor/Source/BsScriptEditorSettings.cpp

@@ -30,6 +30,12 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_SetActiveCoordinateMode", &ScriptEditorSettings::internal_SetActiveCoordinateMode);
 		metaData.scriptClass->addInternalCall("Internal_GetActivePivotMode", &ScriptEditorSettings::internal_GetActivePivotMode);
 		metaData.scriptClass->addInternalCall("Internal_SetActivePivotMode", &ScriptEditorSettings::internal_SetActivePivotMode);
+		metaData.scriptClass->addInternalCall("Internal_GetLastOpenProject", &ScriptEditorSettings::internal_GetLastOpenProject);
+		metaData.scriptClass->addInternalCall("Internal_SetLastOpenProject", &ScriptEditorSettings::internal_SetLastOpenProject);
+		metaData.scriptClass->addInternalCall("Internal_GetAutoLoadLastProject", &ScriptEditorSettings::internal_GetAutoLoadLastProject);
+		metaData.scriptClass->addInternalCall("Internal_SetAutoLoadLastProject", &ScriptEditorSettings::internal_SetAutoLoadLastProject);
+		metaData.scriptClass->addInternalCall("Internal_GetRecentProjects", &ScriptEditorSettings::internal_GetRecentProjects);
+		metaData.scriptClass->addInternalCall("Internal_SetRecentProjects", &ScriptEditorSettings::internal_SetRecentProjects);
 		metaData.scriptClass->addInternalCall("Internal_SetFloat", &ScriptEditorSettings::internal_SetFloat);
 		metaData.scriptClass->addInternalCall("Internal_SetInt", &ScriptEditorSettings::internal_SetInt);
 		metaData.scriptClass->addInternalCall("Internal_SetBool", &ScriptEditorSettings::internal_SetBool);
@@ -42,6 +48,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_DeleteKey", &ScriptEditorSettings::internal_DeleteKey);
 		metaData.scriptClass->addInternalCall("Internal_DeleteAllKeys", &ScriptEditorSettings::internal_DeleteAllKeys);
 		metaData.scriptClass->addInternalCall("Internal_GetHash", &ScriptEditorSettings::internal_GetHash);
+		metaData.scriptClass->addInternalCall("Internal_Save", &ScriptEditorSettings::internal_Save);
 	}
 
 	bool ScriptEditorSettings::internal_GetMoveHandleSnapActive()
@@ -140,6 +147,68 @@ namespace BansheeEngine
 		settings->setActivePivotMode(value);
 	}
 
+	MonoString* ScriptEditorSettings::internal_GetLastOpenProject()
+	{
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		return MonoUtil::wstringToMono(MonoManager::instance().getDomain(), settings->getLastOpenProject().toWString());
+	}
+
+	void ScriptEditorSettings::internal_SetLastOpenProject(MonoString* value)
+	{
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		settings->setLastOpenProject(MonoUtil::monoToWString(value));
+	}
+
+	bool ScriptEditorSettings::internal_GetAutoLoadLastProject()
+	{
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		return settings->getAutoLoadLastProject();
+	}
+
+	void ScriptEditorSettings::internal_SetAutoLoadLastProject(bool value)
+	{
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		settings->setAutoLoadLastProject(value);
+	}
+
+	void ScriptEditorSettings::internal_GetRecentProjects(MonoArray** paths, MonoArray** timeStamps)
+	{
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		const Vector<RecentProject>& recentProjects = settings->getRecentProjects();
+		UINT32 numEntries = (UINT32)recentProjects.size();
+
+		ScriptArray outputPaths = ScriptArray::create<WString>(numEntries);
+		ScriptArray outputTimeStamps = ScriptArray::create<UINT64>(numEntries);
+
+		for (UINT32 i = 0; i < numEntries; i++)
+		{
+			MonoString* monoPath = MonoUtil::wstringToMono(MonoManager::instance().getDomain(), recentProjects[i].path.toWString());
+
+			outputPaths.set(i, monoPath);
+			outputTimeStamps.set(i, recentProjects[i].accessTimestamp);
+		}
+
+		*paths = outputPaths.getInternal();
+		*timeStamps = outputPaths.getInternal();
+	}
+
+	void ScriptEditorSettings::internal_SetRecentProjects(MonoArray* paths, MonoArray* timeStamps)
+	{
+		ScriptArray pathsArray(paths);
+		ScriptArray timeStampsArray(timeStamps);
+		UINT32 numEntries = pathsArray.size();
+
+		Vector<RecentProject> recentProjects(numEntries);
+		for (UINT32 i = 0; i < numEntries; i++)
+		{
+			recentProjects[i].path = pathsArray.get<WString>(i);
+			recentProjects[i].accessTimestamp = timeStampsArray.get<UINT64>(i);
+		}
+
+		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
+		settings->setRecentProjects(recentProjects);
+	}
+
 	void ScriptEditorSettings::internal_SetFloat(MonoString* name, float value)
 	{
 		String nativeName = MonoUtil::monoToString(name);
@@ -178,7 +247,7 @@ namespace BansheeEngine
 		String nativeName = MonoUtil::monoToString(name);
 
 		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
-		return settings->getFloat(nativeName);
+		return settings->getFloat(nativeName, defaultValue);
 	}
 
 	int ScriptEditorSettings::internal_GetInt(MonoString* name, int defaultValue)
@@ -186,7 +255,7 @@ namespace BansheeEngine
 		String nativeName = MonoUtil::monoToString(name);
 
 		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
-		return settings->getInt(nativeName);
+		return settings->getInt(nativeName, defaultValue);
 	}
 
 	bool ScriptEditorSettings::internal_GetBool(MonoString* name, bool defaultValue)
@@ -194,15 +263,16 @@ namespace BansheeEngine
 		String nativeName = MonoUtil::monoToString(name);
 
 		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
-		return settings->getBool(nativeName);
+		return settings->getBool(nativeName, defaultValue);
 	}
 
 	MonoString* ScriptEditorSettings::internal_GetString(MonoString* name, MonoString* defaultValue)
 	{
 		String nativeName = MonoUtil::monoToString(name);
+		WString nativeDefaultValue = MonoUtil::monoToWString(defaultValue);
 
 		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
-		WString nativeValue = settings->getString(nativeName);
+		WString nativeValue = settings->getString(nativeName, nativeDefaultValue);
 
 		return MonoUtil::wstringToMono(MonoManager::instance().getDomain(), nativeValue);
 	}
@@ -234,4 +304,9 @@ namespace BansheeEngine
 		EditorSettingsPtr settings = gEditorApplication().getEditorSettings();
 		return settings->getHash();
 	}
+
+	void ScriptEditorSettings::internal_Save()
+	{
+		gEditorApplication().saveEditorSettings();
+	}
 }

+ 146 - 0
SBansheeEditor/Source/BsScriptProjectSettings.cpp

@@ -0,0 +1,146 @@
+#include "BsScriptProjectSettings.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsMonoUtil.h"
+#include "BsEditorApplication.h"
+#include "BsProjectSettings.h"
+
+namespace BansheeEngine
+{
+	ScriptProjectSettings::ScriptProjectSettings(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptProjectSettings::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_GetLastOpenScene", &ScriptProjectSettings::internal_GetLastOpenScene);
+		metaData.scriptClass->addInternalCall("Internal_SetLastOpenScene", &ScriptProjectSettings::internal_SetLastOpenScene);
+		metaData.scriptClass->addInternalCall("Internal_SetFloat", &ScriptProjectSettings::internal_SetFloat);
+		metaData.scriptClass->addInternalCall("Internal_SetInt", &ScriptProjectSettings::internal_SetInt);
+		metaData.scriptClass->addInternalCall("Internal_SetBool", &ScriptProjectSettings::internal_SetBool);
+		metaData.scriptClass->addInternalCall("Internal_SetString", &ScriptProjectSettings::internal_SetString);
+		metaData.scriptClass->addInternalCall("Internal_GetFloat", &ScriptProjectSettings::internal_GetFloat);
+		metaData.scriptClass->addInternalCall("Internal_GetInt", &ScriptProjectSettings::internal_GetInt);
+		metaData.scriptClass->addInternalCall("Internal_GetBool", &ScriptProjectSettings::internal_GetBool);
+		metaData.scriptClass->addInternalCall("Internal_GetString", &ScriptProjectSettings::internal_GetString);
+		metaData.scriptClass->addInternalCall("Internal_HasKey", &ScriptProjectSettings::internal_HasKey);
+		metaData.scriptClass->addInternalCall("Internal_DeleteKey", &ScriptProjectSettings::internal_DeleteKey);
+		metaData.scriptClass->addInternalCall("Internal_DeleteAllKeys", &ScriptProjectSettings::internal_DeleteAllKeys);
+		metaData.scriptClass->addInternalCall("Internal_GetHash", &ScriptProjectSettings::internal_GetHash);
+		metaData.scriptClass->addInternalCall("Internal_Save", &ScriptProjectSettings::internal_Save);
+	}
+
+	MonoString* ScriptProjectSettings::internal_GetLastOpenScene()
+	{
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		return MonoUtil::stringToMono(MonoManager::instance().getDomain(), settings->getLastOpenScene());
+	}
+
+	void ScriptProjectSettings::internal_SetLastOpenScene(MonoString* value)
+	{
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		settings->setLastOpenScene(MonoUtil::monoToString(value));
+	}
+
+	void ScriptProjectSettings::internal_SetFloat(MonoString* name, float value)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		settings->setFloat(nativeName, value);
+	}
+
+	void ScriptProjectSettings::internal_SetInt(MonoString* name, int value)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		settings->setInt(nativeName, value);
+	}
+
+	void ScriptProjectSettings::internal_SetBool(MonoString* name, bool value)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		settings->setBool(nativeName, value);
+	}
+
+	void ScriptProjectSettings::internal_SetString(MonoString* name, MonoString* value)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+		WString nativeValue = MonoUtil::monoToWString(value);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		settings->setString(nativeName, nativeValue);
+	}
+
+	float ScriptProjectSettings::internal_GetFloat(MonoString* name, float defaultValue)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		return settings->getFloat(nativeName, defaultValue);
+	}
+
+	int ScriptProjectSettings::internal_GetInt(MonoString* name, int defaultValue)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		return settings->getInt(nativeName, defaultValue);
+	}
+
+	bool ScriptProjectSettings::internal_GetBool(MonoString* name, bool defaultValue)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		return settings->getBool(nativeName, defaultValue);
+	}
+
+	MonoString* ScriptProjectSettings::internal_GetString(MonoString* name, MonoString* defaultValue)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+		WString nativeDefaultValue = MonoUtil::monoToWString(defaultValue);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		WString nativeValue = settings->getString(nativeName, nativeDefaultValue);
+
+		return MonoUtil::wstringToMono(MonoManager::instance().getDomain(), nativeValue);
+	}
+
+	bool ScriptProjectSettings::internal_HasKey(MonoString* name)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		return settings->hasKey(nativeName);
+	}
+
+	void ScriptProjectSettings::internal_DeleteKey(MonoString* name)
+	{
+		String nativeName = MonoUtil::monoToString(name);
+
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		settings->deleteKey(nativeName);
+	}
+
+	void ScriptProjectSettings::internal_DeleteAllKeys()
+	{
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		settings->deleteAllKeys();
+	}
+
+	UINT32 ScriptProjectSettings::internal_GetHash()
+	{
+		ProjectSettingsPtr settings = gEditorApplication().getProjectSettings();
+		return settings->getHash();
+	}
+
+	void ScriptProjectSettings::internal_Save()
+	{
+		gEditorApplication().saveProjectSettings();
+	}
+}

+ 3 - 3
TODO.txt

@@ -59,7 +59,7 @@ Move data folder within current repo
 Add Create Project & Open Project entries in main menu
 Rename ProjectWindow to LibraryWindow
 Store last open project location, should the last project be loaded by default, and a list of all known projects (listed by last opened date)
-(Store last open level too. WIll likely need ProjectSettings similar to EditorSettings)
+(Store last open level too in ProjectSettings)
 ProjectWindow
  - Show this on start-up if last open project is empty or load last project is off
   - Main editor window should show up but nothing should be loaded in it 
@@ -85,6 +85,8 @@ Ribek use:
  - Camera, Renderable, Material, Texture inspector
  - Project create/open window
  - Load default layout on initial start
+ - When opening editor load last open scene
+ - Make sure to persist EditorSettings
  - Test release mode
  - Ability to create assets in Project view (At least Material)
  - (Optionally, needed for GUI editing) GUISkin resource inspector & a way to inspect and save the default editor skin
@@ -111,9 +113,7 @@ Other polish:
    - Add a chaching mechanism to inspector (likely based on instance ID & property names)
    - This has to work not only when I come back to the object, but whenever inspector rebuilds (e.g. after removing element from array)
    - Consider saving this information with the serialized object
- - Make sure to persist EditorSettings
  - Import option inspectors for Texture, Mesh, Font
- - When opening editor load last open scene
 
 Stage 2 polish:
  - Inject an icon into an .exe (Win32 specific)