Beispiel #1
0
        /// <summary>
        /// Initializes the patch bootstrapper, creating a PLibPatchRegistry if not yet
        /// present and offering our library as a candidate for shared patches.
        /// </summary>
        public static void Init()
        {
            var obj = Global.Instance.gameObject;

            if (obj != null)
            {
                // The hack is sick but we have few choices
                object reg = obj.GetComponent(typeof(PRegistry).Name);
                if (reg == null)
                {
                    var plr = obj.AddComponent <PRegistry>();
                    // If PLib is ILMerged more than once, PRegistry gets added with a weird
                    // type name including a GUID which does not match GetComponent.Name!
                    string typeName = plr.GetType().Name;
                    if (typeName != "PRegistry")
                    {
                        Debug.LogErrorFormat("PRegistry has the type name {0}; this may be " +
                                             "the result of ILMerging PLib more than once!", typeName);
                    }
#if DEBUG
                    LogPatchDebug("Creating PLibRegistry from " + Assembly.
                                  GetExecutingAssembly().FullName);
#endif
                    // Patch in the bootstrap method
                    plr.ApplyBootstrapper();
                    reg = plr;
                }
                // Use reflection to execute the actual AddPatch method
                try {
                    Traverse.Create(reg).CallMethod(nameof(PRegistry.AddPatch),
                                                    (object)new PLibPatches());
                } catch (Exception e) {
                    PUtil.LogException(e);
                }
            }
            else
            {
#if DEBUG
                LogPatchWarning("Attempted to Init before Global created!");
#endif
            }
        }
Beispiel #2
0
        /// <summary>
        /// Creates a ModInfoAttribute using an object from another mod.
        /// </summary>
        /// <param name="attr">The attribute from the other mod.</param>
        /// <returns>A ModInfoAttribute object with the values from that object, where
        /// possible to retrieve; or null if none could be obtained.</returns>
        internal static ModInfoAttribute CreateFrom(object attr)
        {
            string title = null, image = null, url = null;
            bool   collapse = false;

            if (attr.GetType().Name == typeof(ModInfoAttribute).Name)
            {
                var trAttr = Traverse.Create(attr);
                try {
                    title    = trAttr.GetProperty <string>(nameof(Title));
                    image    = trAttr.GetProperty <string>(nameof(Image));
                    url      = trAttr.GetProperty <string>(nameof(URL));
                    collapse = trAttr.GetProperty <bool>(nameof(ForceCollapseCategories));
                } catch (Exception e) {
                    PUtil.LogExcWarn(e);
                }
            }
            return(string.IsNullOrEmpty(title) ? null : new ModInfoAttribute(title, url,
                                                                             image, collapse));
        }
Beispiel #3
0
        /// <summary>
        /// Creates an OptionAttribute using an object from another mod.
        /// </summary>
        /// <param name="attr">The attribute from the other mod.</param>
        /// <returns>An OptionAttribute object with the values from that object, where
        /// possible to retrieve; or null if none could be obtained.</returns>
        internal static OptionAttribute CreateFrom(object attr)
        {
            string title = "", tt = "", cat = "", format = null;

            if (attr.GetType().Name == typeof(OptionAttribute).Name)
            {
                var trAttr = Traverse.Create(attr);
                try {
                    title  = trAttr.GetProperty <string>(nameof(Title));
                    tt     = trAttr.GetProperty <string>(nameof(Tooltip)) ?? "";
                    cat    = trAttr.GetProperty <string>(nameof(Category)) ?? "";
                    format = trAttr.GetProperty <string>(nameof(Format));
                } catch (Exception e) {
                    PUtil.LogExcWarn(e);
                }
            }
            return(string.IsNullOrEmpty(title) ? null : new OptionAttribute(title, tt, cat)
            {
                Format = format
            });
        }
