Browse Source

Initial commit.

tags/3.0a
Eusth 6 years ago
parent
commit
c7500c0933
31 changed files with 2200 additions and 0 deletions
  1. +45
    -0
      IPA.sln
  2. +66
    -0
      IPA/IPA.csproj
  3. +75
    -0
      IPA/Program.cs
  4. +36
    -0
      IPA/Properties/AssemblyInfo.cs
  5. +18
    -0
      IllusionInjector/Bootstrapper.cs
  6. +109
    -0
      IllusionInjector/CompositePlugin.cs
  7. +71
    -0
      IllusionInjector/ConsoleWindow.cs
  8. +66
    -0
      IllusionInjector/IllusionInjector.csproj
  9. +26
    -0
      IllusionInjector/Injector.cs
  10. +63
    -0
      IllusionInjector/PluginComponent.cs
  11. +126
    -0
      IllusionInjector/PluginManager.cs
  12. +36
    -0
      IllusionInjector/Properties/AssemblyInfo.cs
  13. +17
    -0
      IllusionPlugin/IEnhancedPlugin.cs
  14. +57
    -0
      IllusionPlugin/IPlugin.cs
  15. +178
    -0
      IllusionPlugin/IllusionPlugin.XML
  16. +55
    -0
      IllusionPlugin/IllusionPlugin.csproj
  17. +89
    -0
      IllusionPlugin/IniFile.cs
  18. +166
    -0
      IllusionPlugin/ModPrefs.cs
  19. +36
    -0
      IllusionPlugin/Properties/AssemblyInfo.cs
  20. +104
    -0
      Launcher/Launcher.csproj
  21. +299
    -0
      Launcher/Program.cs
  22. +36
    -0
      Launcher/Properties/AssemblyInfo.cs
  23. +71
    -0
      Launcher/Properties/Resources.Designer.cs
  24. +117
    -0
      Launcher/Properties/Resources.resx
  25. +30
    -0
      Launcher/Properties/Settings.Designer.cs
  26. +7
    -0
      Launcher/Properties/Settings.settings
  27. +73
    -0
      Launcher/Resources.Designer.cs
  28. +124
    -0
      Launcher/Resources.resx
  29. BIN
      Launcher/Resources/DirectToRift.exe
  30. +4
    -0
      Launcher/packages.config
  31. BIN
      Libs/UnityEngine.dll

+ 45
- 0
IPA.sln View File

@@ -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

+ 66
- 0
IPA/IPA.csproj View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.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')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{14092533-98BB-40A4-9AFC-27BB75672A70}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>IPA</RootNamespace>
<AssemblyName>IPA</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<Target Name="AfterBuild">
<Message Text="Packing..." Importance="normal" />
<ItemGroup>
<LauncherDlls Include="$(SolutionDir)Launcher\$(OutDir)*.dll" />
<Launcher Include="$(SolutionDir)Launcher\$(OutDir)Launcher.exe" />
<Dlls Include="$(SolutionDir)IllusionInjector\$(OutDir)**\*" />
</ItemGroup>
<Copy SourceFiles="@(Dlls)" DestinationFolder="$(OutputPath)IPA\Managed" />
<Copy SourceFiles="@(Launcher)" DestinationFolder="$(OutputPath)IPA" />
<Copy SourceFiles="@(LauncherDlls)" DestinationFolder="$(OutputPath)" />
</Target>
</Project>

+ 75
- 0
IPA/Program.cs View File

@@ -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);
}
}
}

+ 36
- 0
IPA/Properties/AssemblyInfo.cs View File

@@ -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")]

+ 18
- 0
IllusionInjector/Bootstrapper.cs View File

@@ -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();
}
}
}

+ 109
- 0
IllusionInjector/CompositePlugin.cs View File

@@ -0,0 +1,109 @@
using IllusionPlugin;
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

namespace IllusionInjector
{
public class CompositePlugin : IPlugin
{
IEnumerable<IPlugin> plugins;

private delegate void CompositeCall(IPlugin plugin);

public CompositePlugin(IEnumerable<IPlugin> 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();
});
}
}
}

