using Mono.Cecil; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace IPA.Patcher { class VirtualizedModule { private const string ENTRY_TYPE = "Display"; private 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); } /// /// /// /// public void Virtualize() { foreach (var type in _Module.Types) { VirtualizeType(type); } _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.WriteLine("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")); if (awakeMethods.Count() == 0) return false; return ((float)awakeMethods.Count(m => m.IsVirtual) / awakeMethods.Count()) > 0.5f; } } } }