Explorar o código

VS integration finished (for now)

Marko Pintera %!s(int64=10) %!d(string=hai) anos
pai
achega
3a73e65b09

+ 6 - 6
BansheeEditor/Include/BsCodeEditor.h

@@ -36,8 +36,8 @@ namespace BansheeEngine
 		CodeEditorManager();
 		~CodeEditorManager();
 
-		const Vector<WString>& getAvailableEditors() const { return mEditors; }
-		void setActive(const WString& editor);
+		const Vector<CodeEditorType>& getAvailableEditors() const { return mEditors; }
+		void setActive(CodeEditorType editor);
 
 		void openFile(const Path& path, UINT32 lineNumber) const;
 		void syncSolution() const;
@@ -46,8 +46,8 @@ namespace BansheeEngine
 		Path getSolutionPath() const;
 
 		CodeEditor* mActiveEditor;
-		Map<WString, CodeEditorFactory*> mFactoryPerEditor;
-		Vector<WString> mEditors;
+		Map<CodeEditorType, CodeEditorFactory*> mFactoryPerEditor;
+		Vector<CodeEditorType> mEditors;
 		Vector<CodeEditorFactory*> mFactories;
 	};
 
@@ -61,7 +61,7 @@ namespace BansheeEngine
 	class BS_ED_EXPORT CodeEditorFactory
 	{
 	public:
-		virtual const Vector<WString>& getAvailableEditors() const = 0;
-		virtual CodeEditor* create(const WString& editor) const = 0;
+		virtual const Vector<CodeEditorType>& getAvailableEditors() const = 0;
+		virtual CodeEditor* create(CodeEditorType editor) const = 0;
 	};
 }

+ 9 - 0
BansheeEditor/Include/BsEditorPrerequisites.h

@@ -83,6 +83,15 @@ namespace BansheeEngine
 		Resources = 10002
 	};
 
+	enum class CodeEditorType
+	{
+		VS2008,
+		VS2010,
+		VS2012,
+		VS2013,
+		VS2015
+	};
+
 	enum TypeID_BansheeEditor
 	{
 		TID_ProjectResourceMeta = 40000,

+ 5 - 5
BansheeEditor/Include/Win32/BsVSCodeEditor.h

@@ -33,8 +33,8 @@ namespace BansheeEngine
 	public:
 		VSCodeEditorFactory();
 
-		const Vector<WString>& getAvailableEditors() const override { return mAvailableEditors; }
-		CodeEditor* create(const WString& editor) const override;
+		const Vector<CodeEditorType>& getAvailableEditors() const override { return mAvailableEditors; }
+		CodeEditor* create(CodeEditorType editor) const override;
 
 	private:
 		struct VSVersionInfo
@@ -45,9 +45,9 @@ namespace BansheeEngine
 			VisualStudioVersion version;
 		};
 
-		Map<WString, VSVersionInfo> getAvailableVersions() const;
+		Map<CodeEditorType, VSVersionInfo> getAvailableVersions() const;
 
-		Map<WString, VSVersionInfo> mAvailableVersions;
-		Vector<WString> mAvailableEditors;
+		Map<CodeEditorType, VSVersionInfo> mAvailableVersions;
+		Vector<CodeEditorType> mAvailableEditors;
 	};
 }

+ 17 - 10
BansheeEditor/Source/BsCodeEditor.cpp