+ 71
- 0
IllusionInjector/ConsoleWindow.cs View File

@@ -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);
}
}

+ 66
- 0
IllusionInjector/IllusionInjector.csproj View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.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')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D1C61AF5-0D2D-4752-8203-1C6929025F7C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>IllusionInjector</RootNamespace>
<AssemblyName>IllusionInjector</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="UnityEngine">
<HintPath>..\Libs\UnityEngine.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Bootstrapper.cs" />
<Compile Include="CompositePlugin.cs" />
<Compile Include="ConsoleWindow.cs" />
<Compile Include="Injector.cs" />
<Compile Include="PluginManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PluginComponent.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IllusionPlugin\IllusionPlugin.csproj">
<Project>{e2848bfb-5432-42f4-8ae0-d2ec0cdf2f71}</Project>
<Name>IllusionPlugin</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 26
- 0
IllusionInjector/Injector.cs View File

@@ -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>();
bootstrapper.Destroyed += Bootstrapper_Destroyed;
}
}

private static void Bootstrapper_Destroyed()
{
var singleton = new GameObject("PluginManager");
singleton.AddComponent<PluginComponent>(); ;
}
}
}

+ 63
- 0
IllusionInjector/PluginComponent.cs View File

@@ -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;
}

}
}

+ 126
- 0
IllusionInjector/PluginManager.cs View File

@@ -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<IPlugin> _Plugins = null;

/// <summary>
/// Gets the list of loaded plugins and loads them if necessary.
/// </summary>
public static IEnumerable<IPlugin> 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<IPlugin>();

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<IPlugin> LoadPluginsFromFile(string file, string exeName)
{
List<IPlugin> plugins = new List<IPlugin>();

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();
}
}
}

}
}

+ 36
- 0
IllusionInjector/Properties/AssemblyInfo.cs View File

@@ -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")]

+ 17
- 0
IllusionPlugin/IEnhancedPlugin.cs View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace IllusionPlugin
{
public interface IEnhancedPlugin : IPlugin
{
/// <summary>
/// Gets a list of executables this plugin should be excuted on (without the file ending)
/// </summary>
/// <example>{ "PlayClub", "PlayClubStudio" }</example>
string[] Filter { get; }

void OnLateUpdate();
}
}

+ 57
- 0
IllusionPlugin/IPlugin.cs View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace IllusionPlugin
{
/// <summary>
/// Interface for generic Illusion unity plugins. Every class that implements this will be loaded if the DLL is placed at
/// data/Managed/Plugins.
/// </summary>
public interface IPlugin
{

/// <summary>
/// Gets the name of the plugin.
/// </summary>
string Name { get; }

/// <summary>
/// Gets the version of the plugin.
/// </summary>
string Version { get; }

/// <summary>
/// Gets invoked when the application is started.
/// </summary>
void OnApplicationStart();

/// <summary>
/// Gets invoked when the application is closed.
/// </summary>
void OnApplicationQuit();

/// <summary>
/// Gets invoked whenever a level is loaded.
/// </summary>
/// <param name="level"></param>
void OnLevelWasLoaded(int level);

/// <summary>
/// Gets invoked after the first update cycle after a level was loaded.
/// </summary>
/// <param name="level"></param>
void OnLevelWasInitialized(int level);

/// <summary>
/// Gets invoked on every graphic update.
/// </summary>
void OnUpdate();


/// <summary>
/// Gets invoked on ever physics update.
/// </summary>
void OnFixedUpdate();
}
}

+ 178
- 0
IllusionPlugin/IllusionPlugin.XML View File

