Implement prototype .NET loader

This commit is contained in:
Bepis committed 2020-04-27 23:44:50 +10:00
1 parent dc5d9f444f
commit 9c8ad31af8
12 files changed
+545 -2

No files matched your search

+5
View File
@@ -85,6 +85,11 @@ namespace BepInEx
} }
} }
public static void ForceSetActive(bool value)
{
ConsoleActive = value;
}
public static readonly ConfigEntry<bool> ConfigConsoleEnabled = ConfigFile.CoreConfig.Bind( public static readonly ConfigEntry<bool> ConfigConsoleEnabled = ConfigFile.CoreConfig.Bind(
"Logging.Console", "Enabled", "Logging.Console", "Enabled",
false, false,
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
+21
View File
@@ -0,0 +1,21 @@
namespace BepInEx.NetLauncher
{
public abstract class BasePlugin
{
protected HarmonyLib.Harmony HarmonyInstance { get; }
protected BasePlugin()
{
//var info = PluginInfoHelper.GetPluginInfo(this);
//HarmonyInstance = new HarmonyLib.Harmony("BepInEx.Plugin." + info.GUID);
}
public abstract void Load();
public virtual bool Unload()
{
return false;
}
}
}
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<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>
<ProjectGuid>{490B052B-7F23-4052-AD04-613856618901}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>BepInEx.NetLauncher</RootNamespace>
<AssemblyName>BepInEx.NetLauncher</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin\net\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin\net\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Cecil, Version=0.11.2.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.11.2\lib\net40\Mono.Cecil.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil.Mdb, Version=0.11.2.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.11.2\lib\net40\Mono.Cecil.Mdb.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil.Pdb, Version=0.11.2.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.11.2\lib\net40\Mono.Cecil.Pdb.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil.Rocks, Version=0.11.2.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.11.2\lib\net40\Mono.Cecil.Rocks.dll</HintPath>
</Reference>
<Reference Include="MonoMod.RuntimeDetour, Version=20.4.3.1, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\MonoMod.RuntimeDetour.20.4.3.1\lib\net40\MonoMod.RuntimeDetour.dll</HintPath>
</Reference>
<Reference Include="MonoMod.Utils, Version=20.4.3.1, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\MonoMod.Utils.20.4.3.1\lib\net40\MonoMod.Utils.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="BasePlugin.cs" />
<Compile Include="NetChainloader.cs" />
<Compile Include="NetPreloader.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utility.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BepInEx.Core\BepInEx.Core.csproj">
<Project>{4ffba620-f5ed-47f9-b90c-dad1316fd9b9}</Project>
<Name>BepInEx.Core</Name>
</ProjectReference>
<ProjectReference Include="..\BepInEx.Preloader.Core\BepInEx.Preloader.Core.csproj">
<Project>{15f8bc38-a761-4f93-8903-1b531ac5d9f9}</Project>
<Name>BepInEx.Preloader.Core</Name>
</ProjectReference>
<ProjectReference Include="..\submodules\BepInEx.Harmony\BepInEx.Harmony\BepInEx.Harmony.csproj">
<Project>{54161cfe-ff42-4dde-b161-3a49545db5cd}</Project>
<Name>BepInEx.Harmony</Name>
</ProjectReference>
<ProjectReference Include="..\submodules\BepInEx.Harmony\submodules\Harmony\Harmony\Harmony.csproj">
<Project>{a15d6ee6-f954-415b-8605-8a8470cc87dc}</Project>
<Name>Harmony</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+20
View File
@@ -0,0 +1,20 @@
using System;
using System.Reflection;
using BepInEx.Bootstrap;
namespace BepInEx.NetLauncher
{
public class NetChainloader : BaseChainloader<BasePlugin>
{
public override BasePlugin LoadPlugin(PluginInfo pluginInfo, Assembly pluginAssembly)
{
var type = pluginAssembly.GetType(pluginInfo.TypeName);
var pluginInstance = (BasePlugin)Activator.CreateInstance(type);
pluginInstance.Load();
return pluginInstance;
}
}
}
+118
View File
@@ -0,0 +1,118 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Preloader.Core;
using BepInEx.Preloader.Core.RuntimeFixes;
using MonoMod.RuntimeDetour;
namespace BepInEx.NetLauncher
{
public static class NetPreloader
{
private static readonly ManualLogSource Log = PreloaderLogger.Log;
public static void Start(string[] args)
{
if (ConfigEntrypointExecutable.Value == null)
{
Log.LogFatal($"Entry executable was not set. Please set this in your config before launching the application");
Program.ReadExit();
return;
}
string executablePath = Path.GetFullPath(ConfigEntrypointExecutable.Value);
if (!File.Exists(executablePath))
{
Log.LogFatal($"Unable to locate executable: {ConfigEntrypointExecutable.Value}");
Program.ReadExit();
return;
}
Paths.SetExecutablePath(executablePath);
Program.ResolveDirectories.Add(Paths.GameRootPath);
TypeLoader.SearchDirectories.Add(Paths.GameRootPath);
bool bridgeInitialized = Utility.TryDo(() =>
{
if (ConfigShimHarmony.Value)
HarmonyDetourBridge.Init();
}, out var harmonyBridgeException);
Logger.Sources.Add(TraceLogSource.CreateSource());
HarmonyFixes.Apply();
string consoleTile = $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Process.GetCurrentProcess().ProcessName}";
Log.LogMessage(consoleTile);
if (ConsoleManager.ConsoleActive)
ConsoleManager.SetConsoleTitle(consoleTile);
//See BuildInfoAttribute for more information about this section.
object[] attributes = typeof(BuildInfoAttribute).Assembly.GetCustomAttributes(typeof(BuildInfoAttribute), false);
if (attributes.Length > 0)
{
var attribute = (BuildInfoAttribute)attributes[0];
Log.LogMessage(attribute.Info);
}
Log.LogInfo($"CLR runtime version: {Environment.Version}");
if (harmonyBridgeException != null)
Log.LogWarning($"Failed to enable fix for Harmony for .NET Standard API. Error message: {harmonyBridgeException.Message}");
Log.LogMessage("Preloader started");
using (var assemblyPatcher = new AssemblyPatcher())
{
assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);
Log.LogInfo($"{assemblyPatcher.PatcherPlugins.Count} patcher plugin(s) loaded");
assemblyPatcher.LoadAssemblyDirectory(Paths.GameRootPath, "dll", "exe");
Log.LogInfo($"{assemblyPatcher.AssembliesToPatch.Count} assemblies discovered");
assemblyPatcher.PatchAndLoad();
}
Log.LogMessage("Preloader finished");
var chainloader = new NetChainloader();
chainloader.Initialize();
chainloader.Execute();
var assemblyName = AssemblyName.GetAssemblyName(executablePath);
var entrypointAssembly = Assembly.Load(assemblyName);
entrypointAssembly.EntryPoint.Invoke(null, new [] { args });
}
#region Config
private static readonly ConfigEntry<string> ConfigEntrypointExecutable = ConfigFile.CoreConfig.Bind<string>(
"Preloader.Entrypoint", "Assembly",
null,
"The local filename of the .NET executable to target.");
private static readonly ConfigEntry<bool> ConfigShimHarmony = ConfigFile.CoreConfig.Bind(
"Preloader", "ShimHarmonySupport",
!Utility.CLRSupportsDynamicAssemblies,
"If enabled, basic Harmony functionality is patched to use MonoMod's RuntimeDetour instead.\nTry using this if Harmony does not work in a game.");
private static readonly ConfigEntry<bool> ConfigPreloaderCOutLogging = ConfigFile.CoreConfig.Bind(
"Logging", "PreloaderConsoleOutRedirection",
true,
"Redirects text from Console.Out during preloader patch loading to the BepInEx logging system.");
#endregion
}
}
+131
View File
@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using BepInEx.Logging;
using BepInEx.Preloader.Core;
namespace BepInEx.NetLauncher
{
internal static class NetPreloaderRunner
{
internal static void PreloaderMain(string[] args)
{
Logger.Listeners.Add(new ConsoleLogListener());
ConsoleManager.ForceSetActive(true);
NetPreloader.Start(args);
}
internal static void OuterMain(string[] args, string filename)
{
try
{
Paths.SetExecutablePath(filename);
AppDomain.CurrentDomain.AssemblyResolve += LocalResolve;
PreloaderMain(args);
}
catch (Exception ex)
{
PreloaderLogger.Log.LogFatal("Unhandled exception");
PreloaderLogger.Log.LogFatal(ex);
Program.ReadExit();
}
}
private static Assembly LocalResolve(object sender, ResolveEventArgs args)
{
var assemblyName = new AssemblyName(args.Name);
var foundAssembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(x => x.GetName().Name == assemblyName.Name);
if (foundAssembly != null)
return foundAssembly;
if (LocalUtility.TryResolveDllAssembly(assemblyName, Paths.BepInExAssemblyDirectory, out foundAssembly)
|| LocalUtility.TryResolveDllAssembly(assemblyName, Paths.PatcherPluginPath, out foundAssembly)
|| LocalUtility.TryResolveDllAssembly(assemblyName, Paths.PluginPath, out foundAssembly))
return foundAssembly;
return null;
}
}
class Program
{
internal static void ReadExit()
{
Console.WriteLine("Press enter to exit...");
Console.ReadLine();
Environment.Exit(-1);
}
static void Main(string[] args)
{
try
{
Console.WriteLine("test");
string filename;
#if DEBUG
filename = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName));
#else
filename = Process.GetCurrentProcess().MainModule.FileName;
#endif
ResolveDirectories.Add(Path.Combine(Path.GetDirectoryName(filename), "BepInEx", "Core"));
AppDomain.CurrentDomain.AssemblyResolve += RemoteResolve;
NetPreloaderRunner.OuterMain(args, filename);
}
catch (Exception ex)
{
Console.WriteLine("Unhandled exception");
Console.WriteLine(ex);
ReadExit();
}
}
public static List<string> ResolveDirectories { get; set; } = new List<string>
{
"C:\\Windows\\Microsoft.NET\\assembly\\GAC_32\\Microsoft.Xna.Framework.Game\\v4.0_4.0.0.0__842cf8be1de50553\\"
};
private static Assembly RemoteResolve(object sender, ResolveEventArgs reference)
{
var assemblyName = new AssemblyName(reference.Name);
foreach (var directory in ResolveDirectories)
{
var potentialDirectories = new List<string> { directory };
potentialDirectories.AddRange(Directory.GetDirectories(directory, "*", SearchOption.AllDirectories));
var potentialFiles = potentialDirectories.Select(x => Path.Combine(x, $"{assemblyName.Name}.dll"))
.Concat(potentialDirectories.Select(x => Path.Combine(x, $"{assemblyName.Name}.exe")));
foreach (string path in potentialFiles)
{
if (!File.Exists(path))
continue;
var assembly = Assembly.LoadFrom(path);
if (assembly.GetName().Name == assemblyName.Name)
return assembly;
}
}
return null;
}
}
}
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BepInEx.NetLauncher")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BepInEx.NetLauncher")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("490b052b-7f23-4052-ad04-613856618901")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+62
View File
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace BepInEx.NetLauncher
{
/// <summary>
/// Generic helper properties and methods.
/// </summary>
public static class LocalUtility
{
/// <summary>
/// Try to resolve and load the given assembly DLL.
/// </summary>
/// <param name="assemblyName">Name of the assembly, of the type <see cref="AssemblyName" />.</param>
/// <param name="directory">Directory to search the assembly from.</param>
/// <param name="assembly">The loaded assembly.</param>
/// <returns>True, if the assembly was found and loaded. Otherwise, false.</returns>
private static bool TryResolveDllAssembly<T>(AssemblyName assemblyName, string directory, Func<string, T> loader, out T assembly) where T : class
{
assembly = null;
var potentialDirectories = new List<string> { directory };
potentialDirectories.AddRange(Directory.GetDirectories(directory, "*", SearchOption.AllDirectories));
foreach (string subDirectory in potentialDirectories)
{
string path = Path.Combine(subDirectory, $"{assemblyName.Name}.dll");
if (!File.Exists(path))
continue;
try
{
assembly = loader(path);
}
catch (Exception)
{
continue;
}
return true;
}
return false;
}
/// <summary>
/// Try to resolve and load the given assembly DLL.
/// </summary>
/// <param name="assemblyName">Name of the assembly, of the type <see cref="AssemblyName" />.</param>
/// <param name="directory">Directory to search the assembly from.</param>
/// <param name="assembly">The loaded assembly.</param>
/// <returns>True, if the assembly was found and loaded. Otherwise, false.</returns>
public static bool TryResolveDllAssembly(AssemblyName assemblyName, string directory, out Assembly assembly)
{
return TryResolveDllAssembly(assemblyName, directory, Assembly.LoadFile, out assembly);
}
}
}
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Mono.Cecil" version="0.11.2" targetFramework="net452" />
<package id="MonoMod.RuntimeDetour" version="20.4.3.1" targetFramework="net452" />
<package id="MonoMod.Utils" version="20.4.3.1" targetFramework="net452" />
</packages>
@@ -43,7 +43,7 @@ namespace BepInEx.Preloader.Core
/// </summary> /// </summary>
public string DumpedAssembliesPath { get; set; } = Path.Combine(Paths.BepInExRootPath, "DumpedAssemblies"); public string DumpedAssembliesPath { get; set; } = Path.Combine(Paths.BepInExRootPath, "DumpedAssemblies");
public ManualLogSource Logger { get; } = new ManualLogSource("AssemblyPatcher"); public ManualLogSource Logger { get; } = BepInEx.Logging.Logger.CreateLogSource("AssemblyPatcher");
private static T CreateDelegate<T>(MethodInfo method) where T : class => method != null ? Delegate.CreateDelegate(typeof(T), method) as T : null; private static T CreateDelegate<T>(MethodInfo method) where T : class => method != null ? Delegate.CreateDelegate(typeof(T), method) as T : null;
@@ -173,7 +173,7 @@ namespace BepInEx.Preloader.Core
public void LoadAssemblyDirectory(string directory, params string[] assemblyExtensions) public void LoadAssemblyDirectory(string directory, params string[] assemblyExtensions)
{ {
var filesToSearch = assemblyExtensions var filesToSearch = assemblyExtensions
.SelectMany(ext => Directory.GetFiles(directory, "*." + ext)); .SelectMany(ext => Directory.GetFiles(directory, "*." + ext, SearchOption.TopDirectoryOnly));
foreach (string assemblyPath in filesToSearch) foreach (string assemblyPath in filesToSearch)
{ {
@@ -192,6 +192,8 @@ namespace BepInEx.Preloader.Core
AssembliesToPatch.Add(Path.GetFileName(assemblyPath), assembly); AssembliesToPatch.Add(Path.GetFileName(assemblyPath), assembly);
Logger.LogDebug($"Assembly loaded: {Path.GetFileName(assemblyPath)}");
//if (UnityPatches.AssemblyLocations.ContainsKey(assembly.FullName)) //if (UnityPatches.AssemblyLocations.ContainsKey(assembly.FullName))
//{ //{
// Logger.LogWarning($"Tried to load duplicate assembly {Path.GetFileName(assemblyPath)} from Managed folder! Skipping..."); // Logger.LogWarning($"Tried to load duplicate assembly {Path.GetFileName(assemblyPath)} from Managed folder! Skipping...");
@@ -343,6 +345,8 @@ namespace BepInEx.Preloader.Core
Assembly.Load(assemblyStream.ToArray()); Assembly.Load(assemblyStream.ToArray());
} }
} }
Logger.LogDebug($"Loaded '{assembly.FullName}' into memory");
} }
// Though we have to dispose of all assemblies regardless of them being patched or not // Though we have to dispose of all assemblies regardless of them being patched or not
+42
View File
@@ -34,47 +34,88 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BepInEx.Core", "BepInEx.Cor
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unity", "Unity", "{6E2DD21E-0854-4F4A-B925-D90E0016D03D}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unity", "Unity", "{6E2DD21E-0854-4F4A-B925-D90E0016D03D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BepInEx.NetLauncher", "BepInEx.NetLauncher\BepInEx.NetLauncher.csproj", "{490B052B-7F23-4052-AD04-613856618901}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NetFramework", "NetFramework", "{6EC98884-A3DC-4828-85EF-5F10F7519429}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release_NetFramework|Any CPU = Release_NetFramework|Any CPU
Release_Unity|Any CPU = Release_Unity|Any CPU
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Debug|Any CPU.ActiveCfg = Release|Any CPU {DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Debug|Any CPU.Build.0 = Release|Any CPU {DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Debug|Any CPU.Build.0 = Release|Any CPU
{DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Release_NetFramework|Any CPU.ActiveCfg = Release|Any CPU
{DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Release_Unity|Any CPU.ActiveCfg = Release|Any CPU
{DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Release|Any CPU.ActiveCfg = Release|Any CPU {DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Release|Any CPU.Build.0 = Release|Any CPU {DC89F18B-235B-4C01-AB31-AF40DCE5C4C7}.Release|Any CPU.Build.0 = Release|Any CPU
{6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Debug|Any CPU.ActiveCfg = Release|Any CPU {6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Debug|Any CPU.Build.0 = Release|Any CPU {6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Debug|Any CPU.Build.0 = Release|Any CPU
{6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Release_NetFramework|Any CPU.ActiveCfg = Release|Any CPU
{6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Release_Unity|Any CPU.ActiveCfg = Release|Any CPU
{6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Release|Any CPU.Build.0 = Release|Any CPU {6E6BC1E5-5BE8-4566-B3AE-52C4CB218AEB}.Release|Any CPU.Build.0 = Release|Any CPU
{54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Debug|Any CPU.Build.0 = Debug|Any CPU {54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Release_NetFramework|Any CPU.ActiveCfg = Release|Any CPU
{54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Release_NetFramework|Any CPU.Build.0 = Release|Any CPU
{54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Release_Unity|Any CPU.ActiveCfg = Release|Any CPU
{54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Release_Unity|Any CPU.Build.0 = Release|Any CPU
{54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Release|Any CPU.ActiveCfg = Release|Any CPU {54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Release|Any CPU.Build.0 = Release|Any CPU {54161CFE-FF42-4DDE-B161-3A49545DB5CD}.Release|Any CPU.Build.0 = Release|Any CPU
{A15D6EE6-F954-415B-8605-8A8470CC87DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A15D6EE6-F954-415B-8605-8A8470CC87DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A15D6EE6-F954-415B-8605-8A8470CC87DC}.Debug|Any CPU.Build.0 = Debug|Any CPU {A15D6EE6-F954-415B-8605-8A8470CC87DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A15D6EE6-F954-415B-8605-8A8470CC87DC}.Release_NetFramework|Any CPU.ActiveCfg = Release|Any CPU
{A15D6EE6-F954-415B-8605-8A8470CC87DC}.Release_NetFramework|Any CPU.Build.0 = Release|Any CPU
{A15D6EE6-F954-415B-8605-8A8470CC87DC}.Release_Unity|Any CPU.ActiveCfg = Release|Any CPU
{A15D6EE6-F954-415B-8605-8A8470CC87DC}.Release_Unity|Any CPU.Build.0 = Release|Any CPU
{A15D6EE6-F954-415B-8605-8A8470CC87DC}.Release|Any CPU.ActiveCfg = Release|Any CPU {A15D6EE6-F954-415B-8605-8A8470CC87DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A15D6EE6-F954-415B-8605-8A8470CC87DC}.Release|Any CPU.Build.0 = Release|Any CPU {A15D6EE6-F954-415B-8605-8A8470CC87DC}.Release|Any CPU.Build.0 = Release|Any CPU
{E7CD429A-D057-48E3-8C51-E5C934E8E07B}.Debug|Any CPU.ActiveCfg = Debug|x86 {E7CD429A-D057-48E3-8C51-E5C934E8E07B}.Debug|Any CPU.ActiveCfg = Debug|x86
{E7CD429A-D057-48E3-8C51-E5C934E8E07B}.Debug|Any CPU.Build.0 = Debug|x86 {E7CD429A-D057-48E3-8C51-E5C934E8E07B}.Debug|Any CPU.Build.0 = Debug|x86
{E7CD429A-D057-48E3-8C51-E5C934E8E07B}.Release_NetFramework|Any CPU.ActiveCfg = Release|x86
{E7CD429A-D057-48E3-8C51-E5C934E8E07B}.Release_Unity|Any CPU.ActiveCfg = Release|x86
{E7CD429A-D057-48E3-8C51-E5C934E8E07B}.Release|Any CPU.ActiveCfg = Release|x86 {E7CD429A-D057-48E3-8C51-E5C934E8E07B}.Release|Any CPU.ActiveCfg = Release|x86
{15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Debug|Any CPU.Build.0 = Debug|Any CPU {15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Release_NetFramework|Any CPU.ActiveCfg = Release|Any CPU
{15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Release_NetFramework|Any CPU.Build.0 = Release|Any CPU
{15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Release_Unity|Any CPU.ActiveCfg = Release|Any CPU
{15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Release_Unity|Any CPU.Build.0 = Release|Any CPU
{15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Release|Any CPU.ActiveCfg = Release|Any CPU {15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Release|Any CPU.Build.0 = Release|Any CPU {15F8BC38-A761-4F93-8903-1B531AC5D9F9}.Release|Any CPU.Build.0 = Release|Any CPU
{EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Debug|Any CPU.Build.0 = Debug|Any CPU {EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Release_NetFramework|Any CPU.ActiveCfg = Release|Any CPU
{EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Release_Unity|Any CPU.ActiveCfg = Release|Any CPU
{EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Release_Unity|Any CPU.Build.0 = Release|Any CPU
{EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Release|Any CPU.ActiveCfg = Release|Any CPU {EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Release|Any CPU.Build.0 = Release|Any CPU {EAE9FAE6-8011-45A3-8B6E-0C7F14210533}.Release|Any CPU.Build.0 = Release|Any CPU
{D404C973-441D-48ED-B266-C21320BA0D87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D404C973-441D-48ED-B266-C21320BA0D87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D404C973-441D-48ED-B266-C21320BA0D87}.Debug|Any CPU.Build.0 = Debug|Any CPU {D404C973-441D-48ED-B266-C21320BA0D87}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D404C973-441D-48ED-B266-C21320BA0D87}.Release_NetFramework|Any CPU.ActiveCfg = Release|Any CPU
{D404C973-441D-48ED-B266-C21320BA0D87}.Release_Unity|Any CPU.ActiveCfg = Release|Any CPU
{D404C973-441D-48ED-B266-C21320BA0D87}.Release_Unity|Any CPU.Build.0 = Release|Any CPU
{D404C973-441D-48ED-B266-C21320BA0D87}.Release|Any CPU.ActiveCfg = Release|Any CPU {D404C973-441D-48ED-B266-C21320BA0D87}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D404C973-441D-48ED-B266-C21320BA0D87}.Release|Any CPU.Build.0 = Release|Any CPU {D404C973-441D-48ED-B266-C21320BA0D87}.Release|Any CPU.Build.0 = Release|Any CPU
{4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Debug|Any CPU.Build.0 = Debug|Any CPU {4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Release_NetFramework|Any CPU.ActiveCfg = Release|Any CPU
{4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Release_NetFramework|Any CPU.Build.0 = Release|Any CPU
{4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Release_Unity|Any CPU.ActiveCfg = Release|Any CPU
{4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Release_Unity|Any CPU.Build.0 = Release|Any CPU
{4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Release|Any CPU.ActiveCfg = Release|Any CPU {4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Release|Any CPU.Build.0 = Release|Any CPU {4FFBA620-F5ED-47F9-B90C-DAD1316FD9B9}.Release|Any CPU.Build.0 = Release|Any CPU
{490B052B-7F23-4052-AD04-613856618901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{490B052B-7F23-4052-AD04-613856618901}.Debug|Any CPU.Build.0 = Debug|Any CPU
{490B052B-7F23-4052-AD04-613856618901}.Release_NetFramework|Any CPU.ActiveCfg = Release|Any CPU
{490B052B-7F23-4052-AD04-613856618901}.Release_NetFramework|Any CPU.Build.0 = Release|Any CPU
{490B052B-7F23-4052-AD04-613856618901}.Release_Unity|Any CPU.ActiveCfg = Release|Any CPU
{490B052B-7F23-4052-AD04-613856618901}.Release|Any CPU.ActiveCfg = Release|Any CPU
{490B052B-7F23-4052-AD04-613856618901}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -86,6 +127,7 @@ Global
{A15D6EE6-F954-415B-8605-8A8470CC87DC} = {BAC58F7E-AAD8-4D0C-9490-9765ACBBA6FB} {A15D6EE6-F954-415B-8605-8A8470CC87DC} = {BAC58F7E-AAD8-4D0C-9490-9765ACBBA6FB}
{EAE9FAE6-8011-45A3-8B6E-0C7F14210533} = {6E2DD21E-0854-4F4A-B925-D90E0016D03D} {EAE9FAE6-8011-45A3-8B6E-0C7F14210533} = {6E2DD21E-0854-4F4A-B925-D90E0016D03D}
{D404C973-441D-48ED-B266-C21320BA0D87} = {6E2DD21E-0854-4F4A-B925-D90E0016D03D} {D404C973-441D-48ED-B266-C21320BA0D87} = {6E2DD21E-0854-4F4A-B925-D90E0016D03D}
{490B052B-7F23-4052-AD04-613856618901} = {6EC98884-A3DC-4828-85EF-5F10F7519429}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55AC11EF-F568-4C79-A356-7ED9510145B1} SolutionGuid = {55AC11EF-F568-4C79-A356-7ED9510145B1}