Beispiel #4
0
        /// <summary>
        /// Retrieves a type using its full name (including namespace). However, the assembly
        /// name is optional, as this method searches all assemblies in the current
        /// AppDomain if it is null or empty.
        /// </summary>
        /// <param name="name">The type name to retrieve.</param>
        /// <param name="assemblyName">If specified, the name of the assembly that contains
        /// the type. No other assembly name will be searched if this parameter is not null
        /// or empty. The assembly name might not match the DLL name, use a decompiler to
        /// make sure.</param>
        /// <returns>The type, or null if the type is not found or cannot be loaded.</returns>
        public static Type GetTypeSafe(string name, string assemblyName = null)
        {
            Type type = null;

            if (string.IsNullOrEmpty(assemblyName))
            {
                foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
                {
                    try {
                        type = assembly.GetType(name, false);
                    } catch (System.IO.IOException) {
                        // The common parent of exceptions when the type requires another type
                        // that cannot be loaded
                    } catch (BadImageFormatException) { }
                    if (type != null)
                    {
                        break;
                    }
                }
            }
            else
            {
                try {
                    type = Type.GetType(name + ", " + assemblyName, false);
                } catch (TargetInvocationException e) {
                    PUtil.LogWarning("Unable to load type {0} from assembly {1}:".F(name,
                                                                                    assemblyName));
                    PUtil.LogExcWarn(e);
                } catch (ArgumentException e) {
                    // A generic type is loaded with bad arguments
                    PUtil.LogWarning("Unable to load type {0} from assembly {1}:".F(name,
                                                                                    assemblyName));
                    PUtil.LogExcWarn(e);
                } catch (System.IO.IOException) {
                    // The common parent of exceptions when the type requires another type that
                    // cannot be loaded
                } catch (BadImageFormatException) { }
            }
            return(type);
        }
Beispiel #5
0
        /// <summary>
        /// Creates a LimitAttribute using an object from another mod.
        /// </summary>
        /// <param name="attr">The attribute from the other mod.</param>
        /// <returns>A LimitAttribute object with the values from that object, where
        /// possible to retrieve; or null if none could be obtained.</returns>
        private static LimitAttribute CreateFrom(object attr)
        {
            LimitAttribute la = null;

            if (attr.GetType().Name == typeof(LimitAttribute).Name)
            {
                // Has limit type
                var    trAttr = Traverse.Create(attr);
                double min = 0.0, max = 0.0;
                try {
                    min = trAttr.GetProperty <double>(nameof(Minimum));
                    max = trAttr.GetProperty <double>(nameof(Maximum));
                } catch (Exception e) {
                    PUtil.LogExcWarn(e);
                }
                if (min != 0.0 || max != 0.0)
                {
                    la = new LimitAttribute(min, max);
                }
            }
            return(la);
        }
Beispiel #6
0
        /// <summary>
        /// Executes all legacy post-load handlers.
        /// </summary>
        internal static void ExecuteLegacyPostload()
        {
            IList <PostLoadHandler> postload = null;

            lock (PSharedData.GetLock(PRegistry.KEY_POSTLOAD_LOCK)) {
                // Get list holding postload information
                var list = PSharedData.GetData <IList <PostLoadHandler> >(PRegistry.
                                                                          KEY_POSTLOAD_TABLE);
                if (list != null)
                {
                    postload = new List <PostLoadHandler>(list);
                }
            }
            // If there were any, run them
            if (postload != null)
            {
                var hInst = HarmonyInstance.Create("PLib.PostLoad");
                PRegistry.LogPatchDebug("Executing {0:D} legacy post-load handler(s)".F(
                                            postload.Count));
                foreach (var handler in postload)
                {
                    try {
                        handler?.Invoke(hInst);
                    } catch (Exception e) {
                        var method = handler.Method;
                        // Say which mod's postload crashed
                        if (method != null)
                        {
                            PRegistry.LogPatchWarning("Postload handler for mod {0} failed:".F(
                                                          method.DeclaringType.Assembly?.GetName()?.Name ?? "?"));
                        }
                        PUtil.LogException(e);
                    }
                }
            }
        }
Beispiel #7
0
 /// <summary>
 /// Patches a constructor manually.
 /// </summary>
 /// <param name="instance">The Harmony instance.</param>
 /// <param name="type">The class to modify.</param>
 /// <param name="arguments">The constructor's argument types.</param>
 /// <param name="prefix">The prefix to apply, or null if none.</param>
 /// <param name="postfix">The postfix to apply, or null if none.</param>
 public static void PatchConstructor(this HarmonyInstance instance, Type type,
                                     Type[] arguments, HarmonyMethod prefix = null, HarmonyMethod postfix = null)
 {
     if (type == null)
     {
         throw new ArgumentNullException("type");
     }
     // Fetch the constructor
     try {
         var cons = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public |
                                        BindingFlags.Static | BindingFlags.Instance, null, arguments, null);
         if (cons != null)
         {
             instance.Patch(cons, prefix, postfix);
         }
         else
         {
             PUtil.LogWarning("Unable to find constructor on type {0}".F(type.
                                                                         FullName));
         }
     } catch (ArgumentException e) {
         PUtil.LogException(e);
     }
 }