@@ -17,7 +17,7 @@ namespace BansheeEngine
 	{
 #if BS_PLATFORM == BS_PLATFORM_WIN32
 		VSCodeEditorFactory* vsCodeEditorFactory = bs_new<VSCodeEditorFactory>();
-		Vector<WString> vsEditors = vsCodeEditorFactory->getAvailableEditors();
+		Vector<CodeEditorType> vsEditors = vsCodeEditorFactory->getAvailableEditors();
 		for(auto& editor : vsEditors)
 		{
 			mFactoryPerEditor[editor] = vsCodeEditorFactory;
@@ -39,7 +39,7 @@ namespace BansheeEngine
 			bs_delete(mActiveEditor);
 	}
 
-	void CodeEditorManager::setActive(const WString& editor)
+	void CodeEditorManager::setActive(CodeEditorType editor)
 	{
 		if (mActiveEditor != nullptr)
 		{
@@ -56,8 +56,14 @@ namespace BansheeEngine
 
 	void CodeEditorManager::openFile(const Path& path, UINT32 lineNumber) const
 	{
-		if (mActiveEditor != nullptr)
-			mActiveEditor->openFile(getSolutionPath(), path, lineNumber);
+		if (mActiveEditor == nullptr)
+			return;
+
+		Path filePath = path;
+		if (!path.isAbsolute())
+			filePath.makeAbsolute(gEditorApplication().getProjectPath());
+
+		mActiveEditor->openFile(getSolutionPath(), filePath, lineNumber);
 	}
 
 	void CodeEditorManager::syncSolution() const
@@ -75,9 +81,11 @@ namespace BansheeEngine
 
 		Vector<ProjectLibrary::LibraryEntry*> libraryEntries = ProjectLibrary::instance().search(L"*", scriptTypeIds);
 		
-		// Game project
 		slnData.projects.push_back(CodeProjectData());
-		CodeProjectData& gameProject = slnData.projects.back();
+		slnData.projects.push_back(CodeProjectData());
+
+		// Game project
+		CodeProjectData& gameProject = slnData.projects[0];
 		gameProject.name = toWString(SCRIPT_GAME_ASSEMBLY);
 		
 		//// Add references
@@ -85,8 +93,7 @@ namespace BansheeEngine
 		gameProject.assemblyReferences.push_back(CodeProjectReference{ L"BansheeEngine", gApplication().getEngineAssemblyPath() });
 
 		// Editor project
-		slnData.projects.push_back(CodeProjectData());
-		CodeProjectData& editorProject = slnData.projects.back();
+		CodeProjectData& editorProject = slnData.projects[1];
 		editorProject.name = toWString(SCRIPT_EDITOR_ASSEMBLY);
 
 		//// Add references
@@ -94,7 +101,7 @@ namespace BansheeEngine
 		editorProject.assemblyReferences.push_back(CodeProjectReference{ L"BansheeEngine", gApplication().getEngineAssemblyPath() });
 		editorProject.assemblyReferences.push_back(CodeProjectReference{ L"BansheeEditor", gEditorApplication().getEditorAssemblyPath() });
 
-		editorProject.projectReferences.push_back(CodeProjectReference{ gameProject.name, Path::BLANK});
+		editorProject.projectReferences.push_back(CodeProjectReference{ gameProject.name, Path::BLANK });
 
 		//// Add files for both projects
 		for (auto& entry : libraryEntries)
@@ -120,7 +127,7 @@ namespace BansheeEngine
 				gameProject.nonCodeFiles.push_back(resEntry->path);
 		}
 
-		mActiveEditor->syncSolution(slnData, getSolutionPath());
+		mActiveEditor->syncSolution(slnData, gEditorApplication().getProjectPath());
 	}
 
 	Path CodeEditorManager::getSolutionPath() const

+ 124 - 114
BansheeEditor/Source/Win32/BsVSCodeEditor.cpp

@@ -32,16 +32,16 @@ namespace BansheeEngine
 	class VisualStudio
 	{
 	private:
-		static const WString SLN_TEMPLATE;
-		static const WString PROJ_ENTRY_TEMPLATE;
-		static const WString PROJ_PLATFORM_TEMPLATE;
+		static const String SLN_TEMPLATE;
+		static const String PROJ_ENTRY_TEMPLATE;
+		static const String PROJ_PLATFORM_TEMPLATE;
 
-		static const WString PROJ_TEMPLATE;
-		static const WString REFERENCE_ENTRY_TEMPLATE;
-		static const WString REFERENCE_PROJECT_ENTRY_TEMPLATE;
-		static const WString REFERENCE_PATH_ENTRY_TEMPLATE;
-		static const WString CODE_ENTRY_TEMPLATE;
-		static const WString NON_CODE_ENTRY_TEMPLATE;
+		static const String PROJ_TEMPLATE;
+		static const String REFERENCE_ENTRY_TEMPLATE;
+		static const String REFERENCE_PROJECT_ENTRY_TEMPLATE;
+		static const String REFERENCE_PATH_ENTRY_TEMPLATE;
+		static const String CODE_ENTRY_TEMPLATE;
+		static const String NON_CODE_ENTRY_TEMPLATE;
 
 	public:
 		static CComPtr<EnvDTE::_DTE> findRunningInstance(const CLSID& clsID, const Path& solutionPath)
@@ -173,150 +173,153 @@ namespace BansheeEngine
 			return true;
 		}
 
-		static String getSolutionGUID(const WString& solutionName)
-		{
-			static const String guidTemplate = "{0}-{1}-{2}-{3}-{4}";
-			String hash = md5(L"SLN_" + solutionName);
-
-			return StringUtil::format(guidTemplate, hash.substr(0, 8), hash.substr(8, 4), hash.substr(12, 4), hash.substr(16, 4), hash.substr(20, 12));
-		}
-
 		static String getProjectGUID(const WString& projectName)
 		{
 			static const String guidTemplate = "{0}-{1}-{2}-{3}-{4}";
-			String hash = md5(L"PRJ_" + projectName);
+			String hash = md5(projectName);
+
+			String output = StringUtil::format(guidTemplate, hash.substr(0, 8),
+				hash.substr(8, 4), hash.substr(12, 4), hash.substr(16, 4), hash.substr(20, 12));
+			StringUtil::toUpperCase(output);
 
-			return StringUtil::format(guidTemplate, hash.substr(0, 8), hash.substr(8, 4), hash.substr(12, 4), hash.substr(16, 4), hash.substr(20, 12));
+			return output;
 		}
 
-		static WString writeSolution(VisualStudioVersion version, const CodeSolutionData& data)
+		static String writeSolution(VisualStudioVersion version, const CodeSolutionData& data)
 		{
 			struct VersionData
 			{
-				WString formatVersion;
+				String formatVersion;
 			};
 
 			Map<VisualStudioVersion, VersionData> versionData =
 			{
-				{ VisualStudioVersion::VS2008, { L"10.0" } },
-				{ VisualStudioVersion::VS2010, { L"11.0" } },
-				{ VisualStudioVersion::VS2012, { L"12.0" } },
-				{ VisualStudioVersion::VS2013, { L"12.0" } },
-				{ VisualStudioVersion::VS2015, { L"12.0" } }
+				{ VisualStudioVersion::VS2008, { "10.00" } },
+				{ VisualStudioVersion::VS2010, { "11.00" } },
+				{ VisualStudioVersion::VS2012, { "12.00" } },
+				{ VisualStudioVersion::VS2013, { "12.00" } },
+				{ VisualStudioVersion::VS2015, { "12.00" } }
 			};
 
-			WString solutionGUID = toWString(getSolutionGUID(data.name));
-
-			WStringStream projectEntriesStream;
-			WStringStream projectPlatformsStream;
+			StringStream projectEntriesStream;
+			StringStream projectPlatformsStream;
 			for (auto& project : data.projects)
 			{
-				WString guid = toWString(getProjectGUID(project.name));
+				String guid = getProjectGUID(project.name);
+				String projectName = toString(project.name);
 
-				projectEntriesStream << StringUtil::format(PROJ_ENTRY_TEMPLATE, solutionGUID, project.name, project.name + L".csproj", guid) << std::endl;
-				projectPlatformsStream << StringUtil::format(PROJ_PLATFORM_TEMPLATE, guid) << std::endl;
+				projectEntriesStream << StringUtil::format(PROJ_ENTRY_TEMPLATE, projectName, projectName + ".csproj", guid);
+				projectPlatformsStream << StringUtil::format(PROJ_PLATFORM_TEMPLATE, guid);
 			}
 
-			WString projectEntries = projectEntriesStream.str();
-			WString projectPlatforms = projectPlatformsStream.str();
+			String projectEntries = projectEntriesStream.str();
+			String projectPlatforms = projectPlatformsStream.str();
 
 			return StringUtil::format(SLN_TEMPLATE, versionData[version].formatVersion, projectEntries, projectPlatforms);
 		}
 
-		static WString writeProject(VisualStudioVersion version, const CodeProjectData& projectData)
+		static String writeProject(VisualStudioVersion version, const CodeProjectData& projectData)
 		{
 			struct VersionData
 			{
-				WString toolsVersion;
+				String toolsVersion;
 			};
 
 			Map<VisualStudioVersion, VersionData> versionData =
 			{
-				{ VisualStudioVersion::VS2008, { L"3.5" } },
-				{ VisualStudioVersion::VS2010, { L"4.0" } },
-				{ VisualStudioVersion::VS2012, { L"4.0" } },
-				{ VisualStudioVersion::VS2013, { L"12.0" } },
-				{ VisualStudioVersion::VS2015, { L"13.0" } }
+				{ VisualStudioVersion::VS2008, { "3.5" } },
+				{ VisualStudioVersion::VS2010, { "4.0" } },
+				{ VisualStudioVersion::VS2012, { "4.0" } },
+				{ VisualStudioVersion::VS2013, { "12.0" } },
+				{ VisualStudioVersion::VS2015, { "13.0" } }
 			};
 
-			WStringStream tempStream;
+			StringStream tempStream;
 			for (auto& codeEntry : projectData.codeFiles)
-				tempStream << StringUtil::format(CODE_ENTRY_TEMPLATE, codeEntry.toWString()) << std::endl;
+				tempStream << StringUtil::format(CODE_ENTRY_TEMPLATE, codeEntry.toString());
 
-			WString codeEntries = tempStream.str();
-			tempStream.str(L"");
+			String codeEntries = tempStream.str();
+			tempStream.str("");
 			tempStream.clear();
 
 			for (auto& nonCodeEntry : projectData.nonCodeFiles)
-				tempStream << StringUtil::format(NON_CODE_ENTRY_TEMPLATE, nonCodeEntry.toWString()) << std::endl;
+				tempStream << StringUtil::format(NON_CODE_ENTRY_TEMPLATE, nonCodeEntry.toString());
 
-			WString nonCodeEntries = tempStream.str();
-			tempStream.str(L"");
+			String nonCodeEntries = tempStream.str();
+			tempStream.str("");
 			tempStream.clear();
 
 			for (auto& referenceEntry : projectData.assemblyReferences)
 			{
+				String referenceName = toString(referenceEntry.name);
+
 				if (referenceEntry.path.isEmpty())
-					tempStream << StringUtil::format(REFERENCE_ENTRY_TEMPLATE, referenceEntry.name) << std::endl;
+					tempStream << StringUtil::format(REFERENCE_ENTRY_TEMPLATE, referenceName);
 				else
-					tempStream << StringUtil::format(REFERENCE_PATH_ENTRY_TEMPLATE, referenceEntry.name, referenceEntry.path.toWString()) << std::endl;
+					tempStream << StringUtil::format(REFERENCE_PATH_ENTRY_TEMPLATE, referenceName, referenceEntry.path.toString());
 			}
 
-			WString referenceEntries = tempStream.str();
-			tempStream.str(L"");
+			String referenceEntries = tempStream.str();
+			tempStream.str("");
 			tempStream.clear();
 
 			for (auto& referenceEntry : projectData.projectReferences)
 			{
-				WString projectGUID = toWString(getProjectGUID(referenceEntry.name));
-				tempStream << StringUtil::format(REFERENCE_PROJECT_ENTRY_TEMPLATE, referenceEntry.name, projectGUID) << std::endl;
+				String referenceName = toString(referenceEntry.name);
+				String projectGUID = getProjectGUID(referenceEntry.name);
+
+				tempStream << StringUtil::format(REFERENCE_PROJECT_ENTRY_TEMPLATE, referenceName, projectGUID);
 			}
 
-			WString projectReferenceEntries = tempStream.str();
-			tempStream.str(L"");
+			String projectReferenceEntries = tempStream.str();
+			tempStream.str("");
 			tempStream.clear();
 
 			for (auto& define : projectData.defines)
-				tempStream << define << L";";
+				tempStream << toString(define) << ";";
 
-			WString defines = tempStream.str();
-			WString projectGUID = toWString(getProjectGUID(projectData.name));
+			String defines = tempStream.str();
+			String projectGUID = getProjectGUID(projectData.name);
 
-			return StringUtil::format(PROJ_ENTRY_TEMPLATE, versionData[version].toolsVersion, projectGUID, 
-				projectData.name, defines, referenceEntries, projectReferenceEntries, codeEntries, nonCodeEntries);
+			return StringUtil::format(PROJ_TEMPLATE, versionData[version].toolsVersion, projectGUID, 
+				toString(projectData.name), defines, referenceEntries, projectReferenceEntries, codeEntries, nonCodeEntries);
 		}
 	};
 
