Browse Source

Completely removed old patching method

pull/46/head
Anairkoen Schno 6 years ago
parent
commit
22336ffa91
7 changed files with 30 additions and 412 deletions
  1. +0
    -14
      IPA.Injector/Injector.cs
  2. +1
    -2
      IPA.Loader/Updating/ModSaber/ApiEndpoint.cs
  3. +0
    -2
      IPA/IPA.csproj
  4. +0
    -134
      IPA/Patcher/Patcher.cs
  5. +0
    -116
      IPA/Patcher/Virtualizer.cs
  6. +28
    -143
      IPA/Program.cs
  7. +1
    -1
      IPA/obj/Debug/IPA.csproj.CoreCompileInputs.cache

+ 0
- 14
IPA.Injector/Injector.cs View File

@ -14,7 +14,6 @@ using MethodAttributes = Mono.Cecil.MethodAttributes;
namespace IPA.Injector namespace IPA.Injector
{ {
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public static class Injector public static class Injector
{ {
// ReSharper disable once UnusedParameter.Global // ReSharper disable once UnusedParameter.Global
@ -165,19 +164,6 @@ namespace IPA.Injector
bootstrapper.Destroyed += Bootstrapper_Destroyed; bootstrapper.Destroyed += Bootstrapper_Destroyed;
} }
private static bool _injected;
public static void Inject()
{
if (!_injected)
{
_injected = true;
WinConsole.Initialize();
SetupLibraryLoading();
var bootstrapper = new GameObject("Bootstrapper").AddComponent<Bootstrapper>();
bootstrapper.Destroyed += Bootstrapper_Destroyed;
}
}
private static bool _loadingDone; private static bool _loadingDone;
private static void SetupLibraryLoading() private static void SetupLibraryLoading()


+ 1
- 2
IPA.Loader/Updating/ModSaber/ApiEndpoint.cs View File

@ -120,8 +120,7 @@ namespace IPA.Updating.ModSaber
public string Manifest; public string Manifest;
} }
[JsonProperty("gameVersion"),
JsonConverter(typeof(SemverVersionConverter))]
[JsonProperty("gameVersion")]
public GameVersionType GameVersion; public GameVersionType GameVersion;
#pragma warning restore CS0649 #pragma warning restore CS0649


+ 0
- 2
IPA/IPA.csproj View File

@ -100,8 +100,6 @@
<Compile Include="PatchContext.cs" /> <Compile Include="PatchContext.cs" />
<Compile Include="Patcher\BackupManager.cs" /> <Compile Include="Patcher\BackupManager.cs" />
<Compile Include="Patcher\BackupUnit.cs" /> <Compile Include="Patcher\BackupUnit.cs" />
<Compile Include="Patcher\Patcher.cs" />
<Compile Include="Patcher\Virtualizer.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Shortcut.cs" /> <Compile Include="Shortcut.cs" />


+ 0
- 134
IPA/Patcher/Patcher.cs View File

@ -1,134 +0,0 @@
using Mono.Cecil;
using Mono.Cecil.Cil;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace IPA.Patcher
{
internal class PatchedModule
{
private static readonly string[] EntryTypes = { "Input", "Display" };
private readonly 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
{
var data = new PatchData { IsPatched = false, Version = null };
foreach (var @ref in _module.AssemblyReferences) {
switch (@ref.Name)
{
case "IllusionInjector":
case "IllusionPlugin":
data = new PatchData { IsPatched = true, Version = new Version(0, 0, 0, 0) };
break;
case "IPA.Injector":
return new PatchData { IsPatched = true, Version = @ref.Version };
}
}
return data;
}
}
public void Patch(Version v)
{
// First, let's add the reference
var nameReference = new AssemblyNameReference("IPA.Injector", v);
var injectorPath = Path.Combine(_file.DirectoryName ?? throw new InvalidOperationException(), "IPA.Injector.dll");
var injector = ModuleDefinition.ReadModule(injectorPath);
bool hasIPAInjector = false;
for (int i = 0; i < _module.AssemblyReferences.Count; i++)
{
if (_module.AssemblyReferences[i].Name == "IllusionInjector")
_module.AssemblyReferences.RemoveAt(i--);
if (_module.AssemblyReferences[i].Name == "IllusionPlugin")
_module.AssemblyReferences.RemoveAt(i--);
if (_module.AssemblyReferences[i].Name == "IPA.Injector")
{
hasIPAInjector = true;
_module.AssemblyReferences[i].Version = v;
}
}
if (!hasIPAInjector)
{
_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!");
}
}
else
{
_module.Write(_file.FullName);
}
}
private bool PatchType(TypeDefinition targetType, ModuleDefinition injector)
{
var targetMethod = targetType.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic);
if (targetMethod != null)
{
var methodReference = _module.ImportReference(injector.GetType("IPA.Injector.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 => EntryTypes.Contains(m.Name));
}
}
}