@@ -0,0 +1,178 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>IllusionPlugin</name>
</assembly>
<members>
<member name="P:IllusionPlugin.IEnhancedPlugin.Filter">
<summary>
Gets a list of executables this plugin should be excuted on (without the file ending)
</summary>
<example>{ "PlayClub", "PlayClubStudio" }</example>
</member>
<member name="T:IllusionPlugin.IniFile">
<summary>
Create a New INI file to store or load data
</summary>
</member>
<member name="M:IllusionPlugin.IniFile.#ctor(System.String)">
<summary>
INIFile Constructor.
</summary>
<PARAM name="INIPath"></PARAM>
</member>
<member name="M:IllusionPlugin.IniFile.IniWriteValue(System.String,System.String,System.String)">
<summary>
Write Data to the INI File
</summary>
<PARAM name="Section"></PARAM>
Section name
<PARAM name="Key"></PARAM>
Key Name
<PARAM name="Value"></PARAM>
Value Name
</member>
<member name="M:IllusionPlugin.IniFile.IniReadValue(System.String,System.String)">
<summary>
Read Data Value From the Ini File
</summary>
<PARAM name="Section"></PARAM>
<PARAM name="Key"></PARAM>
<PARAM name="Path"></PARAM>
<returns></returns>
</member>
<member name="T:IllusionPlugin.IPlugin">
<summary>
Interface for generic Illusion unity plugins. Every class that implements this will be loaded if the DLL is placed at
data/Managed/Plugins.
</summary>
</member>
<member name="P:IllusionPlugin.IPlugin.Name">
<summary>
Gets the name of the plugin.
</summary>
</member>
<member name="P:IllusionPlugin.IPlugin.Version">
<summary>
Gets the version of the plugin.
</summary>
</member>
<member name="M:IllusionPlugin.IPlugin.OnApplicationStart">
<summary>
Gets invoked when the application is started.
</summary>
</member>
<member name="M:IllusionPlugin.IPlugin.OnApplicationQuit">
<summary>
Gets invoked when the application is closed.
</summary>
</member>
<member name="M:IllusionPlugin.IPlugin.OnLevelWasLoaded(System.Int32)">
<summary>
Gets invoked whenever a level is loaded.
</summary>
<param name="level"></param>
</member>
<member name="M:IllusionPlugin.IPlugin.OnLevelWasInitialized(System.Int32)">
<summary>
Gets invoked after the first update cycle after a level was loaded.
</summary>
<param name="level"></param>
</member>
<member name="M:IllusionPlugin.IPlugin.OnUpdate">
<summary>
Gets invoked on every graphic update.
</summary>
</member>
<member name="M:IllusionPlugin.IPlugin.OnFixedUpdate">
<summary>
Gets invoked on ever physics update.
</summary>
</member>
<member name="T:IllusionPlugin.ModPrefs">
<summary>
Allows to get and set preferences for your mod.
</summary>
</member>
<member name="M:IllusionPlugin.ModPrefs.GetString(System.String,System.String,System.String,System.Boolean)">
<summary>
Gets a string from the ini.
</summary>
<param name="section">Section of the key.</param>
<param name="name">Name of the key.</param>
<param name="defaultValue">Value that should be used when no value is found.</param>
<param name="autoSave">Whether or not the default value should be written if no value is found.</param>
<returns></returns>
</member>
<member name="M:IllusionPlugin.ModPrefs.GetInt(System.String,System.String,System.Int32,System.Boolean)">
<summary>
Gets an int from the ini.
</summary>
<param name="section">Section of the key.</param>
<param name="name">Name of the key.</param>
<param name="defaultValue">Value that should be used when no value is found.</param>
<param name="autoSave">Whether or not the default value should be written if no value is found.</param>
<returns></returns>
</member>
<member name="M:IllusionPlugin.ModPrefs.GetFloat(System.String,System.String,System.Single,System.Boolean)">
<summary>
Gets a float from the ini.
</summary>
<param name="section">Section of the key.</param>
<param name="name">Name of the key.</param>
<param name="defaultValue">Value that should be used when no value is found.</param>
<param name="autoSave">Whether or not the default value should be written if no value is found.</param>
<returns></returns>
</member>
<member name="M:IllusionPlugin.ModPrefs.GetBool(System.String,System.String,System.Boolean,System.Boolean)">
<summary>
Gets a bool from the ini.
</summary>
<param name="section">Section of the key.</param>
<param name="name">Name of the key.</param>
<param name="defaultValue">Value that should be used when no value is found.</param>
<param name="autoSave">Whether or not the default value should be written if no value is found.</param>
<returns></returns>
</member>
<member name="M:IllusionPlugin.ModPrefs.HasKey(System.String,System.String)">
<summary>
Checks whether or not a key exists in the ini.
</summary>
<param name="section">Section of the key.</param>
<param name="name">Name of the key.</param>
<returns></returns>
</member>
<member name="M:IllusionPlugin.ModPrefs.SetFloat(System.String,System.String,System.Single)">
<summary>
Sets a float in the ini.
</summary>
<param name="section">Section of the key.</param>
<param name="name">Name of the key.</param>
<param name="value">Value that should be written.</param>
</member>
<member name="M:IllusionPlugin.ModPrefs.SetInt(System.String,System.String,System.Int32)">
<summary>
Sets an int in the ini.
</summary>
<param name="section">Section of the key.</param>
<param name="name">Name of the key.</param>
<param name="value">Value that should be written.</param>
</member>
<member name="M:IllusionPlugin.ModPrefs.SetString(System.String,System.String,System.String)">
<summary>
Sets a string in the ini.
</summary>
<param name="section">Section of the key.</param>
<param name="name">Name of the key.</param>
<param name="value">Value that should be written.</param>
</member>
<member name="M:IllusionPlugin.ModPrefs.SetBool(System.String,System.String,System.Boolean)">
<summary>
Sets a bool in the ini.
</summary>
<param name="section">Section of the key.</param>
<param name="name">Name of the key.</param>
<param name="value">Value that should be written.</param>
</member>
</members>
</doc>