-	const WString VisualStudio::SLN_TEMPLATE =
-		LR"(Microsoft Visual Studio Solution File, Format Version {0}
-{1}
+	const String VisualStudio::SLN_TEMPLATE =
+		R"(Microsoft Visual Studio Solution File, Format Version {0}
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30723.0
+MinimumVisualStudioVersion = 10.0.40219.1{1}
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{2}
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution{2}
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
-EndGlobal)";
+EndGlobal
+)";
 
-	const WString VisualStudio::PROJ_ENTRY_TEMPLATE =
-		LR"(Project("\{{0}\}") = "{1}", "{2}", "\{{3}\}"
+	const String VisualStudio::PROJ_ENTRY_TEMPLATE =
+		R"(
+Project("\{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC\}") = "{0}", "{1}", "\{{2}\}"
 EndProject)";
 
-	const WString VisualStudio::PROJ_PLATFORM_TEMPLATE =
-		LR"(\{{0}\}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+	const String VisualStudio::PROJ_PLATFORM_TEMPLATE =
+		R"(
+		\{{0}\}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		\{{0}\}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		\{{0}\}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		\{{0}\}.Release|Any CPU.Build.0 = Release|Any CPU)";
 
-	const WString VisualStudio::PROJ_TEMPLATE =
-		LR"literal(<?xml version="1.0" encoding="utf-8"?>
+	const String VisualStudio::PROJ_TEMPLATE =
+		R"literal(<?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="{0}" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')" />
   <PropertyGroup>
     <Configuration Condition = " '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition = " '$(Platform)' == '' ">AnyCPU</Platform>