+ 0
- 116
IPA/Patcher/Virtualizer.cs View File

@ -1,116 +0,0 @@
using Mono.Cecil;
using System;
using System.IO;
using System.Linq;
namespace IPA.Patcher
{
class VirtualizedModule
{
private readonly FileInfo _file;
private ModuleDefinition _module;
public static VirtualizedModule Load(string engineFile)
{
return new VirtualizedModule(engineFile);
}
private VirtualizedModule(string assemblyFile)
{
_file = new FileInfo(assemblyFile);
LoadModules();
}
private void LoadModules()
{
var resolver = new DefaultAssemblyResolver();
resolver.AddSearchDirectory(_file.DirectoryName);
var parameters = new ReaderParameters
{
AssemblyResolver = resolver,
};
_module = ModuleDefinition.ReadModule(_file.FullName, parameters);
}
/// <summary>
///
/// </summary>
public void Virtualize()
{
foreach (var type in _module.Types)
{
VirtualizeType(type);
}
Console.WriteLine();
_module.Write(_file.FullName);
}
private void VirtualizeType(TypeDefinition type)
{
if(type.IsSealed)
{
// Unseal
type.IsSealed = false;
}
if (type.IsInterface) return;
if (type.IsAbstract) return;
// These two don't seem to work.
if (type.Name == "SceneControl" || type.Name == "ConfigUI") return;
//Console.CursorTop--;
Console.CursorLeft = 0;
Program.ClearLine();
Console.Write("Virtualizing {0}", type.Name);
// Take care of sub types
foreach (var subType in type.NestedTypes)
{
VirtualizeType(subType);
}
foreach (var method in type.Methods)
{
if (method.IsManaged
&& method.IsIL
&& !method.IsStatic
&& !method.IsVirtual
&& !method.IsAbstract
&& !method.IsAddOn
&& !method.IsConstructor
&& !method.IsSpecialName
&& !method.IsGenericInstance
&& !method.HasOverrides)
{
method.IsVirtual = true;
method.IsPublic = true;
method.IsPrivate = false;
method.IsNewSlot = true;
method.IsHideBySig = true;
}
}
foreach (var field in type.Fields)
{
if (field.IsPrivate) field.IsFamily = true;
}
}
public bool IsVirtualized
{
get
{
var awakeMethods = _module.GetTypes().SelectMany(t => t.Methods.Where(m => m.Name == "Awake"));
var methodDefinitions = awakeMethods as MethodDefinition[] ?? awakeMethods.ToArray();
if (!methodDefinitions.Any()) return false;
return ((float)methodDefinitions.Count(m => m.IsVirtual) / methodDefinitions.Count()) > 0.5f;
}
}
}
}

+ 28
- 143
IPA/Program.cs View File