Beispiel #8
0
        /// <summary>
        /// Applies all patches.
        /// </summary>
        /// <param name="instance">The Harmony instance to use when patching.</param>
        private static void PatchAll(HarmonyInstance instance)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            // ColonyAchievementStatus
            instance.Patch(typeof(ColonyAchievementStatus), "Serialize",
                           PatchMethod(nameof(Serialize_Prefix)), null);

            // Db
            instance.Patch(typeof(Db), "Initialize", PatchMethod(nameof(Initialize_Prefix)),
                           PatchMethod(nameof(Initialize_Postfix)));

            // Game
            instance.Patch(typeof(Game), "DestroyInstances", null, PatchMethod(nameof(
                                                                                   Game_DestroyInstances_Postfix)));
            instance.Patch(typeof(Game), "OnPrefabInit", null, PatchMethod(nameof(
                                                                               Game_OnPrefabInit_Postfix)));

            // GameInputMapping
            instance.Patch(typeof(GameInputMapping), "SetDefaultKeyBindings", null,
                           PatchMethod(nameof(SetDefaultKeyBindings_Postfix)));

            // GameUtil
            instance.Patch(typeof(GameUtil), "GetKeycodeLocalized",
                           PatchMethod(nameof(GetKeycodeLocalized_Prefix)), null);

            // KInputController
            instance.PatchConstructor(typeof(KInputController.KeyDef), new Type[] {
                typeof(KKeyCode), typeof(Modifier)
            }, null, PatchMethod(nameof(CKeyDef_Postfix)));
            instance.Patch(typeof(KInputController), "IsActive",
                           PatchMethod(nameof(IsActive_Prefix)), null);
            instance.Patch(typeof(KInputController), "QueueButtonEvent",
                           PatchMethod(nameof(QueueButtonEvent_Prefix)), null);

            if (PLightManager.InitInstance())
            {
                // DiscreteShadowCaster
                instance.Patch(typeof(DiscreteShadowCaster), "GetVisibleCells",
                               PatchMethod(nameof(GetVisibleCells_Prefix)), null);

                // Light2D
                instance.Patch(typeof(Light2D), "AddToScenePartitioner",
                               PatchMethod(nameof(AddToScenePartitioner_Prefix)), null);
                instance.Patch(typeof(Light2D), "RefreshShapeAndPosition", null,
                               PatchMethod(nameof(RefreshShapeAndPosition_Postfix)));

                // LightGridEmitter
                instance.Patch(typeof(LightGridEmitter), "AddToGrid", null,
                               PatchMethod(nameof(AddToGrid_Postfix)));
                instance.Patch(typeof(LightGridEmitter), "ComputeLux",
                               PatchMethod(nameof(ComputeLux_Prefix)), null);
                instance.Patch(typeof(LightGridEmitter), "RemoveFromGrid",
                               null, PatchMethod(nameof(RemoveFromGrid_Postfix)));
                instance.Patch(typeof(LightGridEmitter), "UpdateLitCells",
                               PatchMethod(nameof(UpdateLitCells_Prefix)), null);

                // LightGridManager
                instance.Patch(typeof(LightGridManager), "CreatePreview",
                               PatchMethod(nameof(CreatePreview_Prefix)), null);

                // LightShapePreview
                instance.Patch(typeof(LightShapePreview), "Update",
                               PatchMethod(nameof(LightShapePreview_Update_Prefix)), null);

                // Rotatable
                instance.Patch(typeof(Rotatable), "OrientVisualizer", null,
                               PatchMethod(nameof(OrientVisualizer_Postfix)));
            }

            // MainMenu
            instance.Patch(typeof(MainMenu), "OnSpawn", null, PatchMethod(
                               nameof(MainMenu_OnSpawn_Postfix)));

            // PBuilding
            instance.Patch(typeof(BuildingTemplates), "CreateBuildingDef", null,
                           PatchMethod(nameof(CreateBuildingDef_Postfix)));
            instance.Patch(typeof(EquipmentTemplates), "CreateEquipmentDef", null,
                           PatchMethod(nameof(CreateEquipmentDef_Postfix)));
            if (PBuilding.CheckBuildings())
            {
                instance.Patch(typeof(GeneratedBuildings), "LoadGeneratedBuildings",
                               PatchMethod(nameof(LoadGeneratedBuildings_Prefix)), null);
            }

            // PCodex
            instance.Patch(typeof(CodexCache), "CollectEntries", null,
                           PatchMethod(nameof(CollectEntries_Postfix)));
            instance.Patch(typeof(CodexCache), "CollectSubEntries", null,
                           PatchMethod(nameof(CollectSubEntries_Postfix)));

            // PLocalization
            var locale = Localization.GetLocale();

            if (locale != null)
            {
                PLocalization.LocalizeAll(locale);
            }

            // ModsScreen
            POptions.Init();
            instance.Patch(typeof(ModsScreen), "BuildDisplay", null,
                           PatchMethod(nameof(BuildDisplay_Postfix)));

            // SteamUGCService
            var ugc = PPatchTools.GetTypeSafe("SteamUGCService", "Assembly-CSharp");

            if (ugc != null)
            {
                try {
                    instance.PatchTranspile(ugc, "LoadPreviewImage", PatchMethod(nameof(
                                                                                     LoadPreviewImage_Transpile)));
                } catch (Exception e) {
                    PUtil.LogExcWarn(e);
                }
            }

            // TMPro.TMP_InputField
            try {
                instance.Patch(typeof(TMPro.TMP_InputField), "OnEnable", null,
                               PatchMethod(nameof(OnEnable_Postfix)));
            } catch (Exception) {
                PUtil.LogWarning("Unable to patch TextMeshPro bug, text fields may display " +
                                 "improperly inside scroll areas");
            }

            // Postload, legacy and normal
            PPatchManager.ExecuteLegacyPostload();
            PPatchManager.RunAll(RunAt.AfterModsLoad);
        }