@@ -330,11 +333,12 @@ EndProject)";
     <BaseDirectory>Resources</BaseDirectory>
     <SchemaVersion>2.0</SchemaVersion>
   </PropertyGroup>
-    <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+  <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
-    <OutputPath>Internal\Temp\Assemblies\Debug\</OutputPath>
+    <OutputPath>Internal\\Temp\\Assemblies\\Debug\\</OutputPath>
+    <BaseIntermediateOutputPath>Internal\\Temp\\Assemblies\\</BaseIntermediateOutputPath>
     <DefineConstants>DEBUG;TRACE;{3}</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel >
@@ -342,45 +346,47 @@ EndProject)";
   <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
-    <OutputPath>Internal\Temp\Assemblies\Release\</OutputPath>
+    <OutputPath>Internal\\Temp\\Assemblies\\Release\\</OutputPath>
+	<BaseIntermediateOutputPath>Internal\\Temp\\Assemblies\\</BaseIntermediateOutputPath>
     <DefineConstants>TRACE;{3}</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
-  <ItemGroup>
-{4}
+  <ItemGroup>{4}
   </ItemGroup>
-  <ItemGroup>
-{5}
+  <ItemGroup>{5}
   </ItemGroup>
-  <ItemGroup>
-{6}
+  <ItemGroup>{6}
   </ItemGroup>
-  <ItemGroup>
-{7}
+  <ItemGroup>{7}
   </ItemGroup>
-  <Import Project = "$(MSBuildToolsPath)\Microsoft.CSharp.targets"/>
+  <Import Project = "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"/>
 </Project>)literal";
 
-	const WString VisualStudio::REFERENCE_ENTRY_TEMPLATE =
-		LR"(    <Reference Include="{0}"/>)";
+	const String VisualStudio::REFERENCE_ENTRY_TEMPLATE =
+		R"(
+    <Reference Include="{0}"/>)";
 
-	const WString VisualStudio::REFERENCE_PATH_ENTRY_TEMPLATE =
-		LR"(    <Reference Include="{0}">
+	const String VisualStudio::REFERENCE_PATH_ENTRY_TEMPLATE =
+		R"(
+    <Reference Include="{0}">
       <HintPath>{1}</HintPath>
     </Reference>)";
 
-	const WString VisualStudio::REFERENCE_PROJECT_ENTRY_TEMPLATE =
-		LR"(    <ProjectReference Include="{0}.csproj">
+	const String VisualStudio::REFERENCE_PROJECT_ENTRY_TEMPLATE =
+		R"(
+    <ProjectReference Include="{0}.csproj">
       <Project>\{{1}\}</Project>
       <Name>{0}</Name>
     </ProjectReference>)";
 
-	const WString VisualStudio::CODE_ENTRY_TEMPLATE =
-		LR"(    <Compile Include="{0}"/>)";
+	const String VisualStudio::CODE_ENTRY_TEMPLATE =
+		R"(
+    <Compile Include="{0}"/>)";
 