@ -32,12 +32,12 @@ namespace IPA
public static readonly ArgumentFlag ArgNoWait = new ArgumentFlag("--nowait", "-n") { DocString = "doesn't wait for user input after the operation" }; public static readonly ArgumentFlag ArgNoWait = new ArgumentFlag("--nowait", "-n") { DocString = "doesn't wait for user input after the operation" };
public static readonly ArgumentFlag ArgStart = new ArgumentFlag("--start", "-s") { DocString = "uses value_ as arguments to start the game after the patch/unpatch", ValueString = "ARGUMENTS" }; public static readonly ArgumentFlag ArgStart = new ArgumentFlag("--start", "-s") { DocString = "uses value_ as arguments to start the game after the patch/unpatch", ValueString = "ARGUMENTS" };
public static readonly ArgumentFlag ArgLaunch = new ArgumentFlag("--launch", "-l") { DocString = "uses positional parameters as arguments to start the game after patch/unpatch" }; public static readonly ArgumentFlag ArgLaunch = new ArgumentFlag("--launch", "-l") { DocString = "uses positional parameters as arguments to start the game after patch/unpatch" };
public static readonly ArgumentFlag ArgDestructive = new ArgumentFlag("--destructive", "-d") { DocString = "patches the game using the now outdated destructive methods" };
//public static readonly ArgumentFlag ArgDestructive = new ArgumentFlag("--destructive", "-d") { DocString = "patches the game using the now outdated destructive methods" };
[STAThread] [STAThread]
public static void Main(string[] args) public static void Main(string[] args)
{ {
Arguments.CmdLine.Flags(ArgHelp, ArgWaitFor, ArgForce, ArgRevert, ArgNoWait, ArgStart, ArgLaunch, ArgDestructive).Process();
Arguments.CmdLine.Flags(ArgHelp, ArgWaitFor, ArgForce, ArgRevert, ArgNoWait, ArgStart, ArgLaunch/*, ArgDestructive*/).Process();
if (ArgHelp) if (ArgHelp)
{ {
@ -139,132 +139,35 @@ namespace IPA
try try
{ {
var backup = new BackupUnit(context); var backup = new BackupUnit(context);
if (ArgDestructive)
{
#region Patch Version Check
var patchedModule = PatchedModule.Load(context.EngineFile);
#if DEBUG
var isCurrentNewer = Version.CompareTo(patchedModule.Data.Version) >= 0;
#else
var isCurrentNewer = Version.CompareTo(patchedModule.Data.Version) > 0;
#endif
Console.WriteLine($"Current: {Version} Patched: {patchedModule.Data.Version}");
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);
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) || ArgForce;
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));
CopyAll(new DirectoryInfo(context.LibsPathSrc), new DirectoryInfo(context.LibsPathDst), 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 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 Creating shortcut
if (!File.Exists(context.ShortcutPath))
{
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine("Creating shortcut to IPA ({0})... ", context.IPA);
try
{
Shortcut.Create(
fileName: context.ShortcutPath,
targetPath: context.IPA,
arguments: Args(context.Executable, "-ln"),
workingDirectory: context.ProjectRoot,
description: "Launches the game and makes sure it's in a patched state",
hotkey: "",
iconPath: context.Executable
);
}
catch (Exception)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine("Failed to create shortcut, but game was patched!");
}
Console.ResetColor();
}
#endregion
}
else
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Restoring old version... ");
if (BackupManager.HasBackup(context))
BackupManager.Restore(context);
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) || ArgForce;
var architecture = DetectArchitecture(context.Executable);
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("Installing files... ");
CopyAll(new DirectoryInfo(context.DataPathSrc), new DirectoryInfo(context.DataPathDst), force,
backup,
(from, to) => NativePluginInterceptor(from, to, new DirectoryInfo(nativePluginFolder), isFlat,
architecture));
CopyAll(new DirectoryInfo(context.LibsPathSrc), new DirectoryInfo(context.LibsPathDst), force,
backup,
(from, to) => NativePluginInterceptor(from, to, new DirectoryInfo(nativePluginFolder), isFlat,
architecture));
CopyAll(new DirectoryInfo(context.IPARoot), new DirectoryInfo(context.ProjectRoot), force,
backup,
null, false);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Restoring old version... ");
if (BackupManager.HasBackup(context))
BackupManager.Restore(context);
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) || ArgForce;
var architecture = DetectArchitecture(context.Executable);
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("Installing files... ");
CopyAll(new DirectoryInfo(context.DataPathSrc), new DirectoryInfo(context.DataPathDst), force,
backup,
(from, to) => NativePluginInterceptor(from, to, new DirectoryInfo(nativePluginFolder), isFlat,
architecture));
CopyAll(new DirectoryInfo(context.LibsPathSrc), new DirectoryInfo(context.LibsPathDst), force,
backup,
(from, to) => NativePluginInterceptor(from, to, new DirectoryInfo(nativePluginFolder), isFlat,
architecture));
CopyAll(new DirectoryInfo(context.IPARoot), new DirectoryInfo(context.ProjectRoot), force,
backup,
null, false);
//backup.Add(context.AssemblyFile); //backup.Add(context.AssemblyFile);
//backup.Add(context.EngineFile); //backup.Add(context.EngineFile);
}
#region Create Plugin Folder #region Create Plugin Folder
@ -278,24 +181,6 @@ namespace IPA
#endregion #endregion
#region Virtualizing
if (ArgDestructive && File.Exists(context.AssemblyFile))
{
var virtualizedModule = VirtualizedModule.Load(context.AssemblyFile);
if (!virtualizedModule.IsVirtualized)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Virtualizing Assembly-Csharp.dll... ");
backup.Add(context.AssemblyFile);
virtualizedModule.Virtualize();
Console.WriteLine("Done!");
Console.ResetColor();
}
}
#endregion
} }
catch (Exception e) catch (Exception e)
{ {


+ 1
- 1
IPA/obj/Debug/IPA.csproj.CoreCompileInputs.cache View File

@ -1 +1 @@
27a27b93f9cca058d6b4f09d77cb8a300416a979
7adf61ed0901354b09d9632d801b1671b9c38345

Loading…
Cancel
Save