diff --git a/IPA.sln b/IPA.sln new file mode 100644 index 0000000..edd3f93 --- /dev/null +++ b/IPA.sln @@ -0,0 +1,45 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA", "IPA\IPA.csproj", "{14092533-98BB-40A4-9AFC-27BB75672A70}" + ProjectSection(ProjectDependencies) = postProject + {D1390268-F68B-4A55-B50D-EAD25756C8EF} = {D1390268-F68B-4A55-B50D-EAD25756C8EF} + {D1C61AF5-0D2D-4752-8203-1C6929025F7C} = {D1C61AF5-0D2D-4752-8203-1C6929025F7C} + {E2848BFB-5432-42F4-8AE0-D2EC0CDF2F71} = {E2848BFB-5432-42F4-8AE0-D2EC0CDF2F71} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher", "Launcher\Launcher.csproj", "{D1390268-F68B-4A55-B50D-EAD25756C8EF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IllusionPlugin", "IllusionPlugin\IllusionPlugin.csproj", "{E2848BFB-5432-42F4-8AE0-D2EC0CDF2F71}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IllusionInjector", "IllusionInjector\IllusionInjector.csproj", "{D1C61AF5-0D2D-4752-8203-1C6929025F7C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {14092533-98BB-40A4-9AFC-27BB75672A70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14092533-98BB-40A4-9AFC-27BB75672A70}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14092533-98BB-40A4-9AFC-27BB75672A70}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14092533-98BB-40A4-9AFC-27BB75672A70}.Release|Any CPU.Build.0 = Release|Any CPU + {D1390268-F68B-4A55-B50D-EAD25756C8EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1390268-F68B-4A55-B50D-EAD25756C8EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1390268-F68B-4A55-B50D-EAD25756C8EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1390268-F68B-4A55-B50D-EAD25756C8EF}.Release|Any CPU.Build.0 = Release|Any CPU + {E2848BFB-5432-42F4-8AE0-D2EC0CDF2F71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2848BFB-5432-42F4-8AE0-D2EC0CDF2F71}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2848BFB-5432-42F4-8AE0-D2EC0CDF2F71}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2848BFB-5432-42F4-8AE0-D2EC0CDF2F71}.Release|Any CPU.Build.0 = Release|Any CPU + {D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/IPA/IPA.csproj b/IPA/IPA.csproj new file mode 100644 index 0000000..79b5d81 --- /dev/null +++ b/IPA/IPA.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {14092533-98BB-40A4-9AFC-27BB75672A70} + Exe + Properties + IPA + IPA + v3.5 + 512 + Client + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + none + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IPA/Program.cs b/IPA/Program.cs new file mode 100644 index 0000000..9fd5fb6 --- /dev/null +++ b/IPA/Program.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace IPA +{ + class Program + { + static void Main(string[] args) + { + if(args.Length < 1 || !args[0].EndsWith(".exe")) + { + Fail("Drag an (executable) file on the exe!"); + } + + string launcherSrc = Path.Combine("IPA", "Launcher.exe"); + string managedFolder = Path.Combine("IPA", "Managed"); + + // Sanitizing + if (!File.Exists(launcherSrc)) Fail("Couldn't find launcher! Make sure you extracted all contents of the release archive."); + if (!File.Exists(launcherSrc)) Fail("Couldn't find DLLs! Make sure you extracted all contents of the release archive."); + + // Copying + try + { + string projectName = Path.GetFileNameWithoutExtension(args[0]); + string launcherPath = Path.Combine(Environment.CurrentDirectory, projectName + "_Patched.exe"); + string dataPath = Path.Combine(Path.Combine(Environment.CurrentDirectory, projectName + "_Data"), "Managed"); + + File.Copy(launcherSrc, launcherPath, true); + CopyAll(new DirectoryInfo(managedFolder), new DirectoryInfo(dataPath)); + + Console.WriteLine("Successfully copied files!"); + } catch(Exception e) + { + Fail("Oops! This should not have happened.\n\n" + e); + } + } + + public static void CopyAll(DirectoryInfo source, DirectoryInfo target) + { + Directory.CreateDirectory(target.FullName); + + // Copy each file into the new directory. + foreach (FileInfo fi in source.GetFiles()) + { + Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name); + fi.CopyTo(Path.Combine(target.FullName, fi.Name), true); + } + + // Copy each subdirectory using recursion. + foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) + { + DirectoryInfo nextTargetSubDir = + target.CreateSubdirectory(diSourceSubDir.Name); + CopyAll(diSourceSubDir, nextTargetSubDir); + } + } + + + static void Fail(string message) + { + Console.BackgroundColor = ConsoleColor.Red; + Console.ForegroundColor = ConsoleColor.White; + Console.Write("{0,80}", ""); + Console.Write("{0,-80}", " "+message); + Console.Write("{0,80}", ""); + + Console.ReadLine(); + Environment.Exit(1); + } + } +} diff --git a/IPA/Properties/AssemblyInfo.cs b/IPA/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7c8a7df --- /dev/null +++ b/IPA/Properties/AssemblyInfo.cs @@ -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("IPA")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("IPA")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[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("14092533-98bb-40a4-9afc-27bb75672a70")] + +// 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")] diff --git a/IllusionInjector/Bootstrapper.cs b/IllusionInjector/Bootstrapper.cs new file mode 100644 index 0000000..43219e9 --- /dev/null +++ b/IllusionInjector/Bootstrapper.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace IllusionInjector +{ + class Bootstrapper : MonoBehaviour + { + public event Action Destroyed = delegate {}; + + void OnDestroy() + { + Destroyed(); + } + } +} diff --git a/IllusionInjector/CompositePlugin.cs b/IllusionInjector/CompositePlugin.cs new file mode 100644 index 0000000..3a4b0ea --- /dev/null +++ b/IllusionInjector/CompositePlugin.cs @@ -0,0 +1,109 @@ +using IllusionPlugin; +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace IllusionInjector +{ + public class CompositePlugin : IPlugin + { + IEnumerable plugins; + + private delegate void CompositeCall(IPlugin plugin); + + public CompositePlugin(IEnumerable plugins) + { + this.plugins = plugins; + } + + public void OnApplicationStart() + { + Invoke(plugin => plugin.OnApplicationStart()); + } + + public void OnApplicationQuit() + { + Invoke(plugin => plugin.OnApplicationQuit()); + } + + public void OnLevelWasLoaded(int level) + { + foreach (var plugin in plugins) + { + try + { + plugin.OnLevelWasLoaded(level); + } + catch (Exception ex) + { + Console.WriteLine("{0}: {1}", plugin.Name, ex); + } + } + } + + + private void Invoke(CompositeCall callback) + { + foreach (var plugin in plugins) + { + try + { + callback(plugin); + } + catch (Exception ex) + { + Console.WriteLine("{0}: {1}", plugin.Name, ex); + } + } + } + + + + public void OnLevelWasInitialized(int level) + { + foreach (var plugin in plugins) + { + try + { + plugin.OnLevelWasInitialized(level); + } + catch (Exception ex) + { + Console.WriteLine("{0}: {1}", plugin.Name, ex); + } + } + } + + + public void OnUpdate() + { + Invoke(plugin => plugin.OnUpdate()); + } + + public void OnFixedUpdate() + { + Invoke(plugin => plugin.OnFixedUpdate()); + } + + + public string Name + { + get { throw new NotImplementedException(); } + } + + public string Version + { + get { throw new NotImplementedException(); } + } + + public void OnLateUpdate() + { + Invoke(plugin => + { + if (plugin is IEnhancedPlugin) + ((IEnhancedPlugin)plugin).OnLateUpdate(); + }); + } + } +} diff --git a/IllusionInjector/ConsoleWindow.cs b/IllusionInjector/ConsoleWindow.cs new file mode 100644 index 0000000..928795e --- /dev/null +++ b/IllusionInjector/ConsoleWindow.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; +using System.Runtime.InteropServices; +using System.IO; +using System.Text; + +namespace Windows +{ + + class GuiConsole + { + public static void CreateConsole() + { + if (hasConsole) + return; + if (oldOut == IntPtr.Zero) + oldOut = GetStdHandle( -11 ); + if (! AllocConsole()) + throw new Exception("AllocConsole() failed"); + conOut = CreateFile( "CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero ); + if (! SetStdHandle(-11, conOut)) + throw new Exception("SetStdHandle() failed"); + StreamToConsole(); + hasConsole = true; + } + public static void ReleaseConsole() + { + if (! hasConsole) + return; + if (! CloseHandle(conOut)) + throw new Exception("CloseHandle() failed"); + conOut = IntPtr.Zero; + if (! FreeConsole()) + throw new Exception("FreeConsole() failed"); + if (! SetStdHandle(-11, oldOut)) + throw new Exception("SetStdHandle() failed"); + StreamToConsole(); + hasConsole = false; + } + private static void StreamToConsole() + { + Stream cstm = Console.OpenStandardOutput(); + StreamWriter cstw = new StreamWriter( cstm, Encoding.Default ); + cstw.AutoFlush = true; + Console.SetOut( cstw ); + Console.SetError( cstw ); + } + private static bool hasConsole = false; + private static IntPtr conOut; + private static IntPtr oldOut; + [DllImport("kernel32.dll", SetLastError=true)] + private static extern bool AllocConsole(); + [DllImport("kernel32.dll", SetLastError=false)] + private static extern bool FreeConsole(); + [DllImport("kernel32.dll", SetLastError=true)] + private static extern IntPtr GetStdHandle( int nStdHandle ); + [DllImport("kernel32.dll", SetLastError=true)] + private static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput); + [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)] + private static extern IntPtr CreateFile( + string fileName, + int desiredAccess, + int shareMode, + IntPtr securityAttributes, + int creationDisposition, + int flagsAndAttributes, + IntPtr templateFile ); + [DllImport("kernel32.dll", ExactSpelling=true, SetLastError=true)] + private static extern bool CloseHandle(IntPtr handle); + } +} \ No newline at end of file diff --git a/IllusionInjector/IllusionInjector.csproj b/IllusionInjector/IllusionInjector.csproj new file mode 100644 index 0000000..0d8c799 --- /dev/null +++ b/IllusionInjector/IllusionInjector.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {D1C61AF5-0D2D-4752-8203-1C6929025F7C} + Library + Properties + IllusionInjector + IllusionInjector + v3.5 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + ..\Libs\UnityEngine.dll + False + + + + + + + + + + + + + + {e2848bfb-5432-42f4-8ae0-d2ec0cdf2f71} + IllusionPlugin + + + + + \ No newline at end of file diff --git a/IllusionInjector/Injector.cs b/IllusionInjector/Injector.cs new file mode 100644 index 0000000..8bc2a95 --- /dev/null +++ b/IllusionInjector/Injector.cs @@ -0,0 +1,26 @@ +using System; +using UnityEngine; + +namespace IllusionInjector +{ + public static class Injector + { + private static bool injected = false; + public static void Inject() + { + if (!injected) + { + injected = true; + + var bootstrapper = new GameObject("Bootstrapper").AddComponent(); + bootstrapper.Destroyed += Bootstrapper_Destroyed; + } + } + + private static void Bootstrapper_Destroyed() + { + var singleton = new GameObject("PluginManager"); + singleton.AddComponent(); ; + } + } +} diff --git a/IllusionInjector/PluginComponent.cs b/IllusionInjector/PluginComponent.cs new file mode 100644 index 0000000..e895345 --- /dev/null +++ b/IllusionInjector/PluginComponent.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace IllusionInjector +{ + public class PluginComponent : MonoBehaviour + { + private CompositePlugin plugins; + private bool freshlyLoaded = false; + + void Awake() + { + DontDestroyOnLoad(gameObject); + + if (Environment.CommandLine.Contains("--verbose") && !Screen.fullScreen) + { + Windows.GuiConsole.CreateConsole(); + } + + plugins = new CompositePlugin(PluginManager.Plugins); + plugins.OnApplicationStart(); + } + + void Start() + { + OnLevelWasLoaded(Application.loadedLevel); + } + + void Update() + { + if (freshlyLoaded) + { + freshlyLoaded = false; + plugins.OnLevelWasInitialized(Application.loadedLevel); + } + plugins.OnUpdate(); + } + + void LateUpdate() + { + plugins.OnLateUpdate(); + } + + void FixedUpdate() + { + plugins.OnFixedUpdate(); + } + + void OnDestroy() + { + plugins.OnApplicationQuit(); + } + + void OnLevelWasLoaded(int level) + { + plugins.OnLevelWasLoaded(level); + freshlyLoaded = true; + } + + } +} diff --git a/IllusionInjector/PluginManager.cs b/IllusionInjector/PluginManager.cs new file mode 100644 index 0000000..2d089d5 --- /dev/null +++ b/IllusionInjector/PluginManager.cs @@ -0,0 +1,126 @@ +using IllusionPlugin; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace IllusionInjector +{ + public static class PluginManager + { + private static List _Plugins = null; + + /// + /// Gets the list of loaded plugins and loads them if necessary. + /// + public static IEnumerable Plugins + { + get + { + if(_Plugins == null) + { + LoadPlugins(); + } + return _Plugins; + } + } + + + private static void LoadPlugins() + { + string pluginDirectory = Path.Combine(Environment.CurrentDirectory, "Plugins"); + + // Process.GetCurrentProcess().MainModule crashes the game and Assembly.GetEntryAssembly() is NULL, + // so we need to resort to P/Invoke + string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath); + Console.WriteLine(exeName); + _Plugins = new List(); + + if (!Directory.Exists(pluginDirectory)) return; + + String[] files = Directory.GetFiles(pluginDirectory, "*.dll"); + foreach (var s in files) + { + _Plugins.AddRange(LoadPluginsFromFile(Path.Combine(pluginDirectory, s), exeName)); + } + + + // DEBUG + Console.WriteLine("-----------------------------"); + Console.WriteLine("Loading plugins from {0} and found {1}", pluginDirectory, _Plugins.Count); + Console.WriteLine("-----------------------------"); + foreach (var plugin in _Plugins) + { + + Console.WriteLine(" {0}: {1}", plugin.Name, plugin.Version); + } + Console.WriteLine("-----------------------------"); + + } + + private static IEnumerable LoadPluginsFromFile(string file, string exeName) + { + List plugins = new List(); + + if (!File.Exists(file) || !file.EndsWith(".dll", true, null)) + return plugins; + + try + { + Assembly assembly = Assembly.LoadFrom(file); + + foreach (Type t in assembly.GetTypes()) + { + if (t.GetInterface("IPlugin") != null) + { + try + { + + IPlugin pluginInstance = Activator.CreateInstance(t) as IPlugin; + string[] filter = null; + + if (pluginInstance is IEnhancedPlugin) + { + filter = ((IEnhancedPlugin)pluginInstance).Filter; + } + + if(filter == null || Enumerable.Contains(filter, exeName, StringComparer.OrdinalIgnoreCase)) + plugins.Add(pluginInstance); + } + catch (Exception) + { + } + } + } + + } + catch (Exception) + { + } + + return plugins; + } + + public class AppInfo + { + [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false)] + private static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length); + private static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero); + public static string StartupPath + { + get + { + StringBuilder stringBuilder = new StringBuilder(260); + GetModuleFileName(NullHandleRef, stringBuilder, stringBuilder.Capacity); + return stringBuilder.ToString(); + } + } + } + + } +} diff --git a/IllusionInjector/Properties/AssemblyInfo.cs b/IllusionInjector/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f1e97dc --- /dev/null +++ b/IllusionInjector/Properties/AssemblyInfo.cs @@ -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("IllusionInjector")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("IllusionInjector")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[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("400a540a-d21f-4609-966b-206059b6e73b")] + +// 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")] diff --git a/IllusionPlugin/IEnhancedPlugin.cs b/IllusionPlugin/IEnhancedPlugin.cs new file mode 100644 index 0000000..304b4ba --- /dev/null +++ b/IllusionPlugin/IEnhancedPlugin.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IllusionPlugin +{ + public interface IEnhancedPlugin : IPlugin + { + /// + /// Gets a list of executables this plugin should be excuted on (without the file ending) + /// + /// { "PlayClub", "PlayClubStudio" } + string[] Filter { get; } + + void OnLateUpdate(); + } +} diff --git a/IllusionPlugin/IPlugin.cs b/IllusionPlugin/IPlugin.cs new file mode 100644 index 0000000..1c4effd --- /dev/null +++ b/IllusionPlugin/IPlugin.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IllusionPlugin +{ + /// + /// Interface for generic Illusion unity plugins. Every class that implements this will be loaded if the DLL is placed at + /// data/Managed/Plugins. + /// + public interface IPlugin + { + + /// + /// Gets the name of the plugin. + /// + string Name { get; } + + /// + /// Gets the version of the plugin. + /// + string Version { get; } + + /// + /// Gets invoked when the application is started. + /// + void OnApplicationStart(); + + /// + /// Gets invoked when the application is closed. + /// + void OnApplicationQuit(); + + /// + /// Gets invoked whenever a level is loaded. + /// + /// + void OnLevelWasLoaded(int level); + + /// + /// Gets invoked after the first update cycle after a level was loaded. + /// + /// + void OnLevelWasInitialized(int level); + + /// + /// Gets invoked on every graphic update. + /// + void OnUpdate(); + + + /// + /// Gets invoked on ever physics update. + /// + void OnFixedUpdate(); + } +} diff --git a/IllusionPlugin/IllusionPlugin.XML b/IllusionPlugin/IllusionPlugin.XML new file mode 100644 index 0000000..11af6a6 --- /dev/null +++ b/IllusionPlugin/IllusionPlugin.XML @@ -0,0 +1,178 @@ + + + + IllusionPlugin + + + + + Gets a list of executables this plugin should be excuted on (without the file ending) + + { "PlayClub", "PlayClubStudio" } + + + + Create a New INI file to store or load data + + + + + INIFile Constructor. + + + + + + Write Data to the INI File + + + Section name + + Key Name + + Value Name + + + + Read Data Value From the Ini File + + + + + + + + + Interface for generic Illusion unity plugins. Every class that implements this will be loaded if the DLL is placed at + data/Managed/Plugins. + + + + + Gets the name of the plugin. + + + + + Gets the version of the plugin. + + + + + Gets invoked when the application is started. + + + + + Gets invoked when the application is closed. + + + + + Gets invoked whenever a level is loaded. + + + + + + Gets invoked after the first update cycle after a level was loaded. + + + + + + Gets invoked on every graphic update. + + + + + Gets invoked on ever physics update. + + + + + Allows to get and set preferences for your mod. + + + + + Gets a string from the ini. + + Section of the key. + Name of the key. + Value that should be used when no value is found. + Whether or not the default value should be written if no value is found. + + + + + Gets an int from the ini. + + Section of the key. + Name of the key. + Value that should be used when no value is found. + Whether or not the default value should be written if no value is found. + + + + + Gets a float from the ini. + + Section of the key. + Name of the key. + Value that should be used when no value is found. + Whether or not the default value should be written if no value is found. + + + + + Gets a bool from the ini. + + Section of the key. + Name of the key. + Value that should be used when no value is found. + Whether or not the default value should be written if no value is found. + + + + + Checks whether or not a key exists in the ini. + + Section of the key. + Name of the key. + + + + + Sets a float in the ini. + + Section of the key. + Name of the key. + Value that should be written. + + + + Sets an int in the ini. + + Section of the key. + Name of the key. + Value that should be written. + + + + Sets a string in the ini. + + Section of the key. + Name of the key. + Value that should be written. + + + + Sets a bool in the ini. + + Section of the key. + Name of the key. + Value that should be written. + + + diff --git a/IllusionPlugin/IllusionPlugin.csproj b/IllusionPlugin/IllusionPlugin.csproj new file mode 100644 index 0000000..0e1e4e6 --- /dev/null +++ b/IllusionPlugin/IllusionPlugin.csproj @@ -0,0 +1,55 @@ + + + + + Debug + AnyCPU + {E2848BFB-5432-42F4-8AE0-D2EC0CDF2F71} + Library + Properties + IllusionPlugin + IllusionPlugin + v3.5 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\IllusionPlugin.XML + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IllusionPlugin/IniFile.cs b/IllusionPlugin/IniFile.cs new file mode 100644 index 0000000..14e9b81 --- /dev/null +++ b/IllusionPlugin/IniFile.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace IllusionPlugin +{ + /// + /// Create a New INI file to store or load data + /// + internal class IniFile + { + [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileStringW", + SetLastError = true, + CharSet = CharSet.Unicode, ExactSpelling = true, + CallingConvention = CallingConvention.StdCall)] + private static extern int GetPrivateProfileString( + string lpSection, + string lpKey, + string lpDefault, + StringBuilder lpReturnString, + int nSize, + string lpFileName); + + [DllImport("KERNEL32.DLL", EntryPoint = "WritePrivateProfileStringW", + SetLastError = true, + CharSet = CharSet.Unicode, ExactSpelling = true, + CallingConvention = CallingConvention.StdCall)] + private static extern int WritePrivateProfileString( + string lpSection, + string lpKey, + string lpValue, + string lpFileName); + + private string _path = ""; + public string Path + { + get + { + return _path; + } + set + { + if (!File.Exists(value)) + File.WriteAllText(value, "", Encoding.Unicode); + _path = value; + } + } + + /// + /// INIFile Constructor. + /// + /// + public IniFile(string INIPath) + { + this.Path = INIPath; + } + + /// + /// Write Data to the INI File + /// + /// + /// Section name + /// + /// Key Name + /// + /// Value Name + public void IniWriteValue(string Section, string Key, string Value) + { + WritePrivateProfileString(Section, Key, Value, this.Path); + } + + /// + /// Read Data Value From the Ini File + /// + /// + /// + /// + /// + public string IniReadValue(string Section, string Key) + { + const int MAX_CHARS = 1023; + StringBuilder result = new StringBuilder(MAX_CHARS); + GetPrivateProfileString(Section, Key, "", result, MAX_CHARS, this.Path); + return result.ToString(); + } + } +} diff --git a/IllusionPlugin/ModPrefs.cs b/IllusionPlugin/ModPrefs.cs new file mode 100644 index 0000000..acdbd7c --- /dev/null +++ b/IllusionPlugin/ModPrefs.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace IllusionPlugin +{ + /// + /// Allows to get and set preferences for your mod. + /// + public static class ModPrefs + { + private static IniFile _instance; + private static IniFile Instance + { + get + { + if (_instance == null) + { + _instance = new IniFile(Path.Combine(Environment.CurrentDirectory, "UserData/modprefs.ini")); + } + return _instance; + } + } + + + /// + /// Gets a string from the ini. + /// + /// Section of the key. + /// Name of the key. + /// Value that should be used when no value is found. + /// Whether or not the default value should be written if no value is found. + /// + public static string GetString(string section, string name, string defaultValue = "", bool autoSave = false) + { + string value = Instance.IniReadValue(section, name); + if (value != "") + return value; + else if (autoSave) + SetString(section, name, defaultValue); + + return defaultValue; + } + + /// + /// Gets an int from the ini. + /// + /// Section of the key. + /// Name of the key. + /// Value that should be used when no value is found. + /// Whether or not the default value should be written if no value is found. + /// + public static int GetInt(string section, string name, int defaultValue = 0, bool autoSave = false) + { + int value; + if (int.TryParse(Instance.IniReadValue(section, name), out value)) + return value; + else if (autoSave) + SetInt(section, name, defaultValue); + + return defaultValue; + } + + + /// + /// Gets a float from the ini. + /// + /// Section of the key. + /// Name of the key. + /// Value that should be used when no value is found. + /// Whether or not the default value should be written if no value is found. + /// + public static float GetFloat(string section, string name, float defaultValue = 0f, bool autoSave = false) + { + float value; + if (float.TryParse(Instance.IniReadValue(section, name), out value)) + return value; + else if (autoSave) + SetFloat(section, name, defaultValue); + + return defaultValue; + } + + /// + /// Gets a bool from the ini. + /// + /// Section of the key. + /// Name of the key. + /// Value that should be used when no value is found. + /// Whether or not the default value should be written if no value is found. + /// + public static bool GetBool(string section, string name, bool defaultValue = false, bool autoSave = false) + { + string sVal = GetString(section, name, null); + if (sVal == "1" || sVal == "0") + { + return sVal == "1"; + } else if (autoSave) + { + SetBool(section, name, defaultValue); + } + + return defaultValue; + } + + + /// + /// Checks whether or not a key exists in the ini. + /// + /// Section of the key. + /// Name of the key. + /// + public static bool HasKey(string section, string name) + { + return Instance.IniReadValue(section, name) != null; + } + + /// + /// Sets a float in the ini. + /// + /// Section of the key. + /// Name of the key. + /// Value that should be written. + public static void SetFloat(string section, string name, float value) + { + Instance.IniWriteValue(section, name, value.ToString()); + } + + /// + /// Sets an int in the ini. + /// + /// Section of the key. + /// Name of the key. + /// Value that should be written. + public static void SetInt(string section, string name, int value) + { + Instance.IniWriteValue(section, name, value.ToString()); + + } + + /// + /// Sets a string in the ini. + /// + /// Section of the key. + /// Name of the key. + /// Value that should be written. + public static void SetString(string section, string name, string value) + { + Instance.IniWriteValue(section, name, value); + + } + + /// + /// Sets a bool in the ini. + /// + /// Section of the key. + /// Name of the key. + /// Value that should be written. + public static void SetBool(string section, string name, bool value) + { + Instance.IniWriteValue(section, name, value ? "1" : "0"); + + } + } +} diff --git a/IllusionPlugin/Properties/AssemblyInfo.cs b/IllusionPlugin/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c2425b9 --- /dev/null +++ b/IllusionPlugin/Properties/AssemblyInfo.cs @@ -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("IllusionPlugin")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("IllusionPlugin")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[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("e8cea89d-6c2f-4729-94b3-f355f7db19e5")] + +// 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")] \ No newline at end of file diff --git a/Launcher/Launcher.csproj b/Launcher/Launcher.csproj new file mode 100644 index 0000000..2293d57 --- /dev/null +++ b/Launcher/Launcher.csproj @@ -0,0 +1,104 @@ + + + + + Debug + AnyCPU + {D1390268-F68B-4A55-B50D-EAD25756C8EF} + WinExe + Properties + QuietLauncher + Launcher + v3.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Mono.Cecil.0.9.6.4\lib\net35\Mono.Cecil.dll + True + + + ..\packages\Mono.Cecil.0.9.6.4\lib\net35\Mono.Cecil.Mdb.dll + False + + + ..\packages\Mono.Cecil.0.9.6.4\lib\net35\Mono.Cecil.Pdb.dll + False + + + ..\packages\Mono.Cecil.0.9.6.4\lib\net35\Mono.Cecil.Rocks.dll + False + + + + + + + + + + + + + + + + True + True + Resources.resx + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + \ No newline at end of file diff --git a/Launcher/Program.cs b/Launcher/Program.cs new file mode 100644 index 0000000..dcdaeb7 --- /dev/null +++ b/Launcher/Program.cs @@ -0,0 +1,299 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using Mono.Cecil; +using Mono.Cecil.Cil; +using System.Threading; + +namespace QuietLauncher +{ + static class Program + { + private static string[] TABOO_NAMES = { + //"Start", + //"Update", + //"Awake", + //"OnDestroy" + }; + private static string[] ENTRY_TYPES = { "Display" }; + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + try { + var execPath = Application.ExecutablePath; + var fileName = Path.GetFileNameWithoutExtension(execPath); + if (fileName.IndexOf("VR") == -1 && fileName.IndexOf("_") == -1) return; + + bool vrMode = fileName.IndexOf("VR") > 0; + bool directMode = Application.ExecutablePath.EndsWith("_DirectToRift.exe"); + string baseName = execPath.Substring(0, vrMode + ? execPath.LastIndexOf("VR") + : execPath.LastIndexOf("_")); + + string executable = baseName + ".exe"; + var file = new FileInfo(executable); + if (file.Exists) + { + var args = Environment.GetCommandLineArgs().ToList(); + bool created = false; + + var dataFolder = Path.Combine(file.DirectoryName, Path.GetFileNameWithoutExtension(file.Name) + "_Data"); + var assemblyPath = Path.Combine(Path.Combine(dataFolder, "Managed"), "Assembly-CSharp.dll"); + var enginePath = Path.Combine(Path.Combine(dataFolder, "Managed"), "UnityEngine.dll"); + var directToRiftPath = baseName + "_DirectToRift.exe"; + + try + { + if (directMode) + { + //args[Array.IndexOf(args, "--direct")] = "-force-d3d11"; + + + if (!File.Exists(directToRiftPath)) + { + File.WriteAllBytes(directToRiftPath, Resources.DirectToRift); + created = true; + } + + file = new FileInfo(directToRiftPath); + } + + + if (vrMode) args.Add("--vr"); + var arguments = string.Join(" ", args.ToArray()); + + try + { + Patch(assemblyPath, enginePath); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + Process.Start(file.FullName, arguments); + + } + finally + { + if (created && directMode) + { + var thread = new Thread(new ThreadStart(delegate + { + int attempts = 0; + while (File.Exists(directToRiftPath) && attempts++ < 20) + { + Thread.Sleep(1000); + try + { + File.Delete(directToRiftPath); + } + catch (Exception ex) + { + + } + } + })); + thread.Start(); + thread.Join(); + // Clean up + } + } + } + else + { + MessageBox.Show("Could not find: " + file.FullName, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } catch(Exception globalException) { + MessageBox.Show(globalException.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + } + + static string PrepareBackup(FileInfo file) + { + string backup = file.FullName + ".Original"; + + if (File.Exists(backup)) + { + int i = 1; + string backupBase = backup; + while (File.Exists(backup)) + { + backup = backupBase + i++; + } + } + return backup; + } + + static void Patch(string assemblyFile, string engineFile) + { + + var input = new FileInfo(assemblyFile); + var engineInput = new FileInfo(engineFile); + string assemblyBackup = PrepareBackup(input); + string engineBackup = PrepareBackup(engineInput); + + if (!input.Exists) Fail("File does not exist."); + + + var directory = input.DirectoryName; + var injectorPath = Path.Combine(directory, "IllusionInjector.dll"); + + if (!File.Exists(injectorPath)) Fail("You're missing IllusionInjector.dll. Please make sure to extract all files correctly."); + + var resolver = new DefaultAssemblyResolver(); + resolver.AddSearchDirectory(directory); + + var parameters = new ReaderParameters + { + // SymbolReaderProvider = GetSymbolReaderProvider(), + AssemblyResolver = resolver, + }; + + var assemblyModule = ModuleDefinition.ReadModule(input.FullName, parameters); + var engineModule = ModuleDefinition.ReadModule(engineInput.FullName, parameters); + + if (!IsPatched(engineModule)) //|| !isVirtualized) + { + // Make backup + input.CopyTo(engineBackup); + // First, let's add the reference + var nameReference = new AssemblyNameReference("IllusionInjector", new Version(1, 0, 0, 0)); + engineModule.AssemblyReferences.Add(nameReference); + var targetType = FindEntryType(engineModule); + + if (targetType == null) Fail("Couldn't find entry class. Aborting."); + + var awakeMethod = targetType.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic); + if (awakeMethod == null) + { + Fail("Couldn't find awake method. Aborting."); + } + + var injector = ModuleDefinition.ReadModule(injectorPath); + var methodReference = engineModule.Import(injector.GetType("IllusionInjector.Injector").Methods.First(m => m.Name == "Inject")); + //var methodReference = module.GetMemberReferences().FirstOrDefault(r => r.FullName == "IllusionInjector.Injector"); + + awakeMethod.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, methodReference)); + engineModule.Write(engineInput.FullName); + } + if(!IsVirtualized(assemblyModule)) + { + input.CopyTo(assemblyBackup); + Virtualize(assemblyModule); + assemblyModule.Write(input.FullName); + } + } + + + /// + /// The forbidden deed of the gods -- make ALL methods virtual and public + /// + /// + private static void Virtualize(ModuleDefinition module) + { + foreach (var type in module.Types) + { + VirtualizeType(type); + } + } + + private static void VirtualizeType(TypeDefinition type) + { + if (type.IsSealed) return; + if (type.IsInterface) return; + if (type.IsAbstract) return; + + // These two don't seem to work. + if (type.Name == "SceneControl" || type.Name == "ConfigUI") return; + + //if (type.FullName.Contains("RootMotion")) return; + //if (type.Methods.Any(m => m.Body != null && m.Body.Variables.Any(v => v.VariableType.FullName.Contains("<")))) return; + //if (!type.FullName.Contains("H_VoiceControl")) return; + //if (!type.FullName.Contains("Human")) return; + //if (type.Namespace.Length > 1) return; + + + // Take care of sub types + foreach (var subType in type.NestedTypes) + { + VirtualizeType(subType); + } + + foreach (var method in type.Methods) + { + Console.WriteLine(method.Name); + if (method.IsManaged + && !TABOO_NAMES.Contains(method.Name) + && method.IsIL + && !method.IsStatic + && !method.IsVirtual + && !method.IsAbstract + && !method.IsAddOn + && !method.IsConstructor + && !method.IsSpecialName + && !method.IsGenericInstance + && !method.HasOverrides) + { + method.IsVirtual = true; + method.IsPublic = true; + method.IsPrivate = false; + method.IsNewSlot = true; + method.IsHideBySig = true; + } + } + + foreach (var field in type.Fields) + { + if (field.IsPrivate) field.IsFamily = true; + //field.IsPublic = true; + } + + //foreach (var property in type.Properties) + //{ + // property.GetMethod.IsVirtual = true; + // property.GetMethod.IsPublic = true; + // property.SetMethod.IsVirtual = true; + // property.SetMethod.IsPublic = true; + //} + + } + + private static bool IsPatched(ModuleDefinition module) + { + foreach (var @ref in module.AssemblyReferences) + { + if (@ref.Name == "IllusionInjector") return true; + } + return false; + } + + private static bool IsVirtualized(ModuleDefinition module) + { + return module.GetTypes().SelectMany(t => t.Methods.Where(m => m.Name == "Awake")).All(m => m.IsVirtual); + } + + private static void Fail(string reason) { + throw new Exception(reason); + } + + private static TypeDefinition FindEntryType(ModuleDefinition module) + { + return module.GetTypes().FirstOrDefault(IsEntryType); + } + + private static bool IsEntryType(TypeDefinition type) + { + return ENTRY_TYPES.Contains(type.Name); + } + + } +} diff --git a/Launcher/Properties/AssemblyInfo.cs b/Launcher/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c2da46c --- /dev/null +++ b/Launcher/Properties/AssemblyInfo.cs @@ -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("QuietLauncher")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("QuietLauncher")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[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("d590f676-c2c0-4b80-ae93-6edf274320e6")] + +// 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")] diff --git a/Launcher/Properties/Resources.Designer.cs b/Launcher/Properties/Resources.Designer.cs new file mode 100644 index 0000000..41e16b2 --- /dev/null +++ b/Launcher/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace QuietLauncher.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("QuietLauncher.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Launcher/Properties/Resources.resx b/Launcher/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Launcher/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Launcher/Properties/Settings.Designer.cs b/Launcher/Properties/Settings.Designer.cs new file mode 100644 index 0000000..62bab1b --- /dev/null +++ b/Launcher/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace QuietLauncher.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Launcher/Properties/Settings.settings b/Launcher/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Launcher/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Launcher/Resources.Designer.cs b/Launcher/Resources.Designer.cs new file mode 100644 index 0000000..04b9966 --- /dev/null +++ b/Launcher/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace QuietLauncher { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("QuietLauncher.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] DirectToRift { + get { + object obj = ResourceManager.GetObject("DirectToRift", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/Launcher/Resources.resx b/Launcher/Resources.resx new file mode 100644 index 0000000..6cd9173 --- /dev/null +++ b/Launcher/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\DirectToRift.exe;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Launcher/Resources/DirectToRift.exe b/Launcher/Resources/DirectToRift.exe new file mode 100644 index 0000000..bf8cb51 Binary files /dev/null and b/Launcher/Resources/DirectToRift.exe differ diff --git a/Launcher/packages.config b/Launcher/packages.config new file mode 100644 index 0000000..1fcd5ba --- /dev/null +++ b/Launcher/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Libs/UnityEngine.dll b/Libs/UnityEngine.dll new file mode 100644 index 0000000..6a4c68c Binary files /dev/null and b/Libs/UnityEngine.dll differ