-	const WString VisualStudio::NON_CODE_ENTRY_TEMPLATE =
-		LR"(    <None Include="{0}"/>)";
+	const String VisualStudio::NON_CODE_ENTRY_TEMPLATE =
+		R"(
+    <None Include="{0}"/>)";
 
 	VSCodeEditor::VSCodeEditor(VisualStudioVersion version, const Path& execPath, const WString& CLSID)
 		:mCLSID(CLSID), mExecPath(execPath), mVersion(version)
@@ -406,23 +412,26 @@ EndProject)";
 
 	void VSCodeEditor::syncSolution(const CodeSolutionData& data, const Path& outputPath) const
 	{
-		WString solutionString = VisualStudio::writeSolution(mVersion, data);
+		String solutionString = VisualStudio::writeSolution(mVersion, data);
+		solutionString = StringUtil::replaceAll(solutionString, "\n", "\r\n");
 		Path solutionPath = outputPath;
 		solutionPath.append(data.name + L".sln");
 
 		for (auto& project : data.projects)
 		{
-			WString projectString = VisualStudio::writeProject(mVersion, project);
+			String projectString = VisualStudio::writeProject(mVersion, project);
+			projectString = StringUtil::replaceAll(projectString, "\n", "\r\n");
+
 			Path projectPath = outputPath;
 			projectPath.append(project.name + L".csproj");
 
 			DataStreamPtr projectStream = FileSystem::createAndOpenFile(projectPath);
-			projectStream->write(projectString.c_str(), projectString.size());
+			projectStream->write(projectString.c_str(), projectString.size() * sizeof(String::value_type));
 			projectStream->close();
 		}
 
 		DataStreamPtr solutionStream = FileSystem::createAndOpenFile(solutionPath);
-		solutionStream->write(solutionString.c_str(), solutionString.size());
+		solutionStream->write(solutionString.c_str(), solutionString.size() * sizeof(String::value_type));
 		solutionStream->close();
 	}
 
@@ -433,7 +442,7 @@ EndProject)";
 			mAvailableEditors.push_back(version.first);
 	}
 
-	Map<WString, VSCodeEditorFactory::VSVersionInfo> VSCodeEditorFactory::getAvailableVersions() const
+	Map<CodeEditorType, VSCodeEditorFactory::VSVersionInfo> VSCodeEditorFactory::getAvailableVersions() const
 	{
 #if BS_ARCH_TYPE == BS_ARCHITECTURE_x86_64
 		bool is64bit = true;
@@ -444,12 +453,13 @@ EndProject)";
 
 		WString registryKeyRoot;
 		if (is64bit)
-			registryKeyRoot = L"SOFTWARE\\Microsoft";
+			registryKeyRoot = L"SOFTWARE\\Wow6432Node\\Microsoft"; 
 		else
-			registryKeyRoot = L"SOFTWARE\\Wow6432Node\\Microsoft";
+			registryKeyRoot = L"SOFTWARE\\Microsoft";
 
 		struct VersionData
 		{
+			CodeEditorType type;
 			WString registryKey;
 			WString name;
 			WString executable;
@@ -457,20 +467,20 @@ EndProject)";
 
 		Map<VisualStudioVersion, VersionData> versionToVersionNumber =
 		{ 
-			{ VisualStudioVersion::VS2008, { L"VisualStudio\\9.0", L"Visual Studio 2008", L"devenv.exe" } },
-			{ VisualStudioVersion::VS2010, { L"VisualStudio\\10.0", L"Visual Studio 2010", L"devenv.exe" } },
-			{ VisualStudioVersion::VS2012, { L"VisualStudio\\11.0", L"Visual Studio 2012", L"devenv.exe" } },
-			{ VisualStudioVersion::VS2013, { L"VisualStudio\\12.0", L"Visual Studio 2013", L"devenv.exe" } },
-			{ VisualStudioVersion::VS2015, { L"VisualStudio\\13.0", L"Visual Studio 2015", L"devenv.exe" } }
+			{ VisualStudioVersion::VS2008, { CodeEditorType::VS2008, L"VisualStudio\\9.0", L"Visual Studio 2008", L"devenv.exe" } },
+			{ VisualStudioVersion::VS2010, { CodeEditorType::VS2010, L"VisualStudio\\10.0", L"Visual Studio 2010", L"devenv.exe" } },
+			{ VisualStudioVersion::VS2012, { CodeEditorType::VS2012, L"VisualStudio\\11.0", L"Visual Studio 2012", L"devenv.exe" } },
+			{ VisualStudioVersion::VS2013, { CodeEditorType::VS2013, L"VisualStudio\\12.0", L"Visual Studio 2013", L"devenv.exe" } },
+			{ VisualStudioVersion::VS2015, { CodeEditorType::VS2015, L"VisualStudio\\13.0", L"Visual Studio 2015", L"devenv.exe" } }
 		};
 
-		Map<WString, VSVersionInfo> versionInfo;
+		Map<CodeEditorType, VSVersionInfo> versionInfo;
 		for(auto version : versionToVersionNumber)
 		{
 			WString registryKey = registryKeyRoot + L"\\" + version.second.registryKey;
 
 			HKEY regKey;
-			LONG result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKeyRoot.c_str(), 0, KEY_READ, &regKey);
+			LONG result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, registryKey.c_str(), 0, KEY_READ, &regKey);
 			if (result != ERROR_SUCCESS)
 				continue;
 
@@ -488,7 +498,7 @@ EndProject)";
 			info.CLSID = clsID;
 			info.version = version.first;
 