Beispiel #9
0
        /// <summary>
        /// Applies all patches.
        /// </summary>
        /// <param name="instance">The Harmony instance to use when patching.</param>
        private static void PatchAll(HarmonyInstance instance)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            // ColonyAchievementStatus
            instance.Patch(typeof(ColonyAchievementStatus), "Serialize",
                           PatchMethod(nameof(Serialize_Prefix)), null);

            // GameInputMapping
            instance.Patch(typeof(GameInputMapping), "SetDefaultKeyBindings", null,
                           PatchMethod(nameof(SetDefaultKeyBindings_Postfix)));

            // KInputController
            instance.PatchConstructor(typeof(KInputController.KeyDef), new Type[] {
                typeof(KKeyCode), typeof(Modifier)
            }, null, PatchMethod(nameof(CKeyDef_Postfix)));
            instance.Patch(typeof(KInputController), "IsActive",
                           PatchMethod(nameof(IsActive_Prefix)), null);
            instance.Patch(typeof(KInputController), "QueueButtonEvent",
                           PatchMethod(nameof(QueueButtonEvent_Prefix)), null);

            if (PLightManager.InitInstance())
            {
                // DiscreteShadowCaster
                instance.Patch(typeof(DiscreteShadowCaster), "GetVisibleCells",
                               PatchMethod(nameof(GetVisibleCells_Prefix)), null);

                // Light2D
                instance.Patch(typeof(Light2D), "AddToScenePartitioner",
                               PatchMethod(nameof(AddToScenePartitioner_Prefix)), null);
                instance.Patch(typeof(Light2D), "RefreshShapeAndPosition", null,
                               PatchMethod(nameof(RefreshShapeAndPosition_Postfix)));

                // LightGridEmitter
                instance.Patch(typeof(LightGridEmitter), "AddToGrid", null,
                               PatchMethod(nameof(AddToGrid_Postfix)));
                instance.Patch(typeof(LightGridEmitter), "ComputeLux",
                               PatchMethod(nameof(ComputeLux_Prefix)), null);
                instance.Patch(typeof(LightGridEmitter), "RemoveFromGrid",
                               null, PatchMethod(nameof(RemoveFromGrid_Postfix)));
                instance.Patch(typeof(LightGridEmitter), "UpdateLitCells",
                               PatchMethod(nameof(UpdateLitCells_Prefix)), null);

                // LightGridManager
                instance.Patch(typeof(LightGridManager), "CreatePreview",
                               PatchMethod(nameof(CreatePreview_Prefix)), null);

                // LightShapePreview
                instance.Patch(typeof(LightShapePreview), "Update",
                               PatchMethod(nameof(LightShapePreview_Update_Prefix)), null);

                // Rotatable
                instance.Patch(typeof(Rotatable), "OrientVisualizer", null,
                               PatchMethod(nameof(OrientVisualizer_Postfix)));
            }

            // PBuilding
            instance.Patch(typeof(BuildingTemplates), "CreateBuildingDef", null,
                           PatchMethod(nameof(CreateBuildingDef_Postfix)));
            instance.Patch(typeof(EquipmentTemplates), "CreateEquipmentDef", null,
                           PatchMethod(nameof(CreateEquipmentDef_Postfix)));
            if (PBuilding.CheckBuildings())
            {
                instance.Patch(typeof(Db), "Initialize",
                               PatchMethod(nameof(Initialize_Prefix)), null);
                instance.Patch(typeof(GeneratedBuildings), "LoadGeneratedBuildings",
                               PatchMethod(nameof(LoadGeneratedBuildings_Prefix)), null);
            }

            // PCodex
            instance.Patch(typeof(CodexCache), "CollectEntries", null,
                           PatchMethod(nameof(CollectEntries_Postfix)));
            instance.Patch(typeof(CodexCache), "CollectSubEntries", null,
                           PatchMethod(nameof(CollectSubEntries_Postfix)));

            // PLocalization
            var locale = Localization.GetLocale();

            if (locale != null)
            {
                PLocalization.LocalizeAll(locale);
            }

            // ModsScreen
            POptions.Init();
            instance.Patch(typeof(ModsScreen), "BuildDisplay", null,
                           PatchMethod(nameof(BuildDisplay_Postfix)));

            // SteamUGCService
            try {
                instance.PatchTranspile(typeof(SteamUGCService), "LoadPreviewImage",
                                        PatchMethod(nameof(LoadPreviewImage_Transpile)));
            } catch (TypeLoadException) {
                // Not a Steam install, ignoring
            }

            // Postload
            PUtil.ExecutePostload();
        }
