@@ -72,6 +72,9 @@ | |||
<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. | |||
@@ -10,7 +10,7 @@ namespace IPA.Patcher | |||
{ | |||
class PatchedModule | |||
{ | |||
private const string ENTRY_TYPE = "Display"; | |||
private static readonly string[] ENTRY_TYPES = { "Input", "Display" }; | |||
private FileInfo _File; | |||
private ModuleDefinition _Module; | |||
@@ -57,29 +57,43 @@ namespace IPA.Patcher | |||
// First, let's add the reference | |||
var nameReference = new AssemblyNameReference("IllusionInjector", new Version(1, 0, 0, 0)); | |||
var injectorPath = Path.Combine(_File.DirectoryName, "IllusionInjector.dll"); | |||
var injector = ModuleDefinition.ReadModule(injectorPath); | |||
_Module.AssemblyReferences.Add(nameReference); | |||
var targetType = FindEntryType(); | |||
if (targetType == null) throw new Exception("Couldn't find entry class. Aborting."); | |||
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) | |||
if (targetMethod != null) | |||
{ | |||
throw new Exception("Couldn't find entry method. Aborting."); | |||
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; | |||
} | |||
var injector = ModuleDefinition.ReadModule(injectorPath); | |||
var methodReference = _Module.Import(injector.GetType("IllusionInjector.Injector").Methods.First(m => m.Name == "Inject")); | |||
targetMethod.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, methodReference)); | |||
_Module.Write(_File.FullName); | |||
return false; | |||
} | |||
private TypeDefinition FindEntryType() | |||
private IEnumerable<TypeDefinition> FindEntryTypes() | |||
{ | |||
return _Module.GetTypes().FirstOrDefault(m => m.Name == ENTRY_TYPE); | |||
return _Module.GetTypes().Where(m => ENTRY_TYPES.Contains(m.Name)); | |||
} | |||
} | |||
} |
@@ -49,17 +49,25 @@ namespace IPA.Patcher | |||
{ | |||
VirtualizeType(type); | |||
} | |||
_Module.Write(_File.FullName); | |||
} | |||
private void VirtualizeType(TypeDefinition type) | |||
{ | |||
if (type.IsSealed) return; | |||
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.WriteLine("Virtualizing {0}", type.Name); | |||
// Take care of sub types | |||
foreach (var subType in type.NestedTypes) | |||
{ | |||
@@ -97,7 +105,10 @@ namespace IPA.Patcher | |||
{ | |||
get | |||
{ | |||
return _Module.GetTypes().SelectMany(t => t.Methods.Where(m => m.Name == "Awake")).All(m => m.IsVirtual); | |||
var awakeMethods = _Module.GetTypes().SelectMany(t => t.Methods.Where(m => m.Name == "Awake")); | |||
if (awakeMethods.Count() == 0) return false; | |||
return ((float)awakeMethods.Count(m => m.IsVirtual) / awakeMethods.Count()) > 0.5f; | |||
} | |||
} | |||
} | |||
@@ -20,7 +20,7 @@ namespace IPA | |||
string managedFolder = Path.Combine("IPA", "Managed"); | |||
string pluginsFolder = "Plugins"; | |||
string projectName = Path.GetFileNameWithoutExtension(args[0]); | |||
string dataPath = Path.Combine(Path.Combine(Environment.CurrentDirectory, projectName + "_Data"), "Managed"); | |||
string dataPath = Path.Combine(Path.Combine(Path.GetDirectoryName(args[0]), projectName + "_Data"), "Managed"); | |||
string engineFile = Path.Combine(dataPath, "UnityEngine.dll"); | |||
string assemblyFile = Path.Combine(dataPath, "Assembly-Csharp.dll"); | |||
@@ -35,11 +35,13 @@ namespace IPA | |||
try | |||
{ | |||
// Copying | |||
Console.Write("Updating files... "); | |||
CopyAll(new DirectoryInfo(managedFolder), new DirectoryInfo(dataPath)); | |||
Console.WriteLine("Successfully copied files!"); | |||
Console.WriteLine("Successfully updated files!"); | |||
if(!Directory.Exists(pluginsFolder)) | |||
if (!Directory.Exists(pluginsFolder)) | |||
{ | |||
Console.WriteLine("Creating plugins folder... "); | |||
Directory.CreateDirectory(pluginsFolder); | |||
} | |||
@@ -47,21 +49,27 @@ namespace IPA | |||
var patchedModule = PatchedModule.Load(engineFile); | |||
if(!patchedModule.IsPatched) | |||
{ | |||
Console.Write("Patching UnityEngine.dll... "); | |||
BackupManager.MakeBackup(engineFile); | |||
patchedModule.Patch(); | |||
Console.WriteLine("Done!"); | |||
} | |||
// Virtualizing | |||
var virtualizedModule = VirtualizedModule.Load(assemblyFile); | |||
if(!virtualizedModule.IsVirtualized) | |||
{ | |||
Console.Write("Virtualizing Assembly-Csharp.dll... "); | |||
BackupManager.MakeBackup(assemblyFile); | |||
virtualizedModule.Virtualize(); | |||
Console.WriteLine("Done!"); | |||
} | |||
} catch(Exception e) | |||
{ | |||
Fail("Oops! This should not have happened.\n\n" + e); | |||
} | |||
Console.WriteLine("Finished!"); | |||
} | |||
public static void CopyAll(DirectoryInfo source, DirectoryInfo target) | |||