-			versionInfo[info.name] = info;
+			versionInfo[version.second.type] = info;
 		}
 
 		// TODO - Also query for VSExpress and VSCommunity (their registry keys are different)
@@ -496,9 +506,9 @@ EndProject)";
 		return versionInfo;
 	}
 
-	CodeEditor* VSCodeEditorFactory::create(const WString& editor) const
+	CodeEditor* VSCodeEditorFactory::create(CodeEditorType type) const
 	{
-		auto findIter = mAvailableVersions.find(editor);
+		auto findIter = mAvailableVersions.find(type);
 		if (findIter == mAvailableVersions.end())
 			return nullptr;
 

+ 10 - 7
BansheeUtility/Include/BsStringFormat.h

@@ -69,7 +69,7 @@ namespace BansheeEngine
 				if (source[i] == '\\' && !escaped && paramRangeWriteIdx < MAX_PARAM_REFERENCES)
 				{
 					escaped = true;
-					paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, 1, 0);
+					paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, 1, (UINT32)-1);
 					continue;
 				}
 
@@ -96,8 +96,8 @@ namespace BansheeEngine
 							UINT32 paramIdx = strToInt(bracketChars);
 							if (paramIdx < MAX_PARAMS && paramRangeWriteIdx < MAX_PARAM_REFERENCES) // Check if exceeded maximum parameter limit
 							{
-								charWriteIdx += parameters[paramIdx].size;
 								paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, numParamChars + 2, paramIdx);
+								charWriteIdx += parameters[paramIdx].size;
 
 								processedBracket = true;
 							}
@@ -128,17 +128,20 @@ namespace BansheeEngine
 			{
 				const FormatParamRange& rangeInfo = paramRanges[i];
 				UINT32 copySize = rangeInfo.start - copyDestIdx;
-				UINT32 paramSize = parameters[rangeInfo.paramIdx].size;
-
-				memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, copySize);
+				
+				memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, copySize * sizeof(T));
 				copySourceIdx += copySize + rangeInfo.identifierSize;
 				copyDestIdx += copySize;
 
-				memcpy(outputBuffer + copyDestIdx, parameters[rangeInfo.paramIdx].buffer, paramSize);
+				if (rangeInfo.paramIdx == (UINT32)-1)
+					continue;
+
+				UINT32 paramSize = parameters[rangeInfo.paramIdx].size;
+				memcpy(outputBuffer + copyDestIdx, parameters[rangeInfo.paramIdx].buffer, paramSize * sizeof(T));
 				copyDestIdx += paramSize;
 			}
 
-			memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, finalStringSize - copyDestIdx);
+			memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, (finalStringSize - copyDestIdx) * sizeof(T));
 
 			BasicString<T> outputStr(outputBuffer, finalStringSize);
 			bs_free(outputBuffer);

+ 17 - 13
BansheeUtility/Source/BsUtil.cpp

@@ -6,30 +6,34 @@ namespace BansheeEngine
 	String md5(const WString& source)
 	{
 		MD5 md5;
-		md5.update((UINT8*)source.c_str(), (UINT32)source.length());
+		md5.update((UINT8*)source.c_str(), (UINT32)source.length() * sizeof(WString::value_type));
 		md5.finalize();
 
-		UINT8* digest = (UINT8*)bs_alloc(16);
-		md5.decdigest(digest, 16);
+		UINT8 digest[16];
+		md5.decdigest(digest, sizeof(digest));
 
-		String output((char*)digest);
-		bs_free(digest);
-
-		return output;
+		char buf[33];
+		for (int i = 0; i < 16; i++)
+			sprintf(buf + i * 2, "%02x", digest[i]);
+		buf[32] = 0;
+		
+		return String(buf);
 	}
 
 	String md5(const String& source)
 	{
 		MD5 md5;
-		md5.update((UINT8*)source.c_str(), (UINT32)source.length());
+		md5.update((UINT8*)source.c_str(), (UINT32)source.length() * sizeof(String::value_type));
 		md5.finalize();
 
-		UINT8* digest = (UINT8*)bs_alloc(16);
-		md5.decdigest(digest, 16);
+		UINT8 digest[16];
+		md5.decdigest(digest, sizeof(digest));
 
-		String output((char*)digest);
-		bs_free(digest);
+		char buf[33];
+		for (int i = 0; i < 16; i++)
+			sprintf(buf + i * 2, "%02x", digest[i]);
+		buf[32] = 0;
 
-		return output;
+		return String(buf);
 	}
 }

+ 51 - 0
MBansheeEditor/CodeEditor.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Runtime.CompilerServices;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    // Note: Must match C++ CodeEditorType enum
+    public enum CodeEditorType
+    {
+        VS2008,
+        VS2010,
+        VS2012,
+        VS2013,
+        VS2015
+    }
+
+    public static class CodeEditor
+    {
+        public static CodeEditorType ActiveEditor
+        {
+            set { Internal_SetActiveEditor(value); }
+        }
+
+        public static CodeEditorType[] AvailableEditors
+        {
+            get { return Internal_GetAvailableEditors(); }
+        }
+
+        public static void OpenFile(string path, UInt32 line)
+        {
+            Internal_OpenFile(path, line);
+        }
+
+        public static void SyncSolution()
+        {
+            Internal_SyncSolution();
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_SetActiveEditor(CodeEditorType type);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern CodeEditorType[] Internal_GetAvailableEditors();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_OpenFile(string path, UInt32 line);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_SyncSolution();
+    }
+}

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -40,6 +40,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="BrowseDialog.cs" />
+    <Compile Include="CodeEditor.cs" />
     <Compile Include="ColorPicker.cs" />
     <Compile Include="DbgCustomInspector.cs" />
     <Compile Include="DbgEditorWindow.cs" />