Beispiel #10
0
        /// <summary>
        /// Transpiles a method to replace calls to the specified victim methods with
        /// replacement methods, altering the call type if necessary.
        ///
        /// Each key to value pair must meet the criteria defined in
        /// ReplaceMethodCall(TranspiledMethod, MethodInfo, MethodInfo).
        /// </summary>
        /// <param name="method">The method to patch.</param>
        /// <param name="translation">A mapping from the old method calls to replace, to the
        /// new method calls to use instead.</param>
        /// <returns>A transpiled version of that method that replaces or removes all calls
        /// to the specified methods.</returns>
        /// <exception cref="ArgumentException">If any of the new methods' argument types do
        /// not exactly match the old methods' argument types.</exception>
        public static TranspiledMethod ReplaceMethodCall(TranspiledMethod method,
                                                         IDictionary <MethodInfo, MethodInfo> translation)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }
            if (translation == null)
            {
                throw new ArgumentNullException("translation");
            }
            // Sanity check arguments
            int replaced = 0;

            foreach (var pair in translation)
            {
                var victim    = pair.Key;
                var newMethod = pair.Value;
                if (victim == null)
                {
                    throw new ArgumentNullException("victim");
                }
                if (newMethod != null)
                {
                    PTranspilerTools.CompareMethodParams(victim, victim.GetParameterTypes(),
                                                         newMethod);
                }
                else if (victim.ReturnType != typeof(void))
                {
                    throw new ArgumentException("Cannot remove method {0} with a return value".
                                                F(victim.Name));
                }
            }
            foreach (var instruction in method)
            {
                var        opcode = instruction.opcode;
                MethodInfo target;
                if ((opcode == OpCodes.Call || opcode == OpCodes.Calli || opcode == OpCodes.
                     Callvirt) && translation.TryGetValue(target = instruction.operand as
                                                                   MethodInfo, out MethodInfo newMethod))
                {
                    if (newMethod != null)
                    {
                        // Replace with new method
                        instruction.opcode = newMethod.IsStatic ? OpCodes.Call :
                                             OpCodes.Callvirt;
                        instruction.operand = newMethod;
                        yield return(instruction);
                    }
                    else
                    {
                        // Pop "this" if needed
                        int n = target.GetParameters().Length;
                        if (!target.IsStatic)
                        {
                            n++;
                        }
                        // Pop the arguments off the stack
                        instruction.opcode  = (n == 0) ? OpCodes.Nop : OpCodes.Pop;
                        instruction.operand = null;
                        yield return(instruction);

                        for (int i = 0; i < n - 1; i++)
                        {
                            yield return(new CodeInstruction(OpCodes.Pop));
                        }
                    }
                    replaced++;
                }
                else
                {
                    yield return(instruction);
                }
            }
