You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.2 KiB

  1. using Mono.Cecil;
  2. using System;
  3. using System.IO;
  4. using System.Reflection;
  5. namespace IPA.Injector
  6. {
  7. internal class VirtualizedModule
  8. {
  9. private readonly FileInfo file;
  10. private ModuleDefinition module;
  11. public static VirtualizedModule Load(string engineFile)
  12. {
  13. return new VirtualizedModule(engineFile);
  14. }
  15. private VirtualizedModule(string assemblyFile)
  16. {
  17. file = new FileInfo(assemblyFile);
  18. LoadModules();
  19. }
  20. private void LoadModules()
  21. {
  22. module = ModuleDefinition.ReadModule(file.FullName);
  23. }
  24. /// <summary>
  25. ///
  26. /// </summary>
  27. public void Virtualize(AssemblyName selfName, Action beforeChangeCallback = null)
  28. {
  29. var changed = false;
  30. var virtualize = true;
  31. foreach (var r in module.AssemblyReferences)
  32. {
  33. if (r.Name == selfName.Name)
  34. {
  35. virtualize = false;
  36. if (r.Version != selfName.Version)
  37. {
  38. r.Version = selfName.Version;
  39. changed = true;
  40. }
  41. }
  42. }
  43. if (virtualize)
  44. {
  45. changed = true;
  46. module.AssemblyReferences.Add(new AssemblyNameReference(selfName.Name, selfName.Version));
  47. foreach (var type in module.Types)
  48. {
  49. VirtualizeType(type);
  50. }
  51. }
  52. if (changed)
  53. {
  54. beforeChangeCallback?.Invoke();
  55. module.Write(file.FullName);
  56. }
  57. }
  58. private void VirtualizeType(TypeDefinition type)
  59. {
  60. if(type.IsSealed)
  61. {
  62. // Unseal
  63. type.IsSealed = false;
  64. }
  65. if (type.IsInterface) return;
  66. if (type.IsAbstract) return;
  67. // These two don't seem to work.
  68. if (type.Name == "SceneControl" || type.Name == "ConfigUI") return;
  69. // Take care of sub types
  70. foreach (var subType in type.NestedTypes)
  71. {
  72. VirtualizeType(subType);
  73. }
  74. foreach (var method in type.Methods)
  75. {
  76. if (method.IsManaged
  77. && method.IsIL
  78. && !method.IsStatic
  79. && !method.IsVirtual
  80. && !method.IsAbstract
  81. && !method.IsAddOn
  82. && !method.IsConstructor
  83. && !method.IsSpecialName
  84. && !method.IsGenericInstance
  85. && !method.HasOverrides)
  86. {
  87. method.IsVirtual = true;
  88. method.IsPublic = true;
  89. method.IsPrivate = false;
  90. method.IsNewSlot = true;
  91. method.IsHideBySig = true;
  92. }
  93. }
  94. foreach (var field in type.Fields)
  95. {
  96. if (field.IsPrivate) field.IsFamily = true;
  97. }
  98. }
  99. }
  100. }