+ 9 - 1
MBansheeEditor/ProjectLibrary.cs

@@ -48,6 +48,11 @@ namespace BansheeEditor
             return Internal_GetEntry(path);
         }
 
+        public LibraryEntry[] Search(string pattern, ResourceType[] types = null)
+        {
+            return Internal_Search(pattern, types);
+        }
+
         public static string GetPath(Resource resource)
         {
             return Internal_GetPath(resource);
@@ -108,6 +113,9 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern LibraryEntry Internal_GetEntry(string path);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern LibraryEntry[] Internal_Search(string path, ResourceType[] types);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern string Internal_GetPath(Resource resource);
 
@@ -136,7 +144,7 @@ namespace BansheeEditor
     // Note: Must be the same as C++ enum ScriptResourceType
     public enum ResourceType
     {
-        Texture, SpriteTexture, Mesh, Font, GpuProgram, Undefined
+        Texture, SpriteTexture, Mesh, Font, GpuProgram, PlainText, ScriptCode, Undefined
     }
 
     public class LibraryEntry : ScriptObject

+ 21 - 0
SBansheeEditor/Include/BsScriptCodeEditor.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BED_EXPORT ScriptCodeEditor : public ScriptObject<ScriptCodeEditor>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "CodeEditor")
+
+	private:
+		static void internal_SetActiveEditor(CodeEditorType type);
+		static MonoArray* internal_GetAvailableEditors();
+		static void internal_OpenFile(MonoString* path, UINT32 line);
+		static void internal_SyncSolution();
+
+		ScriptCodeEditor(MonoObject* instance);
+	};
+}

+ 1 - 0
SBansheeEditor/Include/BsScriptProjectLibrary.h

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

+ 2 - 0
SBansheeEditor/SBansheeEditor.vcxproj

@@ -237,6 +237,7 @@
     <ClInclude Include="Include\BsGUIPanelContainer.h" />
     <ClInclude Include="Include\BsGUIResourceField.h" />
     <ClInclude Include="Include\BsScriptBrowseDialog.h" />
+    <ClInclude Include="Include\BsScriptCodeEditor.h" />
     <ClInclude Include="Include\BsScriptDragDropManager.h" />
     <ClInclude Include="Include\BsScriptEditorPrerequisites.h" />
     <ClInclude Include="Include\BsScriptEditorSettings.h" />
@@ -271,6 +272,7 @@
     <ClInclude Include="Include\BsScriptSelection.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="Source\BsScriptCodeEditor.cpp" />
     <ClCompile Include="Source\BsScriptDragDropManager.cpp" />
     <ClCompile Include="Source\BsEditorScriptManager.cpp" />
     <ClCompile Include="Source\BsGUIGameObjectField.cpp" />

+ 6 - 0
SBansheeEditor/SBansheeEditor.vcxproj.filters

@@ -126,6 +126,9 @@
     <ClInclude Include="Include\BsScriptImportOptions.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptCodeEditor.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
@@ -239,5 +242,8 @@
     <ClCompile Include="Source\BsScriptImportOptions.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptCodeEditor.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 54 - 0
SBansheeEditor/Source/BsScriptCodeEditor.cpp

@@ -0,0 +1,54 @@
+#include "BsScriptCodeEditor.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsMonoManager.h"
+#include "BsMonoUtil.h"
+#include "BsCodeEditor.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptCodeEditor::ScriptCodeEditor(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptCodeEditor::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_SetActiveEditor", &ScriptCodeEditor::internal_SetActiveEditor);
+		metaData.scriptClass->addInternalCall("Internal_GetAvailableEditors", &ScriptCodeEditor::internal_GetAvailableEditors);
+		metaData.scriptClass->addInternalCall("Internal_OpenFile", &ScriptCodeEditor::internal_OpenFile);
+		metaData.scriptClass->addInternalCall("Internal_SyncSolution", &ScriptCodeEditor::internal_SyncSolution);
+	}
+
+	void ScriptCodeEditor::internal_SetActiveEditor(CodeEditorType type)
+	{
+		CodeEditorManager::instance().setActive(type);
+	}
+
+	MonoArray* ScriptCodeEditor::internal_GetAvailableEditors()
+	{
+		Vector<CodeEditorType> availableEditors = CodeEditorManager::instance().getAvailableEditors();
+
+		ScriptArray outArray = ScriptArray::create<UINT32>((UINT32)availableEditors.size());
+		UINT32 idx = 0;
+		for (auto& entry : availableEditors)
+			outArray.set(idx, (UINT32)entry);
+
+		return outArray.getInternal();
+	}
+
+	void ScriptCodeEditor::internal_OpenFile(MonoString* path, UINT32 line)
+	{
+		Path filePath = MonoUtil::monoToWString(path);
+
+		CodeEditorManager::instance().openFile(filePath, line);
+	}
+
+	void ScriptCodeEditor::internal_SyncSolution()
+	{
+		CodeEditorManager::instance().syncSolution();
+	}
+}

+ 33 - 0
SBansheeEditor/Source/BsScriptProjectLibrary.cpp