#if DEBUG
            if (replaced == 0)
            {
                if (translation.Count == 1)
                {
                    // Diagnose the method that could not be replaced
                    var items = new KeyValuePair <MethodInfo, MethodInfo> [1];
                    translation.CopyTo(items, 0);
                    MethodInfo from = items[0].Key, to = items[0].Value;
                    PUtil.LogWarning("No method calls replaced: {0}.{1} to {2}.{3}".F(
                                         from.DeclaringType.FullName, from.Name, to.DeclaringType.FullName,
                                         to.Name));
                }
                else
                {
                    PUtil.LogWarning("No method calls replaced (multiple replacements)");
                }
            }
#endif
        }
Beispiel #11
0
 public static void LogAllFailedAsserts()
 {
     PUtil.LogWarning("PLib in mod " + Assembly.GetCallingAssembly().GetName()?.Name +
                      " is logging ALL failed assertions!");
     PTranspilerTools.LogAllFailedAsserts();
 }
Beispiel #12
0
 public static void LogAllExceptions()
 {
     PUtil.LogWarning("PLib in mod " + Assembly.GetCallingAssembly().GetName()?.Name +
                      " is logging ALL unhandled exceptions!");
     PTranspilerTools.LogAllExceptions();
 }
Beispiel #13
0
        /// <summary>
        /// Applies all patches.
        /// </summary>
        /// <param name="instance">The Harmony instance to use when patching.</param>
        private static void PatchAll(HarmonyInstance instance)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            // GameInputMapping
            instance.Patch(typeof(GameInputMapping), "SetDefaultKeyBindings", null,
                           PatchMethod("SetDefaultKeyBindings_Postfix"));

            // KInputController
            instance.PatchConstructor(typeof(KInputController.KeyDef), new Type[] {
                typeof(KKeyCode), typeof(Modifier)
            }, null, PatchMethod("CKeyDef_Postfix"));
            instance.Patch(typeof(KInputController), "IsActive",
                           PatchMethod("IsActive_Prefix"), null);
            instance.Patch(typeof(KInputController), "QueueButtonEvent",
                           PatchMethod("QueueButtonEvent_Prefix"), null);

            if (PLightManager.InitInstance())
            {
                // DiscreteShadowCaster
                instance.Patch(typeof(DiscreteShadowCaster), "GetVisibleCells",
                               PatchMethod("GetVisibleCells_Prefix"), null);

                // Light2D
                instance.Patch(typeof(Light2D), "AddToScenePartitioner",
                               PatchMethod("AddToScenePartitioner_Prefix"), null);
                instance.Patch(typeof(Light2D), "RefreshShapeAndPosition", null,
                               PatchMethod("RefreshShapeAndPosition_Postfix"));

                // LightGridEmitter
                instance.Patch(typeof(LightGridEmitter), "AddToGrid", null,
                               PatchMethod("AddToGrid_Postfix"));
                instance.Patch(typeof(LightGridEmitter), "ComputeLux",
                               PatchMethod("ComputeLux_Prefix"), null);
                instance.Patch(typeof(LightGridEmitter), "RemoveFromGrid",
                               null, PatchMethod("RemoveFromGrid_Postfix"));
                instance.Patch(typeof(LightGridEmitter), "UpdateLitCells",
                               PatchMethod("UpdateLitCells_Prefix"), null);

                // LightGridManager
                instance.Patch(typeof(LightGridManager), "CreatePreview",
                               PatchMethod("CreatePreview_Prefix"), null);

                // LightShapePreview
                instance.Patch(typeof(LightShapePreview), "Update",
                               PatchMethod("LightShapePreview_Update_Prefix"), null);

                // Rotatable
                instance.Patch(typeof(Rotatable), "OrientVisualizer", null,
                               PatchMethod("OrientVisualizer_Postfix"));
            }

            // ModsScreen
            POptions.Init();
            instance.Patch(typeof(ModsScreen), "BuildDisplay", null,
                           PatchMethod("BuildDisplay_Postfix"));

            // SteamUGCService
            try {
                instance.PatchTranspile(typeof(SteamUGCService), "LoadPreviewImage",
                                        PatchMethod("LoadPreviewImage_Transpile"));
            } catch (TypeLoadException) {
                // Not a Steam install, ignoring
            }

            // Postload
            PUtil.ExecutePostload();
        }
