@ -1,39 +1,39 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
namespace IPA.Tests | |||||
{ | |||||
public class ProgramTest | |||||
{ | |||||
[Theory] | |||||
// Unrelated path | |||||
[InlineData("test/from.dll", "test/to.dll", "native", false, new string[] { "test/to.dll" })] | |||||
// Flat -> Not-Flat | |||||
[InlineData("native/from.dll", "native/to.dll", "native", false, new string[] { "native/x86/to.dll", "native/x86_64/to.dll" })] | |||||
// Flat -> Flat | |||||
[InlineData("native/from.dll", "native/to.dll", "native", true, new string[] { "native/to.dll" })] | |||||
// Not-Flat -> Flat | |||||
[InlineData("native/x86/from.dll", "native/x86/to.dll", "native", true, new string[] { })] | |||||
[InlineData("native/x86_64/from.dll", "native/x86_64/to.dll", "native", true, new string[] { "native/to.dll" })] | |||||
// Not-flat -> Not-Flat | |||||
[InlineData("native/x86/from.dll", "native/x86/to.dll", "native", false, new string[] { "native/x86/to.dll" })] | |||||
[InlineData("native/x86_64/from.dll", "native/x86_64/to.dll", "native", false, new string[] { "native/x86_64/to.dll" })] | |||||
public void CopiesCorrectly(string from, string to, string nativeFolder, bool isFlat, string[] expected) | |||||
{ | |||||
var outcome = Program.NativePluginInterceptor(new FileInfo(from), new FileInfo(to), new DirectoryInfo(nativeFolder), isFlat, Program.Architecture.Unknown).Select(f => f.FullName).ToList(); | |||||
var expectedPaths = expected.Select(e => new FileInfo(e)).Select(f => f.FullName).ToList(); | |||||
Assert.Equal(expectedPaths, outcome); | |||||
} | |||||
} | |||||
} | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
namespace IPA.Tests | |||||
{ | |||||
public class ProgramTest | |||||
{ | |||||
[Theory] | |||||
// Unrelated path | |||||
[InlineData("test/from.dll", "test/to.dll", "native", false, new string[] { "test/to.dll" })] | |||||
// Flat -> Not-Flat | |||||
[InlineData("native/from.dll", "native/to.dll", "native", false, new string[] { "native/x86/to.dll", "native/x86_64/to.dll" })] | |||||
// Flat -> Flat | |||||
[InlineData("native/from.dll", "native/to.dll", "native", true, new string[] { "native/to.dll" })] | |||||
// Not-Flat -> Flat | |||||
[InlineData("native/x86/from.dll", "native/x86/to.dll", "native", true, new string[] { })] | |||||
[InlineData("native/x86_64/from.dll", "native/x86_64/to.dll", "native", true, new string[] { "native/to.dll" })] | |||||
// Not-flat -> Not-Flat | |||||
[InlineData("native/x86/from.dll", "native/x86/to.dll", "native", false, new string[] { "native/x86/to.dll" })] | |||||
[InlineData("native/x86_64/from.dll", "native/x86_64/to.dll", "native", false, new string[] { "native/x86_64/to.dll" })] | |||||
public void CopiesCorrectly(string from, string to, string nativeFolder, bool isFlat, string[] expected) | |||||
{ | |||||
var outcome = Program.NativePluginInterceptor(new FileInfo(from), new FileInfo(to), new DirectoryInfo(nativeFolder), isFlat, Program.Architecture.Unknown).Select(f => f.FullName).ToList(); | |||||
var expectedPaths = expected.Select(e => new FileInfo(e)).Select(f => f.FullName).ToList(); | |||||
Assert.Equal(expectedPaths, outcome); | |||||
} | |||||
} | |||||
} |
@ -1,45 +1,45 @@ | |||||
| |||||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||||
# Visual Studio 14 | |||||
VisualStudioVersion = 14.0.25420.1 | |||||
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}") = "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 | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA.Tests", "IPA.Tests\IPA.Tests.csproj", "{C66092B0-5C1E-44E9-B524-E0E8E1425379}" | |||||
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 | |||||
{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 | |||||
{C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
EndGlobal | |||||
| |||||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||||
# Visual Studio 14 | |||||
VisualStudioVersion = 14.0.25420.1 | |||||
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}") = "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 | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA.Tests", "IPA.Tests\IPA.Tests.csproj", "{C66092B0-5C1E-44E9-B524-E0E8E1425379}" | |||||
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 | |||||
{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 | |||||
{C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
EndGlobal |
@ -1,97 +1,97 @@ | |||||
<?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> | |||||
<PropertyGroup> | |||||
<ApplicationIcon>favicon.ico</ApplicationIcon> | |||||
</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.Windows.Forms" /> | |||||
<Reference Include="System.Xml.Linq" /> | |||||
<Reference Include="System.Data.DataSetExtensions" /> | |||||
<Reference Include="System.Data" /> | |||||
<Reference Include="System.Xml" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Compile Include="PatchContext.cs" /> | |||||
<Compile Include="Patcher\BackupManager.cs" /> | |||||
<Compile Include="Patcher\BackupUnit.cs" /> | |||||
<Compile Include="Patcher\Patcher.cs" /> | |||||
<Compile Include="Patcher\Virtualizer.cs" /> | |||||
<Compile Include="Program.cs" /> | |||||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||||
<Compile Include="Shortcut.cs" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="packages.config" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Content Include="favicon.ico" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Folder Include="IPA\Fallback\" /> | |||||
</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> | |||||
<Dlls Include="$(SolutionDir)IllusionInjector\$(OutDir)**\*" /> | |||||
</ItemGroup> | |||||
<Copy SourceFiles="@(Dlls)" DestinationFolder="$(OutputPath)IPA\Data\Managed" /> | |||||
</Target> | |||||
<?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> | |||||
<PropertyGroup> | |||||
<ApplicationIcon>favicon.ico</ApplicationIcon> | |||||
</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.Windows.Forms" /> | |||||
<Reference Include="System.Xml.Linq" /> | |||||
<Reference Include="System.Data.DataSetExtensions" /> | |||||
<Reference Include="System.Data" /> | |||||
<Reference Include="System.Xml" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Compile Include="PatchContext.cs" /> | |||||
<Compile Include="Patcher\BackupManager.cs" /> | |||||
<Compile Include="Patcher\BackupUnit.cs" /> | |||||
<Compile Include="Patcher\Patcher.cs" /> | |||||
<Compile Include="Patcher\Virtualizer.cs" /> | |||||
<Compile Include="Program.cs" /> | |||||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||||
<Compile Include="Shortcut.cs" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="packages.config" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Content Include="favicon.ico" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Folder Include="IPA\Fallback\" /> | |||||
</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> | |||||
<Dlls Include="$(SolutionDir)IllusionInjector\$(OutDir)**\*" /> | |||||
</ItemGroup> | |||||
<Copy SourceFiles="@(Dlls)" DestinationFolder="$(OutputPath)IPA\Data\Managed" /> | |||||
</Target> | |||||
</Project> | </Project> |
@ -1,58 +1,58 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Text; | |||||
namespace IPA | |||||
{ | |||||
public class PatchContext | |||||
{ | |||||
/// <summary> | |||||
/// Gets the filename of the executable. | |||||
/// </summary> | |||||
public string Executable { get; private set; } | |||||
public string DataPathSrc { get; private set; } | |||||
public string PluginsFolder { get; private set; } | |||||
public string ProjectName { get; private set; } | |||||
public string DataPathDst { get; private set; } | |||||
public string ManagedPath { get; private set; } | |||||
public string EngineFile { get; private set; } | |||||
public string AssemblyFile { get; private set; } | |||||
public string[] Args { get; private set; } | |||||
public string ProjectRoot { get; private set; } | |||||
public string IPARoot { get; private set; } | |||||
public string ShortcutPath { get; private set; } | |||||
public string IPA { get; private set; } | |||||
public string BackupPath { get; private set; } | |||||
private PatchContext() { } | |||||
public static PatchContext Create(String[] args) | |||||
{ | |||||
var context = new PatchContext(); | |||||
context.Args = args; | |||||
context.Executable = args[0]; | |||||
context.ProjectRoot = new FileInfo(context.Executable).Directory.FullName; | |||||
context.IPARoot = Path.Combine(context.ProjectRoot, "IPA"); | |||||
context.IPA = Assembly.GetExecutingAssembly().Location ?? Path.Combine(context.ProjectRoot, "IPA.exe"); | |||||
context.DataPathSrc = Path.Combine(context.IPARoot, "Data"); | |||||
context.PluginsFolder = Path.Combine(context.ProjectRoot, "Plugins"); | |||||
context.ProjectName = Path.GetFileNameWithoutExtension(context.Executable); | |||||
context.DataPathDst = Path.Combine(context.ProjectRoot, context.ProjectName + "_Data"); | |||||
context.ManagedPath = Path.Combine(context.DataPathDst, "Managed"); | |||||
context.EngineFile = Path.Combine(context.ManagedPath, "UnityEngine.CoreModule.dll"); | |||||
context.AssemblyFile = Path.Combine(context.ManagedPath, "Assembly-CSharp.dll"); | |||||
context.BackupPath = Path.Combine(Path.Combine(context.IPARoot, "Backups"), context.ProjectName); | |||||
string shortcutName = $"{context.ProjectName} (Patch & Launch)"; | |||||
context.ShortcutPath = Path.Combine(context.ProjectRoot, shortcutName) + ".lnk"; | |||||
Directory.CreateDirectory(context.BackupPath); | |||||
return context; | |||||
} | |||||
} | |||||
} | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Text; | |||||
namespace IPA | |||||
{ | |||||
public class PatchContext | |||||
{ | |||||
/// <summary> | |||||
/// Gets the filename of the executable. | |||||
/// </summary> | |||||
public string Executable { get; private set; } | |||||
public string DataPathSrc { get; private set; } | |||||
public string PluginsFolder { get; private set; } | |||||
public string ProjectName { get; private set; } | |||||
public string DataPathDst { get; private set; } | |||||
public string ManagedPath { get; private set; } | |||||
public string EngineFile { get; private set; } | |||||
public string AssemblyFile { get; private set; } | |||||
public string[] Args { get; private set; } | |||||
public string ProjectRoot { get; private set; } | |||||
public string IPARoot { get; private set; } | |||||
public string ShortcutPath { get; private set; } | |||||
public string IPA { get; private set; } | |||||
public string BackupPath { get; private set; } | |||||
private PatchContext() { } | |||||
public static PatchContext Create(String[] args) | |||||
{ | |||||
var context = new PatchContext(); | |||||
context.Args = args; | |||||
context.Executable = args[0]; | |||||
context.ProjectRoot = new FileInfo(context.Executable).Directory.FullName; | |||||
context.IPARoot = Path.Combine(context.ProjectRoot, "IPA"); | |||||
context.IPA = Assembly.GetExecutingAssembly().Location ?? Path.Combine(context.ProjectRoot, "IPA.exe"); | |||||
context.DataPathSrc = Path.Combine(context.IPARoot, "Data"); | |||||
context.PluginsFolder = Path.Combine(context.ProjectRoot, "Plugins"); | |||||
context.ProjectName = Path.GetFileNameWithoutExtension(context.Executable); | |||||
context.DataPathDst = Path.Combine(context.ProjectRoot, context.ProjectName + "_Data"); | |||||
context.ManagedPath = Path.Combine(context.DataPathDst, "Managed"); | |||||
context.EngineFile = Path.Combine(context.ManagedPath, "UnityEngine.CoreModule.dll"); | |||||
context.AssemblyFile = Path.Combine(context.ManagedPath, "Assembly-CSharp.dll"); | |||||
context.BackupPath = Path.Combine(Path.Combine(context.IPARoot, "Backups"), context.ProjectName); | |||||
string shortcutName = $"{context.ProjectName} (Patch & Launch)"; | |||||
context.ShortcutPath = Path.Combine(context.ProjectRoot, shortcutName) + ".lnk"; | |||||
Directory.CreateDirectory(context.BackupPath); | |||||
return context; | |||||
} | |||||
} | |||||
} |
@ -1,103 +1,103 @@ | |||||
using Mono.Cecil; | |||||
using Mono.Cecil.Cil; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Text; | |||||
namespace IPA.Patcher | |||||
{ | |||||
class PatchedModule | |||||
{ | |||||
private static readonly string[] ENTRY_TYPES = { "Input", "Display" }; | |||||
private FileInfo _File; | |||||
private ModuleDefinition _Module; | |||||
internal struct PatchData { | |||||
public bool IsPatched; | |||||
public Version Version; | |||||
} | |||||
public static PatchedModule Load(string engineFile) | |||||
{ | |||||
return new PatchedModule(engineFile); | |||||
} | |||||
private PatchedModule(string engineFile) | |||||
{ | |||||
_File = new FileInfo(engineFile); | |||||
LoadModules(); | |||||
} | |||||
private void LoadModules() | |||||
{ | |||||
var resolver = new DefaultAssemblyResolver(); | |||||
resolver.AddSearchDirectory(_File.DirectoryName); | |||||
var parameters = new ReaderParameters | |||||
{ | |||||
AssemblyResolver = resolver, | |||||
}; | |||||
_Module = ModuleDefinition.ReadModule(_File.FullName, parameters); | |||||
} | |||||
public PatchData Data | |||||
{ | |||||
get | |||||
{ | |||||
foreach (var @ref in _Module.AssemblyReferences) { | |||||
if (@ref.Name == "IllusionInjector") return new PatchData { IsPatched = true, Version = @ref.Version}; | |||||
} | |||||
return new PatchData { IsPatched = false, Version = null}; | |||||
} | |||||
} | |||||
public void Patch(Version v) | |||||
{ | |||||
// First, let's add the reference | |||||
var nameReference = new AssemblyNameReference("IllusionInjector", v); | |||||
var injectorPath = Path.Combine(_File.DirectoryName, "IllusionInjector.dll"); | |||||
var injector = ModuleDefinition.ReadModule(injectorPath); | |||||
_Module.AssemblyReferences.Add(nameReference); | |||||
int patched = 0; | |||||
foreach(var type in FindEntryTypes()) | |||||
{ | |||||
if(PatchType(type, injector)) | |||||
{ | |||||
patched++; | |||||
} | |||||
} | |||||
if(patched > 0) | |||||
{ | |||||
_Module.Write(_File.FullName); | |||||
} else | |||||
{ | |||||
throw new Exception("Could not find any entry type!"); | |||||
} | |||||
} | |||||
private bool PatchType(TypeDefinition targetType, ModuleDefinition injector) | |||||
{ | |||||
var targetMethod = targetType.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic); | |||||
if (targetMethod != null) | |||||
{ | |||||
var methodReference = _Module.Import(injector.GetType("IllusionInjector.Injector").Methods.First(m => m.Name == "Inject")); | |||||
targetMethod.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, methodReference)); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
private IEnumerable<TypeDefinition> FindEntryTypes() | |||||
{ | |||||
return _Module.GetTypes().Where(m => ENTRY_TYPES.Contains(m.Name)); | |||||
} | |||||
} | |||||
} | |||||
using Mono.Cecil; | |||||
using Mono.Cecil.Cil; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Text; | |||||
namespace IPA.Patcher | |||||
{ | |||||
class PatchedModule | |||||
{ | |||||
private static readonly string[] ENTRY_TYPES = { "Input", "Display" }; | |||||
private FileInfo _File; | |||||
private ModuleDefinition _Module; | |||||
internal struct PatchData { | |||||
public bool IsPatched; | |||||
public Version Version; | |||||
} | |||||
public static PatchedModule Load(string engineFile) | |||||
{ | |||||
return new PatchedModule(engineFile); | |||||
} | |||||
private PatchedModule(string engineFile) | |||||
{ | |||||
_File = new FileInfo(engineFile); | |||||
LoadModules(); | |||||
} | |||||
private void LoadModules() | |||||
{ | |||||
var resolver = new DefaultAssemblyResolver(); | |||||
resolver.AddSearchDirectory(_File.DirectoryName); | |||||
var parameters = new ReaderParameters | |||||
{ | |||||
AssemblyResolver = resolver, | |||||
}; | |||||
_Module = ModuleDefinition.ReadModule(_File.FullName, parameters); | |||||
} | |||||
public PatchData Data | |||||
{ | |||||
get | |||||
{ | |||||
foreach (var @ref in _Module.AssemblyReferences) { | |||||
if (@ref.Name == "IllusionInjector") return new PatchData { IsPatched = true, Version = @ref.Version}; | |||||
} | |||||
return new PatchData { IsPatched = false, Version = null}; | |||||
} | |||||
} | |||||
public void Patch(Version v) | |||||
{ | |||||
// First, let's add the reference | |||||
var nameReference = new AssemblyNameReference("IllusionInjector", v); | |||||
var injectorPath = Path.Combine(_File.DirectoryName, "IllusionInjector.dll"); | |||||
var injector = ModuleDefinition.ReadModule(injectorPath); | |||||
_Module.AssemblyReferences.Add(nameReference); | |||||
int patched = 0; | |||||
foreach(var type in FindEntryTypes()) | |||||
{ | |||||
if(PatchType(type, injector)) | |||||
{ | |||||
patched++; | |||||
} | |||||
} | |||||
if(patched > 0) | |||||
{ | |||||
_Module.Write(_File.FullName); | |||||
} else | |||||
{ | |||||
throw new Exception("Could not find any entry type!"); | |||||
} | |||||
} | |||||
private bool PatchType(TypeDefinition targetType, ModuleDefinition injector) | |||||
{ | |||||
var targetMethod = targetType.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic); | |||||
if (targetMethod != null) | |||||
{ | |||||
var methodReference = _Module.Import(injector.GetType("IllusionInjector.Injector").Methods.First(m => m.Name == "Inject")); | |||||
targetMethod.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, methodReference)); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
private IEnumerable<TypeDefinition> FindEntryTypes() | |||||
{ | |||||
return _Module.GetTypes().Where(m => ENTRY_TYPES.Contains(m.Name)); | |||||
} | |||||
} | |||||
} |
@ -1,388 +1,388 @@ | |||||
using IPA.Patcher; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Runtime.InteropServices; | |||||
using System.Text; | |||||
using System.Text.RegularExpressions; | |||||
using System.Windows.Forms; | |||||
namespace IPA { | |||||
public class Program { | |||||
public enum Architecture { | |||||
x86, | |||||
x64, | |||||
Unknown | |||||
} | |||||
private static Version Version => new Version(Application.ProductVersion); | |||||
static void Main(string[] args) { | |||||
PatchContext context; | |||||
if (args.Length < 1 || !args[0].EndsWith(".exe")) { | |||||
//Fail("Drag an (executable) file on the exe!"); | |||||
context = PatchContext.Create(new[] { | |||||
new DirectoryInfo(Directory.GetCurrentDirectory()).GetFiles() | |||||
.First(o => o.FullName.EndsWith(".exe")) | |||||
.FullName | |||||
}); | |||||
} | |||||
else { | |||||
context = PatchContext.Create(args); | |||||
} | |||||
try { | |||||
bool isRevert = args.Contains("--revert") || Keyboard.IsKeyDown(Keys.LMenu); | |||||
// Sanitizing | |||||
Validate(context); | |||||
if (isRevert) { | |||||
Revert(context); | |||||
} | |||||
else { | |||||
Install(context); | |||||
StartIfNeedBe(context); | |||||
} | |||||
} | |||||
catch (Exception e) { | |||||
Fail(e.Message); | |||||
} | |||||
} | |||||
private static void Validate(PatchContext c) { | |||||
if (!Directory.Exists(c.DataPathDst) || !File.Exists(c.EngineFile)) { | |||||
Fail("Game does not seem to be a Unity project. Could not find the libraries to patch."); | |||||
Console.WriteLine($"DataPath: {c.DataPathDst}"); | |||||
Console.WriteLine($"EngineFile: {c.EngineFile}"); | |||||
} | |||||
} | |||||
private static void Install(PatchContext context) { | |||||
try { | |||||
var backup = new BackupUnit(context); | |||||
#region Patch Version Check | |||||
var patchedModule = PatchedModule.Load(context.EngineFile); | |||||
var isCurrentNewer = Version.CompareTo(patchedModule.Data.Version) > 0; | |||||
if (isCurrentNewer) { | |||||
Console.ForegroundColor = ConsoleColor.White; | |||||
Console.WriteLine( | |||||
$"Preparing for update, {(patchedModule.Data.Version == null ? "UnPatched" : patchedModule.Data.Version.ToString())} => {Version}"); | |||||
Console.WriteLine("--- Starting ---"); | |||||
Revert(context, new[] {"newVersion"}); | |||||
Console.ResetColor(); | |||||
#region File Copying | |||||
Console.ForegroundColor = ConsoleColor.Magenta; | |||||
Console.WriteLine("Updating files... "); | |||||
var nativePluginFolder = Path.Combine(context.DataPathDst, "Plugins"); | |||||
bool isFlat = Directory.Exists(nativePluginFolder) && | |||||
Directory.GetFiles(nativePluginFolder).Any(f => f.EndsWith(".dll")); | |||||
bool force = !BackupManager.HasBackup(context) || context.Args.Contains("-f") || | |||||
context.Args.Contains("--force"); | |||||
var architecture = DetectArchitecture(context.Executable); | |||||
Console.WriteLine("Architecture: {0}", architecture); | |||||
CopyAll(new DirectoryInfo(context.DataPathSrc), new DirectoryInfo(context.DataPathDst), force, | |||||
backup, | |||||
(from, to) => NativePluginInterceptor(from, to, new DirectoryInfo(nativePluginFolder), isFlat, | |||||
architecture)); | |||||
Console.WriteLine("Successfully updated files!"); | |||||
#endregion | |||||
} | |||||
else { | |||||
Console.ForegroundColor = ConsoleColor.Red; | |||||
Console.WriteLine($"Files up to date @ Version {Version}!"); | |||||
Console.ResetColor(); | |||||
} | |||||
#endregion | |||||
#region Create Plugin Folder | |||||
if (!Directory.Exists(context.PluginsFolder)) { | |||||
Console.ForegroundColor = ConsoleColor.DarkYellow; | |||||
Console.WriteLine("Creating plugins folder... "); | |||||
Directory.CreateDirectory(context.PluginsFolder); | |||||
Console.ResetColor(); | |||||
} | |||||
#endregion | |||||
#region Patching | |||||
if (!patchedModule.Data.IsPatched || isCurrentNewer) { | |||||
Console.ForegroundColor = ConsoleColor.Yellow; | |||||
Console.WriteLine($"Patching UnityEngine.dll with Version {Application.ProductVersion}... "); | |||||
backup.Add(context.EngineFile); | |||||
patchedModule.Patch(Version); | |||||
Console.WriteLine("Done!"); | |||||
Console.ResetColor(); | |||||
} | |||||
#endregion | |||||
#region Virtualizing | |||||
if (File.Exists(context.AssemblyFile)) { | |||||
var virtualizedModule = VirtualizedModule.Load(context.AssemblyFile); | |||||
if (!virtualizedModule.IsVirtualized) { | |||||
Console.ForegroundColor = ConsoleColor.Blue; | |||||
Console.WriteLine("Virtualizing Assembly-Csharp.dll... "); | |||||
backup.Add(context.AssemblyFile); | |||||
virtualizedModule.Virtualize(); | |||||
Console.WriteLine("Done!"); | |||||
Console.ResetColor(); | |||||
} | |||||
} | |||||
#endregion | |||||
#region Creating shortcut | |||||
/*if(!File.Exists(context.ShortcutPath)) | |||||
{ | |||||
Console.Write("Creating shortcut to IPA ({0})... ", context.IPA); | |||||
try | |||||
{ | |||||
Shortcut.Create( | |||||
fileName: context.ShortcutPath, | |||||
targetPath: context.IPA, | |||||
arguments: Args(context.Executable, "--launch"), | |||||
workingDirectory: context.ProjectRoot, | |||||
description: "Launches the game and makes sure it's in a patched state", | |||||
hotkey: "", | |||||
iconPath: context.Executable | |||||
); | |||||
Console.WriteLine("Created"); | |||||
} catch (Exception e) | |||||
{ | |||||
Console.Error.WriteLine("Failed to create shortcut, but game was patched!"); | |||||
} | |||||
}*/ | |||||
#endregion | |||||
} | |||||
catch (Exception e) { | |||||
Fail("Oops! This should not have happened.\n\n" + e); | |||||
} | |||||
Console.ForegroundColor = ConsoleColor.Green; | |||||
Console.WriteLine("Finished!"); | |||||
Console.ResetColor(); | |||||
Console.ReadLine(); | |||||
} | |||||
private static void Revert(PatchContext context, string[] args = null) { | |||||
Console.ForegroundColor = ConsoleColor.Cyan; | |||||
bool isNewVersion = (args != null && args.Contains("newVersion")); | |||||
Console.Write("Restoring backup... "); | |||||
if (BackupManager.Restore(context)) { | |||||
Console.WriteLine("Done!"); | |||||
} | |||||
else { | |||||
Console.WriteLine("Already vanilla!"); | |||||
} | |||||
if (File.Exists(context.ShortcutPath)) { | |||||
Console.WriteLine("Deleting shortcut..."); | |||||
File.Delete(context.ShortcutPath); | |||||
} | |||||
Console.WriteLine(""); | |||||
Console.WriteLine("--- Done reverting ---"); | |||||
if (!Environment.CommandLine.Contains("--nowait") && !isNewVersion) { | |||||
Console.WriteLine("\n\n[Press any key to quit]"); | |||||
Console.ReadKey(); | |||||
} | |||||
Console.ResetColor(); | |||||
} | |||||
private static void StartIfNeedBe(PatchContext context) { | |||||
var argList = context.Args.ToList(); | |||||
bool launch = argList.Remove("--launch"); | |||||
argList.RemoveAt(0); | |||||
if (launch) { | |||||
Process.Start(context.Executable, Args(argList.ToArray())); | |||||
} | |||||
} | |||||
public static IEnumerable<FileInfo> NativePluginInterceptor(FileInfo from, FileInfo to, | |||||
DirectoryInfo nativePluginFolder, bool isFlat, Architecture preferredArchitecture) { | |||||
if (to.FullName.StartsWith(nativePluginFolder.FullName)) { | |||||
var relevantBit = to.FullName.Substring(nativePluginFolder.FullName.Length + 1); | |||||
// Goes into the plugin folder! | |||||
bool isFileFlat = !relevantBit.StartsWith("x86"); | |||||
if (isFlat && !isFileFlat) { | |||||
// Flatten structure | |||||
bool is64Bit = relevantBit.StartsWith("x86_64"); | |||||
if (!is64Bit && preferredArchitecture == Architecture.x86) { | |||||
// 32 bit | |||||
yield return new FileInfo(Path.Combine(nativePluginFolder.FullName, | |||||
relevantBit.Substring("x86".Length + 1))); | |||||
} | |||||
else if (is64Bit && (preferredArchitecture == Architecture.x64 || | |||||
preferredArchitecture == Architecture.Unknown)) { | |||||
// 64 bit | |||||
yield return new FileInfo(Path.Combine(nativePluginFolder.FullName, | |||||
relevantBit.Substring("x86_64".Length + 1))); | |||||
} | |||||
else { | |||||
// Throw away | |||||
yield break; | |||||
} | |||||
} | |||||
else if (!isFlat && isFileFlat) { | |||||
// Deepen structure | |||||
yield return new FileInfo(Path.Combine(Path.Combine(nativePluginFolder.FullName, "x86"), | |||||
relevantBit)); | |||||
yield return new FileInfo(Path.Combine(Path.Combine(nativePluginFolder.FullName, "x86_64"), | |||||
relevantBit)); | |||||
} | |||||
else { | |||||
yield return to; | |||||
} | |||||
} | |||||
else { | |||||
yield return to; | |||||
} | |||||
} | |||||
private static IEnumerable<FileInfo> PassThroughInterceptor(FileInfo from, FileInfo to) { | |||||
yield return to; | |||||
} | |||||
public static void CopyAll(DirectoryInfo source, DirectoryInfo target, bool aggressive, BackupUnit backup, | |||||
Func<FileInfo, FileInfo, IEnumerable<FileInfo>> interceptor = null) { | |||||
if (interceptor == null) { | |||||
interceptor = PassThroughInterceptor; | |||||
} | |||||
// Copy each file into the new directory. | |||||
foreach (FileInfo fi in source.GetFiles()) { | |||||
foreach (var targetFile in interceptor(fi, new FileInfo(Path.Combine(target.FullName, fi.Name)))) { | |||||
if (!targetFile.Exists || targetFile.LastWriteTimeUtc < fi.LastWriteTimeUtc || aggressive) { | |||||
targetFile.Directory.Create(); | |||||
Console.WriteLine(@"Copying {0}", targetFile.FullName); | |||||
backup.Add(targetFile); | |||||
fi.CopyTo(targetFile.FullName, true); | |||||
} | |||||
} | |||||
} | |||||
// Copy each subdirectory using recursion. | |||||
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) { | |||||
DirectoryInfo nextTargetSubDir = new DirectoryInfo(Path.Combine(target.FullName, diSourceSubDir.Name)); | |||||
CopyAll(diSourceSubDir, nextTargetSubDir, aggressive, backup, interceptor); | |||||
} | |||||
} | |||||
static void Fail(string message) { | |||||
Console.Error.Write("ERROR: " + message); | |||||
if (!Environment.CommandLine.Contains("--nowait")) { | |||||
Console.WriteLine("\n\n[Press any key to quit]"); | |||||
Console.ReadKey(); | |||||
} | |||||
Environment.Exit(1); | |||||
} | |||||
public static string Args(params string[] args) { | |||||
return string.Join(" ", args.Select(EncodeParameterArgument).ToArray()); | |||||
} | |||||
/// <summary> | |||||
/// Encodes an argument for passing into a program | |||||
/// </summary> | |||||
/// <param name="original">The value that should be received by the program</param> | |||||
/// <returns>The value which needs to be passed to the program for the original value | |||||
/// to come through</returns> | |||||
public static string EncodeParameterArgument(string original) { | |||||
if (string.IsNullOrEmpty(original)) | |||||
return original; | |||||
string value = Regex.Replace(original, @"(\\*)" + "\"", @"$1\$0"); | |||||
value = Regex.Replace(value, @"^(.*\s.*?)(\\*)$", "\"$1$2$2\""); | |||||
return value; | |||||
} | |||||
public static Architecture DetectArchitecture(string assembly) { | |||||
using (var reader = new BinaryReader(File.OpenRead(assembly))) { | |||||
var header = reader.ReadUInt16(); | |||||
if (header == 0x5a4d) { | |||||
reader.BaseStream.Seek(60, SeekOrigin.Begin); // this location contains the offset for the PE header | |||||
var peOffset = reader.ReadUInt32(); | |||||
reader.BaseStream.Seek(peOffset + 4, SeekOrigin.Begin); | |||||
var machine = reader.ReadUInt16(); | |||||
if (machine == 0x8664) // IMAGE_FILE_MACHINE_AMD64 | |||||
return Architecture.x64; | |||||
else if (machine == 0x014c) // IMAGE_FILE_MACHINE_I386 | |||||
return Architecture.x86; | |||||
else if (machine == 0x0200) // IMAGE_FILE_MACHINE_IA64 | |||||
return Architecture.x64; | |||||
else | |||||
return Architecture.Unknown; | |||||
} | |||||
else { | |||||
// Not a supported binary | |||||
return Architecture.Unknown; | |||||
} | |||||
} | |||||
} | |||||
public abstract class Keyboard { | |||||
[Flags] | |||||
private enum KeyStates { | |||||
None = 0, | |||||
Down = 1, | |||||
Toggled = 2 | |||||
} | |||||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] | |||||
private static extern short GetKeyState(int keyCode); | |||||
private static KeyStates GetKeyState(Keys key) { | |||||
KeyStates state = KeyStates.None; | |||||
short retVal = GetKeyState((int) key); | |||||
//If the high-order bit is 1, the key is down | |||||
//otherwise, it is up. | |||||
if ((retVal & 0x8000) == 0x8000) | |||||
state |= KeyStates.Down; | |||||
//If the low-order bit is 1, the key is toggled. | |||||
if ((retVal & 1) == 1) | |||||
state |= KeyStates.Toggled; | |||||
return state; | |||||
} | |||||
public static bool IsKeyDown(Keys key) { | |||||
return KeyStates.Down == (GetKeyState(key) & KeyStates.Down); | |||||
} | |||||
public static bool IsKeyToggled(Keys key) { | |||||
return KeyStates.Toggled == (GetKeyState(key) & KeyStates.Toggled); | |||||
} | |||||
} | |||||
} | |||||
using IPA.Patcher; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Runtime.InteropServices; | |||||
using System.Text; | |||||
using System.Text.RegularExpressions; | |||||
using System.Windows.Forms; | |||||
namespace IPA { | |||||
public class Program { | |||||
public enum Architecture { | |||||
x86, | |||||
x64, | |||||
Unknown | |||||
} | |||||
private static Version Version => new Version(Application.ProductVersion); | |||||
static void Main(string[] args) { | |||||
PatchContext context; | |||||
if (args.Length < 1 || !args[0].EndsWith(".exe")) { | |||||
//Fail("Drag an (executable) file on the exe!"); | |||||
context = PatchContext.Create(new[] { | |||||
new DirectoryInfo(Directory.GetCurrentDirectory()).GetFiles() | |||||
.First(o => o.FullName.EndsWith(".exe")) | |||||
.FullName | |||||
}); | |||||
} | |||||
else { | |||||
context = PatchContext.Create(args); | |||||
} | |||||
try { | |||||
bool isRevert = args.Contains("--revert") || Keyboard.IsKeyDown(Keys.LMenu); | |||||
// Sanitizing | |||||
Validate(context); | |||||
if (isRevert) { | |||||
Revert(context); | |||||
} | |||||
else { | |||||
Install(context); | |||||
StartIfNeedBe(context); | |||||
} | |||||
} | |||||
catch (Exception e) { | |||||
Fail(e.Message); | |||||
} | |||||
} | |||||
private static void Validate(PatchContext c) { | |||||
if (!Directory.Exists(c.DataPathDst) || !File.Exists(c.EngineFile)) { | |||||
Fail("Game does not seem to be a Unity project. Could not find the libraries to patch."); | |||||
Console.WriteLine($"DataPath: {c.DataPathDst}"); | |||||
Console.WriteLine($"EngineFile: {c.EngineFile}"); | |||||
} | |||||
} | |||||
private static void Install(PatchContext context) { | |||||
try { | |||||
var backup = new BackupUnit(context); | |||||
#region Patch Version Check | |||||
var patchedModule = PatchedModule.Load(context.EngineFile); | |||||
var isCurrentNewer = Version.CompareTo(patchedModule.Data.Version) > 0; | |||||
if (isCurrentNewer) { | |||||
Console.ForegroundColor = ConsoleColor.White; | |||||
Console.WriteLine( | |||||
$"Preparing for update, {(patchedModule.Data.Version == null ? "UnPatched" : patchedModule.Data.Version.ToString())} => {Version}"); | |||||
Console.WriteLine("--- Starting ---"); | |||||
Revert(context, new[] {"newVersion"}); | |||||
Console.ResetColor(); | |||||
#region File Copying | |||||
Console.ForegroundColor = ConsoleColor.Magenta; | |||||
Console.WriteLine("Updating files... "); | |||||
var nativePluginFolder = Path.Combine(context.DataPathDst, "Plugins"); | |||||
bool isFlat = Directory.Exists(nativePluginFolder) && | |||||
Directory.GetFiles(nativePluginFolder).Any(f => f.EndsWith(".dll")); | |||||
bool force = !BackupManager.HasBackup(context) || context.Args.Contains("-f") || | |||||
context.Args.Contains("--force"); | |||||
var architecture = DetectArchitecture(context.Executable); | |||||
Console.WriteLine("Architecture: {0}", architecture); | |||||
CopyAll(new DirectoryInfo(context.DataPathSrc), new DirectoryInfo(context.DataPathDst), force, | |||||
backup, | |||||
(from, to) => NativePluginInterceptor(from, to, new DirectoryInfo(nativePluginFolder), isFlat, | |||||
architecture)); | |||||
Console.WriteLine("Successfully updated files!"); | |||||
#endregion | |||||
} | |||||
else { | |||||
Console.ForegroundColor = ConsoleColor.Red; | |||||
Console.WriteLine($"Files up to date @ Version {Version}!"); | |||||
Console.ResetColor(); | |||||
} | |||||
#endregion | |||||
#region Create Plugin Folder | |||||
if (!Directory.Exists(context.PluginsFolder)) { | |||||
Console.ForegroundColor = ConsoleColor.DarkYellow; | |||||
Console.WriteLine("Creating plugins folder... "); | |||||
Directory.CreateDirectory(context.PluginsFolder); | |||||
Console.ResetColor(); | |||||
} | |||||
#endregion | |||||
#region Patching | |||||
if (!patchedModule.Data.IsPatched || isCurrentNewer) { | |||||
Console.ForegroundColor = ConsoleColor.Yellow; | |||||
Console.WriteLine($"Patching UnityEngine.dll with Version {Application.ProductVersion}... "); | |||||
backup.Add(context.EngineFile); | |||||
patchedModule.Patch(Version); | |||||
Console.WriteLine("Done!"); | |||||
Console.ResetColor(); | |||||
} | |||||
#endregion | |||||
#region Virtualizing | |||||
if (File.Exists(context.AssemblyFile)) { | |||||
var virtualizedModule = VirtualizedModule.Load(context.AssemblyFile); | |||||
if (!virtualizedModule.IsVirtualized) { | |||||
Console.ForegroundColor = ConsoleColor.Blue; | |||||
Console.WriteLine("Virtualizing Assembly-Csharp.dll... "); | |||||
backup.Add(context.AssemblyFile); | |||||
virtualizedModule.Virtualize(); | |||||
Console.WriteLine("Done!"); | |||||
Console.ResetColor(); | |||||
} | |||||
} | |||||
#endregion | |||||
#region Creating shortcut | |||||
/*if(!File.Exists(context.ShortcutPath)) | |||||
{ | |||||
Console.Write("Creating shortcut to IPA ({0})... ", context.IPA); | |||||
try | |||||
{ | |||||
Shortcut.Create( | |||||
fileName: context.ShortcutPath, | |||||
targetPath: context.IPA, | |||||
arguments: Args(context.Executable, "--launch"), | |||||
workingDirectory: context.ProjectRoot, | |||||
description: "Launches the game and makes sure it's in a patched state", | |||||
hotkey: "", | |||||
iconPath: context.Executable | |||||
); | |||||
Console.WriteLine("Created"); | |||||
} catch (Exception e) | |||||
{ | |||||
Console.Error.WriteLine("Failed to create shortcut, but game was patched!"); | |||||
} | |||||
}*/ | |||||
#endregion | |||||
} | |||||
catch (Exception e) { | |||||
Fail("Oops! This should not have happened.\n\n" + e); | |||||
} | |||||
Console.ForegroundColor = ConsoleColor.Green; | |||||
Console.WriteLine("Finished!"); | |||||
Console.ResetColor(); | |||||
Console.ReadLine(); | |||||
} | |||||
private static void Revert(PatchContext context, string[] args = null) { | |||||
Console.ForegroundColor = ConsoleColor.Cyan; | |||||
bool isNewVersion = (args != null && args.Contains("newVersion")); | |||||
Console.Write("Restoring backup... "); | |||||
if (BackupManager.Restore(context)) { | |||||
Console.WriteLine("Done!"); | |||||
} | |||||
else { | |||||
Console.WriteLine("Already vanilla!"); | |||||
} | |||||
if (File.Exists(context.ShortcutPath)) { | |||||
Console.WriteLine("Deleting shortcut..."); | |||||
File.Delete(context.ShortcutPath); | |||||
} | |||||
Console.WriteLine(""); | |||||
Console.WriteLine("--- Done reverting ---"); | |||||
if (!Environment.CommandLine.Contains("--nowait") && !isNewVersion) { | |||||
Console.WriteLine("\n\n[Press any key to quit]"); | |||||
Console.ReadKey(); | |||||
} | |||||
Console.ResetColor(); | |||||
} | |||||
private static void StartIfNeedBe(PatchContext context) { | |||||
var argList = context.Args.ToList(); | |||||
bool launch = argList.Remove("--launch"); | |||||
argList.RemoveAt(0); | |||||
if (launch) { | |||||
Process.Start(context.Executable, Args(argList.ToArray())); | |||||
} | |||||
} | |||||
public static IEnumerable<FileInfo> NativePluginInterceptor(FileInfo from, FileInfo to, | |||||
DirectoryInfo nativePluginFolder, bool isFlat, Architecture preferredArchitecture) { | |||||
if (to.FullName.StartsWith(nativePluginFolder.FullName)) { | |||||
var relevantBit = to.FullName.Substring(nativePluginFolder.FullName.Length + 1); | |||||
// Goes into the plugin folder! | |||||
bool isFileFlat = !relevantBit.StartsWith("x86"); | |||||
if (isFlat && !isFileFlat) { | |||||
// Flatten structure | |||||
bool is64Bit = relevantBit.StartsWith("x86_64"); | |||||
if (!is64Bit && preferredArchitecture == Architecture.x86) { | |||||
// 32 bit | |||||
yield return new FileInfo(Path.Combine(nativePluginFolder.FullName, | |||||
relevantBit.Substring("x86".Length + 1))); | |||||
} | |||||
else if (is64Bit && (preferredArchitecture == Architecture.x64 || | |||||
preferredArchitecture == Architecture.Unknown)) { | |||||
// 64 bit | |||||
yield return new FileInfo(Path.Combine(nativePluginFolder.FullName, | |||||
relevantBit.Substring("x86_64".Length + 1))); | |||||
} | |||||
else { | |||||
// Throw away | |||||
yield break; | |||||
} | |||||
} | |||||
else if (!isFlat && isFileFlat) { | |||||
// Deepen structure | |||||
yield return new FileInfo(Path.Combine(Path.Combine(nativePluginFolder.FullName, "x86"), | |||||
relevantBit)); | |||||
yield return new FileInfo(Path.Combine(Path.Combine(nativePluginFolder.FullName, "x86_64"), | |||||
relevantBit)); | |||||
} | |||||
else { | |||||
yield return to; | |||||
} | |||||
} | |||||
else { | |||||
yield return to; | |||||
} | |||||
} | |||||
private static IEnumerable<FileInfo> PassThroughInterceptor(FileInfo from, FileInfo to) { | |||||
yield return to; | |||||
} | |||||
public static void CopyAll(DirectoryInfo source, DirectoryInfo target, bool aggressive, BackupUnit backup, | |||||
Func<FileInfo, FileInfo, IEnumerable<FileInfo>> interceptor = null) { | |||||
if (interceptor == null) { | |||||
interceptor = PassThroughInterceptor; | |||||
} | |||||
// Copy each file into the new directory. | |||||
foreach (FileInfo fi in source.GetFiles()) { | |||||
foreach (var targetFile in interceptor(fi, new FileInfo(Path.Combine(target.FullName, fi.Name)))) { | |||||
if (!targetFile.Exists || targetFile.LastWriteTimeUtc < fi.LastWriteTimeUtc || aggressive) { | |||||
targetFile.Directory.Create(); | |||||
Console.WriteLine(@"Copying {0}", targetFile.FullName); | |||||
backup.Add(targetFile); | |||||
fi.CopyTo(targetFile.FullName, true); | |||||
} | |||||
} | |||||
} | |||||
// Copy each subdirectory using recursion. | |||||
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) { | |||||
DirectoryInfo nextTargetSubDir = new DirectoryInfo(Path.Combine(target.FullName, diSourceSubDir.Name)); | |||||
CopyAll(diSourceSubDir, nextTargetSubDir, aggressive, backup, interceptor); | |||||
} | |||||
} | |||||
static void Fail(string message) { | |||||
Console.Error.Write("ERROR: " + message); | |||||
if (!Environment.CommandLine.Contains("--nowait")) { | |||||
Console.WriteLine("\n\n[Press any key to quit]"); | |||||
Console.ReadKey(); | |||||
} | |||||
Environment.Exit(1); | |||||
} | |||||
public static string Args(params string[] args) { | |||||
return string.Join(" ", args.Select(EncodeParameterArgument).ToArray()); | |||||
} | |||||
/// <summary> | |||||
/// Encodes an argument for passing into a program | |||||
/// </summary> | |||||
/// <param name="original">The value that should be received by the program</param> | |||||
/// <returns>The value which needs to be passed to the program for the original value | |||||
/// to come through</returns> | |||||
public static string EncodeParameterArgument(string original) { | |||||
if (string.IsNullOrEmpty(original)) | |||||
return original; | |||||
string value = Regex.Replace(original, @"(\\*)" + "\"", @"$1\$0"); | |||||
value = Regex.Replace(value, @"^(.*\s.*?)(\\*)$", "\"$1$2$2\""); | |||||
return value; | |||||
} | |||||
public static Architecture DetectArchitecture(string assembly) { | |||||
using (var reader = new BinaryReader(File.OpenRead(assembly))) { | |||||
var header = reader.ReadUInt16(); | |||||
if (header == 0x5a4d) { | |||||
reader.BaseStream.Seek(60, SeekOrigin.Begin); // this location contains the offset for the PE header | |||||
var peOffset = reader.ReadUInt32(); | |||||
reader.BaseStream.Seek(peOffset + 4, SeekOrigin.Begin); | |||||
var machine = reader.ReadUInt16(); | |||||
if (machine == 0x8664) // IMAGE_FILE_MACHINE_AMD64 | |||||
return Architecture.x64; | |||||
else if (machine == 0x014c) // IMAGE_FILE_MACHINE_I386 | |||||
return Architecture.x86; | |||||
else if (machine == 0x0200) // IMAGE_FILE_MACHINE_IA64 | |||||
return Architecture.x64; | |||||
else | |||||
return Architecture.Unknown; | |||||
} | |||||
else { | |||||
// Not a supported binary | |||||
return Architecture.Unknown; | |||||
} | |||||
} | |||||
} | |||||
public abstract class Keyboard { | |||||
[Flags] | |||||
private enum KeyStates { | |||||
None = 0, | |||||
Down = 1, | |||||
Toggled = 2 | |||||
} | |||||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] | |||||
private static extern short GetKeyState(int keyCode); | |||||
private static KeyStates GetKeyState(Keys key) { | |||||
KeyStates state = KeyStates.None; | |||||
short retVal = GetKeyState((int) key); | |||||
//If the high-order bit is 1, the key is down | |||||
//otherwise, it is up. | |||||
if ((retVal & 0x8000) == 0x8000) | |||||
state |= KeyStates.Down; | |||||
//If the low-order bit is 1, the key is toggled. | |||||
if ((retVal & 1) == 1) | |||||
state |= KeyStates.Toggled; | |||||
return state; | |||||
} | |||||
public static bool IsKeyDown(Keys key) { | |||||
return KeyStates.Down == (GetKeyState(key) & KeyStates.Down); | |||||
} | |||||
public static bool IsKeyToggled(Keys key) { | |||||
return KeyStates.Toggled == (GetKeyState(key) & KeyStates.Toggled); | |||||
} | |||||
} | |||||
} | |||||
} | } |
@ -1,36 +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("Illusion Plugin Architecture")] | |||||
[assembly: AssemblyDescription("")] | |||||
[assembly: AssemblyConfiguration("")] | |||||
[assembly: AssemblyCompany("")] | |||||
[assembly: AssemblyProduct("Illusion Plugin Architecture")] | |||||
[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("3.7")] | |||||
[assembly: AssemblyFileVersion("3.7")] | |||||
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("Illusion Plugin Architecture")] | |||||
[assembly: AssemblyDescription("")] | |||||
[assembly: AssemblyConfiguration("")] | |||||
[assembly: AssemblyCompany("")] | |||||
[assembly: AssemblyProduct("Illusion Plugin Architecture")] | |||||
[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("3.7")] | |||||
[assembly: AssemblyFileVersion("3.7")] |
@ -1 +1 @@ | |||||
f7c20aca6b99cd3b62d50a05d9bdca1eb41dca2a | |||||
65c33cfc23e8dcfc89c7fd78e8cd8344a2518294 |
@ -1,135 +1,135 @@ | |||||
using IllusionPlugin; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using UnityEngine; | |||||
using UnityEngine.SceneManagement; | |||||
using Logger = IllusionPlugin.Logger; | |||||
namespace IllusionInjector { | |||||
public class CompositePlugin : IPlugin { | |||||
IEnumerable<IPlugin> plugins; | |||||
private delegate void CompositeCall(IPlugin plugin); | |||||
private Logger debugLogger => PluginManager.debugLogger; | |||||
public CompositePlugin(IEnumerable<IPlugin> plugins) { | |||||
this.plugins = plugins; | |||||
} | |||||
public void OnApplicationStart() { | |||||
Invoke(plugin => plugin.OnApplicationStart()); | |||||
} | |||||
public void OnApplicationQuit() { | |||||
Invoke(plugin => plugin.OnApplicationQuit()); | |||||
} | |||||
public void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode) { | |||||
foreach (var plugin1 in plugins.Where(o => o is IPluginNew)) { | |||||
var plugin = (IPluginNew) plugin1; | |||||
try { | |||||
plugin.OnSceneLoaded(scene, sceneMode); | |||||
} | |||||
catch (Exception ex) { | |||||
debugLogger.Exception($"{plugin.Name}: {ex}"); | |||||
} | |||||
} | |||||
} | |||||
public void OnSceneUnloaded(Scene scene) { | |||||
foreach (var plugin1 in plugins.Where(o => o is IPluginNew)) { | |||||
var plugin = (IPluginNew) plugin1; | |||||
try { | |||||
plugin.OnSceneUnloaded(scene); | |||||
} | |||||
catch (Exception ex) { | |||||
debugLogger.Exception($"{plugin.Name}: {ex}"); | |||||
} | |||||
} | |||||
} | |||||
public void OnActiveSceneChanged(Scene prevScene, Scene nextScene) { | |||||
foreach (var plugin1 in plugins.Where(o => o is IPluginNew)) { | |||||
var plugin = (IPluginNew) plugin1; | |||||
try { | |||||
plugin.OnActiveSceneChanged(prevScene, nextScene); | |||||
} | |||||
catch (Exception ex) { | |||||
debugLogger.Exception($"{plugin.Name}: {ex}"); | |||||
} | |||||
} | |||||
} | |||||
private void Invoke(CompositeCall callback) { | |||||
foreach (var plugin in plugins) { | |||||
try { | |||||
callback(plugin); | |||||
} | |||||
catch (Exception ex) { | |||||
debugLogger.Exception($"{plugin.Name}: {ex}"); | |||||
} | |||||
} | |||||
} | |||||
public void OnUpdate() { | |||||
Invoke(plugin => plugin.OnUpdate()); | |||||
} | |||||
public void OnFixedUpdate() { | |||||
Invoke(plugin => plugin.OnFixedUpdate()); | |||||
} | |||||
[Obsolete("Use OnSceneLoaded instead")] | |||||
public void OnLevelWasLoaded(int level) | |||||
{ | |||||
foreach (var plugin in plugins) | |||||
{ | |||||
try | |||||
{ | |||||
plugin.OnLevelWasLoaded(level); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
Console.WriteLine("{0}: {1}", plugin.Name, ex); | |||||
} | |||||
} | |||||
} | |||||
[Obsolete("Use OnSceneLoaded instead")] | |||||
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 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(); | |||||
}); | |||||
} | |||||
} | |||||
using IllusionPlugin; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using UnityEngine; | |||||
using UnityEngine.SceneManagement; | |||||
using Logger = IllusionPlugin.Logger; | |||||
namespace IllusionInjector { | |||||
public class CompositePlugin : IPlugin { | |||||
IEnumerable<IPlugin> plugins; | |||||
private delegate void CompositeCall(IPlugin plugin); | |||||
private Logger debugLogger => PluginManager.debugLogger; | |||||
public CompositePlugin(IEnumerable<IPlugin> plugins) { | |||||
this.plugins = plugins; | |||||
} | |||||
public void OnApplicationStart() { | |||||
Invoke(plugin => plugin.OnApplicationStart()); | |||||
} | |||||
public void OnApplicationQuit() { | |||||
Invoke(plugin => plugin.OnApplicationQuit()); | |||||
} | |||||
public void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode) { | |||||
foreach (var plugin1 in plugins.Where(o => o is IPluginNew)) { | |||||
var plugin = (IPluginNew) plugin1; | |||||
try { | |||||
plugin.OnSceneLoaded(scene, sceneMode); | |||||
} | |||||
catch (Exception ex) { | |||||
debugLogger.Exception($"{plugin.Name}: {ex}"); | |||||
} | |||||
} | |||||
} | |||||
public void OnSceneUnloaded(Scene scene) { | |||||
foreach (var plugin1 in plugins.Where(o => o is IPluginNew)) { | |||||
var plugin = (IPluginNew) plugin1; | |||||
try { | |||||
plugin.OnSceneUnloaded(scene); | |||||
} | |||||
catch (Exception ex) { | |||||
debugLogger.Exception($"{plugin.Name}: {ex}"); | |||||
} | |||||
} | |||||
} | |||||
public void OnActiveSceneChanged(Scene prevScene, Scene nextScene) { | |||||
foreach (var plugin1 in plugins.Where(o => o is IPluginNew)) { | |||||
var plugin = (IPluginNew) plugin1; | |||||
try { | |||||
plugin.OnActiveSceneChanged(prevScene, nextScene); | |||||
} | |||||
catch (Exception ex) { | |||||
debugLogger.Exception($"{plugin.Name}: {ex}"); | |||||
} | |||||
} | |||||
} | |||||
private void Invoke(CompositeCall callback) { | |||||
foreach (var plugin in plugins) { | |||||
try { | |||||
callback(plugin); | |||||
} | |||||
catch (Exception ex) { | |||||
debugLogger.Exception($"{plugin.Name}: {ex}"); | |||||
} | |||||
} | |||||
} | |||||
public void OnUpdate() { | |||||
Invoke(plugin => plugin.OnUpdate()); | |||||
} | |||||
public void OnFixedUpdate() { | |||||
Invoke(plugin => plugin.OnFixedUpdate()); | |||||
} | |||||
[Obsolete("Use OnSceneLoaded instead")] | |||||
public void OnLevelWasLoaded(int level) | |||||
{ | |||||
foreach (var plugin in plugins) | |||||
{ | |||||
try | |||||
{ | |||||
plugin.OnLevelWasLoaded(level); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
Console.WriteLine("{0}: {1}", plugin.Name, ex); | |||||
} | |||||
} | |||||
} | |||||
[Obsolete("Use OnSceneLoaded instead")] | |||||
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 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(); | |||||
}); | |||||
} | |||||
} | |||||
} | } |
@ -1,69 +1,69 @@ | |||||
<?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> | |||||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||||
<HintPath>..\Libs\UnityEngine.CoreModule.dll</HintPath> | |||||
</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> | |||||
--> | |||||
<?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> | |||||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||||
<HintPath>..\Libs\UnityEngine.CoreModule.dll</HintPath> | |||||
</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> | </Project> |
@ -1,96 +1,96 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using UnityEngine; | |||||
using UnityEngine.SceneManagement; | |||||
namespace IllusionInjector | |||||
{ | |||||
public class PluginComponent : MonoBehaviour | |||||
{ | |||||
private CompositePlugin plugins; | |||||
private bool freshlyLoaded = false; | |||||
private bool quitting = false; | |||||
public static PluginComponent Create() | |||||
{ | |||||
return new GameObject("IPA_PluginManager").AddComponent<PluginComponent>(); | |||||
} | |||||
void Awake() | |||||
{ | |||||
DontDestroyOnLoad(gameObject); | |||||
plugins = new CompositePlugin(PluginManager.Plugins); | |||||
plugins.OnApplicationStart(); | |||||
SceneManager.activeSceneChanged += OnActiveSceneChanged; | |||||
SceneManager.sceneLoaded += OnSceneLoaded; | |||||
SceneManager.sceneUnloaded += OnSceneUnloaded; | |||||
} | |||||
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() | |||||
{ | |||||
if (!quitting) | |||||
{ | |||||
Create(); | |||||
} | |||||
} | |||||
void OnApplicationQuit() | |||||
{ | |||||
SceneManager.activeSceneChanged += OnActiveSceneChanged; | |||||
SceneManager.sceneLoaded += OnSceneLoaded; | |||||
SceneManager.sceneUnloaded += OnSceneUnloaded; | |||||
plugins.OnApplicationQuit(); | |||||
quitting = true; | |||||
} | |||||
void OnLevelWasLoaded(int level) | |||||
{ | |||||
plugins.OnLevelWasLoaded(level); | |||||
freshlyLoaded = true; | |||||
} | |||||
void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode) | |||||
{ | |||||
plugins.OnSceneLoaded(scene, sceneMode); | |||||
} | |||||
private void OnSceneUnloaded(Scene scene) { | |||||
plugins.OnSceneUnloaded(scene); | |||||
} | |||||
private void OnActiveSceneChanged(Scene prevScene, Scene nextScene) { | |||||
plugins.OnActiveSceneChanged(prevScene, nextScene); | |||||
} | |||||
} | |||||
} | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using UnityEngine; | |||||
using UnityEngine.SceneManagement; | |||||
namespace IllusionInjector | |||||
{ | |||||
public class PluginComponent : MonoBehaviour | |||||
{ | |||||
private CompositePlugin plugins; | |||||
private bool freshlyLoaded = false; | |||||
private bool quitting = false; | |||||
public static PluginComponent Create() | |||||
{ | |||||
return new GameObject("IPA_PluginManager").AddComponent<PluginComponent>(); | |||||
} | |||||
void Awake() | |||||
{ | |||||
DontDestroyOnLoad(gameObject); | |||||
plugins = new CompositePlugin(PluginManager.Plugins); | |||||
plugins.OnApplicationStart(); | |||||
SceneManager.activeSceneChanged += OnActiveSceneChanged; | |||||
SceneManager.sceneLoaded += OnSceneLoaded; | |||||
SceneManager.sceneUnloaded += OnSceneUnloaded; | |||||
} | |||||
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() | |||||
{ | |||||
if (!quitting) | |||||
{ | |||||
Create(); | |||||
} | |||||
} | |||||
void OnApplicationQuit() | |||||
{ | |||||
SceneManager.activeSceneChanged += OnActiveSceneChanged; | |||||
SceneManager.sceneLoaded += OnSceneLoaded; | |||||
SceneManager.sceneUnloaded += OnSceneUnloaded; | |||||
plugins.OnApplicationQuit(); | |||||
quitting = true; | |||||
} | |||||
void OnLevelWasLoaded(int level) | |||||
{ | |||||
plugins.OnLevelWasLoaded(level); | |||||
freshlyLoaded = true; | |||||
} | |||||
void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode) | |||||
{ | |||||
plugins.OnSceneLoaded(scene, sceneMode); | |||||
} | |||||
private void OnSceneUnloaded(Scene scene) { | |||||
plugins.OnSceneUnloaded(scene); | |||||
} | |||||
private void OnActiveSceneChanged(Scene prevScene, Scene nextScene) { | |||||
plugins.OnActiveSceneChanged(prevScene, nextScene); | |||||
} | |||||
} | |||||
} |
@ -1,154 +1,154 @@ | |||||
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; | |||||
internal static readonly Logger debugLogger = new Logger("IllusionInjector"); | |||||
/// <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); | |||||
debugLogger.Log(exeName); | |||||
_Plugins = new List<IPlugin>(); | |||||
if (!Directory.Exists(pluginDirectory)) return; | |||||
if (!Directory.Exists(Path.Combine(pluginDirectory, ".cache"))) | |||||
{ | |||||
Directory.CreateDirectory(Path.Combine(pluginDirectory, ".cache")); | |||||
} | |||||
else | |||||
{ | |||||
foreach (string plugin in Directory.GetFiles(Path.Combine(pluginDirectory, ".cache"), "*")) | |||||
{ | |||||
File.Delete(plugin); | |||||
} | |||||
} | |||||
//Copy plugins to .cache | |||||
string[] originalPlugins = Directory.GetFiles(pluginDirectory, "*.dll"); | |||||
foreach (string s in originalPlugins) | |||||
{ | |||||
string pluginCopy = pluginDirectory + "\\.cache" + s.Substring(s.LastIndexOf('\\')); | |||||
File.Copy(Path.Combine(pluginDirectory, s), pluginCopy); | |||||
} | |||||
//Load copied plugins | |||||
string copiedPluginsDirectory = pluginDirectory + "\\.cache"; | |||||
string[] copiedPlugins = Directory.GetFiles(copiedPluginsDirectory, "*.dll"); | |||||
foreach (string s in copiedPlugins) | |||||
{ | |||||
_Plugins.AddRange(LoadPluginsFromFile(s, exeName)); | |||||
} | |||||
// DEBUG | |||||
debugLogger.Log($"Running on Unity {UnityEngine.Application.unityVersion}"); | |||||
debugLogger.Log("-----------------------------"); | |||||
debugLogger.Log($"Loading plugins from {pluginDirectory} and found {_Plugins.Count}"); | |||||
debugLogger.Log("-----------------------------"); | |||||
foreach (var plugin in _Plugins) | |||||
{ | |||||
debugLogger.Log($"{plugin.Name}: {plugin.Version}"); | |||||
if (!(plugin is IPluginNew)) { | |||||
debugLogger.Warning($"{plugin.Name} uses a Deprecated Interface! This may cause errors!"); | |||||
} | |||||
} | |||||
debugLogger.Log("-----------------------------"); | |||||
} | |||||
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 || filter.Contains(exeName, StringComparer.OrdinalIgnoreCase)) | |||||
plugins.Add(pluginInstance); | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
debugLogger.Exception($"Could not load plugin {t.FullName} in {Path.GetFileName(file)}! {e}"); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
debugLogger.Error($"Could not load {Path.GetFileName(file)}! {e}"); | |||||
} | |||||
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(); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
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; | |||||
internal static readonly Logger debugLogger = new Logger("IllusionInjector"); | |||||
/// <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); | |||||
debugLogger.Log(exeName); | |||||
_Plugins = new List<IPlugin>(); | |||||
if (!Directory.Exists(pluginDirectory)) return; | |||||
if (!Directory.Exists(Path.Combine(pluginDirectory, ".cache"))) | |||||
{ | |||||
Directory.CreateDirectory(Path.Combine(pluginDirectory, ".cache")); | |||||
} | |||||
else | |||||
{ | |||||
foreach (string plugin in Directory.GetFiles(Path.Combine(pluginDirectory, ".cache"), "*")) | |||||
{ | |||||
File.Delete(plugin); | |||||
} | |||||
} | |||||
//Copy plugins to .cache | |||||
string[] originalPlugins = Directory.GetFiles(pluginDirectory, "*.dll"); | |||||
foreach (string s in originalPlugins) | |||||
{ | |||||
string pluginCopy = pluginDirectory + "\\.cache" + s.Substring(s.LastIndexOf('\\')); | |||||
File.Copy(Path.Combine(pluginDirectory, s), pluginCopy); | |||||
} | |||||
//Load copied plugins | |||||
string copiedPluginsDirectory = pluginDirectory + "\\.cache"; | |||||
string[] copiedPlugins = Directory.GetFiles(copiedPluginsDirectory, "*.dll"); | |||||
foreach (string s in copiedPlugins) | |||||
{ | |||||
_Plugins.AddRange(LoadPluginsFromFile(s, exeName)); | |||||
} | |||||
// DEBUG | |||||
debugLogger.Log($"Running on Unity {UnityEngine.Application.unityVersion}"); | |||||
debugLogger.Log("-----------------------------"); | |||||
debugLogger.Log($"Loading plugins from {pluginDirectory} and found {_Plugins.Count}"); | |||||
debugLogger.Log("-----------------------------"); | |||||
foreach (var plugin in _Plugins) | |||||
{ | |||||
debugLogger.Log($"{plugin.Name}: {plugin.Version}"); | |||||
if (!(plugin is IPluginNew)) { | |||||
debugLogger.Warning($"{plugin.Name} uses a Deprecated Interface! This may cause errors!"); | |||||
} | |||||
} | |||||
debugLogger.Log("-----------------------------"); | |||||
} | |||||
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 || filter.Contains(exeName, StringComparer.OrdinalIgnoreCase)) | |||||
plugins.Add(pluginInstance); | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
debugLogger.Exception($"Could not load plugin {t.FullName} in {Path.GetFileName(file)}! {e}"); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
catch (Exception e) | |||||
{ | |||||
debugLogger.Error($"Could not load {Path.GetFileName(file)}! {e}"); | |||||
} | |||||
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(); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
@ -1 +1 @@ | |||||
207669803f9c3f5ead7136a41944fdaa372fd294 | |||||
c4f9eceab04df8633c0ae4f922a37f459ec45217 |
@ -1,50 +1,50 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using UnityEngine.SceneManagement; | |||||
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 on every graphic update. | |||||
/// </summary> | |||||
void OnUpdate(); | |||||
/// <summary> | |||||
/// Gets invoked on ever physics update. | |||||
/// </summary> | |||||
void OnFixedUpdate(); | |||||
[Obsolete("Use OnSceneLoaded instead")] | |||||
void OnLevelWasLoaded(int level); | |||||
[Obsolete("Use OnSceneLoaded instead")] | |||||
void OnLevelWasInitialized(int level); | |||||
} | |||||
} | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using UnityEngine.SceneManagement; | |||||
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 on every graphic update. | |||||
/// </summary> | |||||
void OnUpdate(); | |||||
/// <summary> | |||||
/// Gets invoked on ever physics update. | |||||
/// </summary> | |||||
void OnFixedUpdate(); | |||||
[Obsolete("Use OnSceneLoaded instead")] | |||||
void OnLevelWasLoaded(int level); | |||||
[Obsolete("Use OnSceneLoaded instead")] | |||||
void OnLevelWasInitialized(int level); | |||||
} | |||||
} |
@ -1,60 +1,60 @@ | |||||
<?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" /> | |||||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||||
<HintPath>..\Libs\UnityEngine.CoreModule.dll</HintPath> | |||||
</Reference> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Compile Include="IEnhancedPlugin.cs" /> | |||||
<Compile Include="IniFile.cs" /> | |||||
<Compile Include="IPlugin.cs" /> | |||||
<Compile Include="IPluginNew.cs" /> | |||||
<Compile Include="Logger.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> | |||||
--> | |||||
<?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" /> | |||||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | |||||
<HintPath>..\Libs\UnityEngine.CoreModule.dll</HintPath> | |||||
</Reference> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Compile Include="IEnhancedPlugin.cs" /> | |||||
<Compile Include="IniFile.cs" /> | |||||
<Compile Include="IPlugin.cs" /> | |||||
<Compile Include="IPluginNew.cs" /> | |||||
<Compile Include="Logger.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> | </Project> |
@ -1,101 +1,101 @@ | |||||
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; | |||||
} | |||||
}*/ | |||||
private FileInfo _iniFileInfo; | |||||
public FileInfo IniFileInfo { | |||||
get => _iniFileInfo; | |||||
set { | |||||
_iniFileInfo = value; | |||||
if (_iniFileInfo.Exists) return; | |||||
_iniFileInfo.Directory?.Create(); | |||||
_iniFileInfo.Create(); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// INIFile Constructor. | |||||
/// </summary> | |||||
/// <PARAM name="INIPath"></PARAM> | |||||
public IniFile(string iniPath) | |||||
{ | |||||
IniFileInfo = new FileInfo(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, IniFileInfo.FullName); | |||||
} | |||||
/// <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, IniFileInfo.FullName); | |||||
return result.ToString(); | |||||
} | |||||
} | |||||
} | |||||
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; | |||||
} | |||||
}*/ | |||||
private FileInfo _iniFileInfo; | |||||
public FileInfo IniFileInfo { | |||||
get => _iniFileInfo; | |||||
set { | |||||
_iniFileInfo = value; | |||||
if (_iniFileInfo.Exists) return; | |||||
_iniFileInfo.Directory?.Create(); | |||||
_iniFileInfo.Create(); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// INIFile Constructor. | |||||
/// </summary> | |||||
/// <PARAM name="INIPath"></PARAM> | |||||
public IniFile(string iniPath) | |||||
{ | |||||
IniFileInfo = new FileInfo(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, IniFileInfo.FullName); | |||||
} | |||||
/// <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, IniFileInfo.FullName); | |||||
return result.ToString(); | |||||
} | |||||
} | |||||
} |
@ -1,167 +1,167 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Text; | |||||
namespace IllusionPlugin | |||||
{ | |||||
/// <summary> | |||||
/// Allows to get and set preferences for your mod. | |||||
/// </summary> | |||||
public class ModPrefs { | |||||
internal static Dictionary<IPlugin, ModPrefs> ModPrefses { get; set; } = new Dictionary<IPlugin, ModPrefs>(); | |||||
private IniFile Instance; | |||||
public ModPrefs(IPlugin plugin) { | |||||
Instance = new IniFile(Path.Combine(Environment.CurrentDirectory, $"UserData/ModPrefs/{plugin.Name}.ini")); | |||||
ModPrefses.Add(plugin, this); | |||||
} | |||||
/// <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 string GetString(string section, string name, string defaultValue = "", bool autoSave = false) | |||||
{ | |||||
var 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 int GetInt(string section, string name, int defaultValue = 0, bool autoSave = false) | |||||
{ | |||||
if (int.TryParse(Instance.IniReadValue(section, name), out var 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 float GetFloat(string section, string name, float defaultValue = 0f, bool autoSave = false) | |||||
{ | |||||
if (float.TryParse(Instance.IniReadValue(section, name), out var 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 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 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 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 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 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 void SetBool(string section, string name, bool value) | |||||
{ | |||||
Instance.IniWriteValue(section, name, value ? "1" : "0"); | |||||
} | |||||
} | |||||
public static class ModPrefsExtensions { | |||||
public static ModPrefs GetModPrefs(this IPlugin plugin) { | |||||
return ModPrefs.ModPrefses.First(o => o.Key == plugin).Value; | |||||
} | |||||
} | |||||
} | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Text; | |||||
namespace IllusionPlugin | |||||
{ | |||||
/// <summary> | |||||
/// Allows to get and set preferences for your mod. | |||||
/// </summary> | |||||
public class ModPrefs { | |||||
internal static Dictionary<IPlugin, ModPrefs> ModPrefses { get; set; } = new Dictionary<IPlugin, ModPrefs>(); | |||||
private IniFile Instance; | |||||
public ModPrefs(IPlugin plugin) { | |||||
Instance = new IniFile(Path.Combine(Environment.CurrentDirectory, $"UserData/ModPrefs/{plugin.Name}.ini")); | |||||
ModPrefses.Add(plugin, this); | |||||
} | |||||
/// <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 string GetString(string section, string name, string defaultValue = "", bool autoSave = false) | |||||
{ | |||||
var 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 int GetInt(string section, string name, int defaultValue = 0, bool autoSave = false) | |||||
{ | |||||
if (int.TryParse(Instance.IniReadValue(section, name), out var 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 float GetFloat(string section, string name, float defaultValue = 0f, bool autoSave = false) | |||||
{ | |||||
if (float.TryParse(Instance.IniReadValue(section, name), out var 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 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 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 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 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 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 void SetBool(string section, string name, bool value) | |||||
{ | |||||
Instance.IniWriteValue(section, name, value ? "1" : "0"); | |||||
} | |||||
} | |||||
public static class ModPrefsExtensions { | |||||
public static ModPrefs GetModPrefs(this IPlugin plugin) { | |||||
return ModPrefs.ModPrefses.First(o => o.Key == plugin).Value; | |||||
} | |||||
} | |||||
} |
@ -1 +1 @@ | |||||
dd098bdf8443f9e98a9261f325ce0c78fe53aba4 | |||||
de4d7d5be2f255b6eb5fe16bec001496ad0c8963 |
@ -1,91 +0,0 @@ | |||||
<?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>Launcher</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> | |||||
<PropertyGroup> | |||||
<ApplicationIcon>syringe.ico</ApplicationIcon> | |||||
</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.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> | |||||
<DesignTime>True</DesignTime> | |||||
</Compile> | |||||
<EmbeddedResource Include="Resources.resx"> | |||||
<Generator>ResXFileCodeGenerator</Generator> | |||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput> | |||||
</EmbeddedResource> | |||||
<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> | |||||
<Content Include="syringe.ico" /> | |||||
</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> |
@ -1,100 +0,0 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Text.RegularExpressions; | |||||
using System.Windows.Forms; | |||||
namespace Launcher | |||||
{ | |||||
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) | |||||
{ | |||||
Fail("File not named correctly!"); | |||||
} | |||||
bool vrMode = fileName.IndexOf("VR") > 0; | |||||
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(); | |||||
if (vrMode) args.Add("--vr"); | |||||
EnsureIPA(executable); | |||||
StartGame(executable, args.ToArray()); | |||||
} | |||||
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); | |||||
} | |||||
} | |||||
private static void EnsureIPA(string executable) | |||||
{ | |||||
var processStart = new ProcessStartInfo("IPA.exe", EncodeParameterArgument(executable) + " --nowait"); | |||||
processStart.UseShellExecute = false; | |||||
processStart.CreateNoWindow = true; | |||||
processStart.RedirectStandardError = true; | |||||
var process = Process.Start(processStart); | |||||
process.WaitForExit(); | |||||
if(process.ExitCode != 0) | |||||
{ | |||||
Fail(process.StandardError.ReadToEnd()); | |||||
} | |||||
} | |||||
private static void StartGame(string executable, string[] args) | |||||
{ | |||||
var arguments = string.Join(" ", args.ToArray()); | |||||
Process.Start(executable, arguments); | |||||
} | |||||
private static void Fail(string reason) { | |||||
throw new Exception(reason); | |||||
} | |||||
/// <summary> | |||||
/// Encodes an argument for passing into a program | |||||
/// </summary> | |||||
/// <param name="original">The value that should be received by the program</param> | |||||
/// <returns>The value which needs to be passed to the program for the original value | |||||
/// to come through</returns> | |||||
private static string EncodeParameterArgument(string original) | |||||
{ | |||||
if (string.IsNullOrEmpty(original)) | |||||
return original; | |||||
string value = Regex.Replace(original, @"(\\*)" + "\"", @"$1\$0"); | |||||
value = Regex.Replace(value, @"^(.*\s.*?)(\\*)$", "\"$1$2$2\""); | |||||
return value; | |||||
} | |||||
} | |||||
} |
@ -1,36 +0,0 @@ | |||||
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("Launcher")] | |||||
[assembly: AssemblyDescription("Rename to [EXE]_Patched.exe or [EXE]VR.exe")] | |||||
[assembly: AssemblyConfiguration("")] | |||||
[assembly: AssemblyCompany("")] | |||||
[assembly: AssemblyProduct("Launcher")] | |||||
[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")] |
@ -1,63 +0,0 @@ | |||||
//------------------------------------------------------------------------------ | |||||
// <auto-generated> | |||||
// This code was generated by a tool. | |||||
// Runtime Version:4.0.30319.42000 | |||||
// | |||||
// Changes to this file may cause incorrect behavior and will be lost if | |||||
// the code is regenerated. | |||||
// </auto-generated> | |||||
//------------------------------------------------------------------------------ | |||||
namespace Launcher.Properties { | |||||
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("Launcher.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; | |||||
} | |||||
} | |||||
} | |||||
} |
@ -1,117 +0,0 @@ | |||||
<?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> |
@ -1,26 +0,0 @@ | |||||
//------------------------------------------------------------------------------ | |||||
// <auto-generated> | |||||
// This code was generated by a tool. | |||||
// Runtime Version:4.0.30319.42000 | |||||
// | |||||
// Changes to this file may cause incorrect behavior and will be lost if | |||||
// the code is regenerated. | |||||
// </auto-generated> | |||||
//------------------------------------------------------------------------------ | |||||
namespace Launcher.Properties { | |||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.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; | |||||
} | |||||
} | |||||
} | |||||
} |
@ -1,7 +0,0 @@ | |||||
<?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> |
@ -1,63 +0,0 @@ | |||||
//------------------------------------------------------------------------------ | |||||
// <auto-generated> | |||||
// This code was generated by a tool. | |||||
// Runtime Version:4.0.30319.42000 | |||||
// | |||||
// Changes to this file may cause incorrect behavior and will be lost if | |||||
// the code is regenerated. | |||||
// </auto-generated> | |||||
//------------------------------------------------------------------------------ | |||||
namespace Launcher { | |||||
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("Launcher.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; | |||||
} | |||||
} | |||||
} | |||||
} |
@ -1,121 +0,0 @@ | |||||
<?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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||||
<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" use="required" type="xsd:string" /> | |||||
<xsd:attribute name="type" type="xsd:string" /> | |||||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||||
<xsd:attribute ref="xml:space" /> | |||||
</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" use="required" msdata:Ordinal="1" /> | |||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||||
<xsd:attribute ref="xml:space" /> | |||||
</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> | |||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> | |||||
</root> |
@ -1 +0,0 @@ | |||||
7c6dbd91916854c83d27e1fd6e1b9ccedbe983b8 |
@ -1,4 +0,0 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<packages> | |||||
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net35" /> | |||||
</packages> |