@@ -38,6 +38,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_Search", &ScriptProjectLibrary::internal_Search);
 		metaData.scriptClass->addInternalCall("Internal_Delete", &ScriptProjectLibrary::internal_Delete);
 		metaData.scriptClass->addInternalCall("Internal_CreateFolder", &ScriptProjectLibrary::internal_CreateFolder);
 		metaData.scriptClass->addInternalCall("Internal_Rename", &ScriptProjectLibrary::internal_Rename);
@@ -138,6 +139,38 @@ namespace BansheeEngine
 		return nullptr;
 	}
 
+	MonoArray* ScriptProjectLibrary::internal_Search(MonoString* pattern, MonoArray* types)
+	{
+		WString strPattern = MonoUtil::monoToWString(pattern);
+
+		ScriptArray typeArray(types);
+		Vector<UINT32> typeIds;
+		for (UINT32 i = 0; i < typeArray.size(); i++)
+		{
+			UINT32 typeId = ScriptResource::getTypeIdFromType((ScriptResourceType)typeArray.get<UINT32>(i));
+			typeIds.push_back(typeId);
+		}
+
+		Vector<ProjectLibrary::LibraryEntry*> foundEntries = ProjectLibrary::instance().search(strPattern, typeIds);
+
+		UINT32 idx = 0;
+		ScriptArray outArray = ScriptArray::create<ScriptLibraryEntry>((UINT32)foundEntries.size());
+		for (auto& entry : foundEntries)
+		{
+			MonoObject* managedEntry = nullptr;
+
+			if (entry->type == ProjectLibrary::LibraryEntryType::File)
+				managedEntry = ScriptFileEntry::create(static_cast<ProjectLibrary::ResourceEntry*>(entry));
+			else
+				managedEntry = ScriptDirectoryEntry::create(static_cast<ProjectLibrary::DirectoryEntry*>(entry));
+
+			outArray.set(idx, managedEntry);
+			idx++;
+		}
+
+		return outArray.getInternal();
+	}
+
 	void ScriptProjectLibrary::internal_Delete(MonoString* path)
 	{
 		Path pathToDelete = MonoUtil::monoToWString(path);

+ 2 - 2
SBansheeEngine/Include/BsScriptResource.h

@@ -7,7 +7,7 @@ namespace BansheeEngine
 {
 	enum class ScriptResourceType
 	{
-		Texture, SpriteTexture, Mesh, Font, GpuProgram, Undefined
+		Texture, SpriteTexture, Mesh, Font, GpuProgram, PlainText, ScriptCode, Undefined
 	};
 
 	class BS_SCR_BE_EXPORT ScriptResourceBase : public PersistentScriptObjectBase
@@ -37,7 +37,7 @@ namespace BansheeEngine
 		static void initRuntimeData() { }
 
 		static ScriptResourceType getTypeFromTypeId(UINT32 typeId);
-
+		static UINT32 getTypeIdFromType(ScriptResourceType type);
 	private:
 		ScriptResource(MonoObject* instance)
 			:ScriptObject(instance)

+ 27 - 0
SBansheeEngine/Source/BsScriptResource.cpp

@@ -34,8 +34,35 @@ namespace BansheeEngine
 			return ScriptResourceType::GpuProgram;
 		case TID_Font:
 			return ScriptResourceType::Font;
+		case TID_PlainText:
+			return ScriptResourceType::PlainText;
+		case TID_ScriptCode:
+			return ScriptResourceType::ScriptCode;
 		}
 
 		return ScriptResourceType::Undefined;
 	}
+
+	UINT32 ScriptResource::getTypeIdFromType(ScriptResourceType type)
+	{
+		switch (type)
+		{
+		case ScriptResourceType::Texture:
+			return TID_Texture;
+		case ScriptResourceType::SpriteTexture:
+			return TID_SpriteTexture;
+		case ScriptResourceType::Mesh:
+			return TID_Mesh;
+		case ScriptResourceType::GpuProgram:
+			return TID_GpuProgram;
+		case ScriptResourceType::Font:
+			return TID_Font;
+		case ScriptResourceType::PlainText:
+			return TID_PlainText;
+		case ScriptResourceType::ScriptCode:
+			return TID_ScriptCode;
+		}
+
+		return 0;
+	}
 }

+ 3 - 8
TODO.txt

@@ -11,25 +11,20 @@ Project library
 
 Almost all of PRojectLibrary functionality is completely untested
 
-ProjectLibrary needs a method that searches for all entries with a specific name (or a subset of a name), and all entries of a specific type
- - Can I make Library/Resource entries faster so I can do this properly from C#?
-
 Figure out how to create a C# BuiltinResources class. It should be able to load arbitrary resources from a non-project folder
  - I should move all the GUI element style creation out of code and make it just pure data (once I have an editor for it)
  - Will also need a debug button to reimport all the built-in resources
 
+My GUID generation is screwed up. If multiple GUIDs are generated in succession then the timestamp will remain
+the same and the only variable will be the 4byte random number, which can sometimes end up identical to the previous number.
+
 ----------------------------------------------------------------------
 VisualStudio integration
 
-None of the new VS functionality has been tested
 VS integration will likely not work with VSExpress or Community edition
  - VSExpress doesn't support EnvDTE so the only option is to open it using a shell command which doesn't seem to offer precise parameters
  - Community edition should work similarily to Pro, but might have a different executable and/or registry paths
 
-Test:
- - If string::format works
- - If VS open and sync works
-
 For later:
  - Make sure that 3rd party assemblies can be imported in the project, and that they are properly referenced in VS project generation