+ 55
- 0
IllusionPlugin/IllusionPlugin.csproj View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.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')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E2848BFB-5432-42F4-8AE0-D2EC0CDF2F71}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>IllusionPlugin</RootNamespace>
<AssemblyName>IllusionPlugin</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\IllusionPlugin.XML</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="IEnhancedPlugin.cs" />
<Compile Include="IniFile.cs" />
<Compile Include="IPlugin.cs" />
<Compile Include="ModPrefs.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 89
- 0
IllusionPlugin/IniFile.cs View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace IllusionPlugin
{
/// <summary>
/// Create a New INI file to store or load data
/// </summary>
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;
}
}

/// <summary>
/// INIFile Constructor.
/// </summary>
/// <PARAM name="INIPath"></PARAM>
public IniFile(string INIPath)
{
this.Path = INIPath;
}

/// <summary>
/// Write Data to the INI File
/// </summary>
/// <PARAM name="Section"></PARAM>
/// Section name
/// <PARAM name="Key"></PARAM>
/// Key Name
/// <PARAM name="Value"></PARAM>
/// Value Name
public void IniWriteValue(string Section, string Key, string Value)
{
WritePrivateProfileString(Section, Key, Value, this.Path);
}

/// <summary>
/// Read Data Value From the Ini File
/// </summary>
/// <PARAM name="Section"></PARAM>
/// <PARAM name="Key"></PARAM>
/// <PARAM name="Path"></PARAM>
/// <returns></returns>
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();
}
}
}

+ 166
- 0
IllusionPlugin/ModPrefs.cs View File

@@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace IllusionPlugin
{
/// <summary>
/// Allows to get and set preferences for your mod.
/// </summary>
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;
}
}


/// <summary>
/// Gets a string from the ini.
/// </summary>
/// <param name="section">Section of the key.</param>
/// <param name="name">Name of the key.</param>
/// <param name="defaultValue">Value that should be used when no value is found.</param>
/// <param name="autoSave">Whether or not the default value should be written if no value is found.</param>
/// <returns></returns>
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;
}

/// <summary>
/// Gets an int from the ini.
/// </summary>
/// <param name="section">Section of the key.</param>
/// <param name="name">Name of the key.</param>
/// <param name="defaultValue">Value that should be used when no value is found.</param>
/// <param name="autoSave">Whether or not the default value should be written if no value is found.</param>
/// <returns></returns>
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;
}