Beispiel #14
0
        /// <summary>
        /// Transpiles a method to replace all calls to the specified victim method with
        /// another method, altering the call type if necessary. The argument types and return
        /// type must match exactly, including in/out/ref parameters.
        ///
        /// If replacing an instance method call with a static method, the first argument
        /// will receive the "this" which the old method would have received.
        ///
        /// If newMethod is null, the calls will all be removed silently instead. This will
        /// fail if the method call being removed had a return type (what would it be replaced
        /// with?); in those cases, declare an empty method with the same signature and
        /// replace it instead.
        /// </summary>
        /// <param name="method">The method to patch.</param>
        /// <param name="victim">The old method calls to remove.</param>
        /// <param name="newMethod">The new method to replace, or null to delete the calls.</param>
        /// <returns>A transpiled version of that method that replaces or removes all calls
        /// to method.</returns>
        /// <exception cref="ArgumentException">If the new method's argument types do not
        /// exactly match the old method's argument types.</exception>
        public static TranspiledMethod ReplaceMethodCall(TranspiledMethod method,
                                                         MethodInfo victim, MethodInfo newMethod = null)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }
            if (victim == null)
            {
                throw new ArgumentNullException("victim");
            }
            // Sanity check arguments
            var types = victim.GetParameterTypes();
            int n = types.Length, replaced = 0;

            if (newMethod != null)
            {
                CompareMethodParams(victim, types, newMethod);
            }
            else if (victim.ReturnType != typeof(void))
            {
                throw new ArgumentException("Cannot remove method {0} with a return value".F(
                                                victim.Name));
            }
            // Pop "this" in removal cases
            if (!victim.IsStatic)
            {
                n++;
            }
            foreach (var instruction in method)
            {
                var opcode = instruction.opcode;
                if ((opcode == OpCodes.Call || opcode == OpCodes.Calli || opcode == OpCodes.
                     Callvirt) && instruction.operand == victim)
                {
                    if (newMethod != null)
                    {
                        // Replace with new method
                        instruction.opcode = newMethod.IsStatic ? OpCodes.Call :
                                             OpCodes.Callvirt;
                        instruction.operand = newMethod;
                        yield return(instruction);
                    }
                    else
                    {
                        // Pop the arguments off the stack
                        instruction.opcode  = (n == 0) ? OpCodes.Nop : OpCodes.Pop;
                        instruction.operand = null;
                        yield return(instruction);

                        for (int i = 0; i < n - 1; i++)
                        {
                            yield return(new CodeInstruction(OpCodes.Pop));
                        }
                    }
                    replaced++;
                }
                else
                {
                    yield return(instruction);
                }
            }
#if DEBUG
            if (replaced == 0)
            {
                PUtil.LogWarning("No method calls replaced: {0}.{1} to {2}.{3}".F(victim.
                                                                                  DeclaringType.Name, victim.Name, newMethod?.DeclaringType?.Name ?? "None",
                                                                                  newMethod?.Name));
            }
#endif
        }
Beispiel #15
0
 static PAction()
 {
     // Enum.TryParse was introduced in .NET Framework 4.0
     MaxAction = PUtil.TryParseEnum("NumActions", Action.NumActions);
 }