/// <summary>
/// Gets a float from the ini.
/// </summary>
/// <param name="section">Section of the key.</param>
/// <param name="name">Name of the key.</param>
/// <param name="defaultValue">Value that should be used when no value is found.</param>
/// <param name="autoSave">Whether or not the default value should be written if no value is found.</param>
/// <returns></returns>
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;
}

/// <summary>
/// Gets a bool from the ini.
/// </summary>
/// <param name="section">Section of the key.</param>
/// <param name="name">Name of the key.</param>
/// <param name="defaultValue">Value that should be used when no value is found.</param>
/// <param name="autoSave">Whether or not the default value should be written if no value is found.</param>
/// <returns></returns>
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;
}


/// <summary>
/// Checks whether or not a key exists in the ini.
/// </summary>
/// <param name="section">Section of the key.</param>
/// <param name="name">Name of the key.</param>
/// <returns></returns>
public static bool HasKey(string section, string name)
{
return Instance.IniReadValue(section, name) != null;
}

/// <summary>
/// Sets a float in the ini.
/// </summary>
/// <param name="section">Section of the key.</param>
/// <param name="name">Name of the key.</param>
/// <param name="value">Value that should be written.</param>
public static void SetFloat(string section, string name, float value)
{
Instance.IniWriteValue(section, name, value.ToString());
}

/// <summary>
/// Sets an int in the ini.
/// </summary>
/// <param name="section">Section of the key.</param>
/// <param name="name">Name of the key.</param>
/// <param name="value">Value that should be written.</param>
public static void SetInt(string section, string name, int value)
{
Instance.IniWriteValue(section, name, value.ToString());

}

/// <summary>
/// Sets a string in the ini.
/// </summary>
/// <param name="section">Section of the key.</param>
/// <param name="name">Name of the key.</param>
/// <param name="value">Value that should be written.</param>
public static void SetString(string section, string name, string value)
{
Instance.IniWriteValue(section, name, value);

}

/// <summary>
/// Sets a bool in the ini.
/// </summary>
/// <param name="section">Section of the key.</param>
/// <param name="name">Name of the key.</param>
/// <param name="value">Value that should be written.</param>
public static void SetBool(string section, string name, bool value)
{
Instance.IniWriteValue(section, name, value ? "1" : "0");

}
}
}

+ 36
- 0
IllusionPlugin/Properties/AssemblyInfo.cs View File

@@ -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")]

+ 104
- 0
Launcher/Launcher.csproj View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.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')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D1390268-F68B-4A55-B50D-EAD25756C8EF}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>QuietLauncher</RootNamespace>
<AssemblyName>Launcher</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</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\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net35\Mono.Cecil.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net35\Mono.Cecil.Mdb.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net35\Mono.Cecil.Pdb.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net35\Mono.Cecil.Rocks.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="Resources\DirectToRift.exe" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

+ 299
- 0
Launcher/Program.cs View File

@@ -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" };
/// <summary>
/// The main entry point for the application.
/// </summary>
[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);
}
}


/// <summary>
/// The forbidden deed of the gods -- make ALL methods virtual and public
/// </summary>
/// <param name="module"></param>
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);
}

}
}

+ 36
- 0
Launcher/Properties/AssemblyInfo.cs View File

@@ -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")]

+ 71
- 0
Launcher/Properties/Resources.Designer.cs View File

@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------

namespace QuietLauncher.Properties
{


/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// 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()
{
}

/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[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;
}
}

/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

+ 117
- 0
Launcher/Properties/Resources.resx View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

+ 30
- 0
Launcher/Properties/Settings.Designer.cs View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------

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;
}
}
}
}

+ 7
- 0
Launcher/Properties/Settings.settings View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

+ 73
- 0
Launcher/Resources.Designer.cs View File

@@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------

namespace QuietLauncher {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// 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() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[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;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static glob