/// <summary>
 /// Runs the method, passing the required parameters if any.
 /// </summary>
 /// <param name="instance">The Harmony instance to use if the method wants to
 /// perform a patch.</param>
 public void Run(HarmonyInstance instance)
 {
     if (PPatchManager.CheckConditions(Descriptor.RequireAssembly, Descriptor.
                                       RequireType, out Type requiredType))
     {
         // Only runs once, no meaningful savings with a delegate
         var paramTypes = Method.GetParameterTypes();
         int len        = paramTypes.Length;
         if (len <= 0)
         {
             // No parameters, static method only
             Method.Invoke(null, null);
         }
         else if (paramTypes[0] == typeof(HarmonyInstance))
         {
             if (len == 1)
             {
                 // Harmony instance parameter
                 Method.Invoke(null, new object[] { instance });
             }
             else if (len == 2 && paramTypes[1] == typeof(Type))
             {
                 // Type parameter
                 Method.Invoke(null, new object[] { instance, requiredType });
             }
         }
         else
         {
             PUtil.LogWarning("Invalid signature for PLibMethod - must have (), " +
                              "(HarmonyInstance), or (HarmonyInstance, Type)");
         }
     }
 }
Exemple #2
0
        /// <summary>
        /// Registers a class containing methods for [PLibPatch] and [PLibMethod] handlers.
        /// All methods, public and private, of the type will be searched for annotations.
        /// However, nested and derived types will not be searched, nor will inherited methods.
        ///
        /// This method cannot be used to register a class from another mod, as the annotations
        /// on those methods would have a different assembly qualified name and would thus
        /// not be recognized.
        /// </summary>
        /// <param name="type">The type to register.</param>
        public static void RegisterPatchClass(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            // Some others used this call before the library was initialized
            if (!PLibInit)
            {
                InitLibrary(false);
                LogWarning("PUtil.InitLibrary was not called before using RegisterPatchClass!");
            }
            int count = 0;

            foreach (var method in type.GetMethods(PPatchManager.FLAGS | BindingFlags.Static))
            {
                foreach (var attrib in method.GetCustomAttributes(true))
                {
                    if (attrib is IPLibAnnotation pm)
                    {
                        PPatchManager.AddHandler(pm.Runtime, pm.CreateInstance(method));
                        count++;
                    }
                }
            }
            if (count > 0)
            {
                PRegistry.LogPatchDebug("Registered {0:D} handler(s) for {1}".F(count,
                                                                                Assembly.GetCallingAssembly().GetNameSafe() ?? "?"));
            }
            else
            {
                PRegistry.LogPatchWarning("RegisterPatchClass could not find any handlers!");
            }
        }
Exemple #3
0
 /// <summary>
 /// Applied to Db to register PLib buildings and run postload handlers.
 /// </summary>
 private static void Initialize_Prefix()
 {
     if (PBuilding.CheckBuildings())
     {
         PBuilding.AddAllTechs();
     }
     PPatchManager.RunAll(RunAt.BeforeDbInit);
 }
Exemple #4
0
 /// <summary>
 /// Applied to Db to run postload handlers.
 /// </summary>
 private static void Initialize_Postfix(bool __state)
 {
     if (__state && PBuilding.RequiresDBInit)
     {
         PBuilding.AddAllTechs();
     }
     PPatchManager.RunAll(RunAt.AfterDbInit);
 }
Exemple #5
0
        /// <summary>
        /// Applied to Db to register PLib buildings and run postload handlers.
        /// </summary>
        private static void Initialize_Prefix(ref bool __state)
        {
            bool needBuilds = PBuilding.CheckBuildings();

            if (needBuilds && !PBuilding.RequiresDBInit)
            {
                PBuilding.AddAllTechs();
            }
            __state = needBuilds;
            PPatchManager.RunAll(RunAt.BeforeDbInit);
        }
        /// <summary>
        /// Applies the patch.
        /// </summary>
        /// <param name="instance">The Harmony instance to use.</param>
        /// <exception cref="InvalidOperationException">If the </exception>
        /// <exception cref="AmbiguousMatchException">If no parameter types were specified,
        /// and multiple options match the method name.</exception>
        public void Run(HarmonyInstance instance)
        {
            if (PPatchManager.CheckConditions(Descriptor.RequireAssembly, Descriptor.
                                              RequireType, out Type requiredType))
            {
                var dest = new HarmonyMethod(Method);
                if (instance == null)
                {
                    throw new ArgumentNullException("instance");
                }
                try {
                    var method = GetTargetMethod(requiredType);
                    switch (GetPatchType())
                    {
                    case HarmonyPatchType.Postfix:
                        instance.Patch(method, postfix: dest);
                        break;

                    case HarmonyPatchType.Prefix:
                        instance.Patch(method, prefix: dest);
                        break;

                    case HarmonyPatchType.Transpiler:
                        instance.Patch(method, transpiler: dest);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException("PatchType");
                    }
                } catch (AmbiguousMatchException e) {
                    // Multi catch or filtering is not available in this version of C#
                    if (!LogIgnoreOnFail(e))
                    {
                        throw;
                    }
                } catch (InvalidOperationException e) {
                    if (!LogIgnoreOnFail(e))
                    {
                        throw;
                    }
                }
            }
        }
Exemple #7
0
        public static void RegisterPostload(PostLoadHandler callback)
        {
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            // Some others used this call before the library was initialized
            if (!PLibInit)
            {
                InitLibrary(false);
                LogWarning("PUtil.InitLibrary was not called before using RegisterPostload!");
            }
            PPatchManager.AddHandler(RunAt.AfterModsLoad, new LegacyPostloadMethod(
                                         callback));
            string name = Assembly.GetCallingAssembly().GetNameSafe();

            if (name != null)
            {
                PRegistry.LogPatchDebug("Registered post-load handler for " + name);
            }
        }
Exemple #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);
        }
Exemple #9
0
 /// <summary>
 /// Applied to MainMenu to run postload handlers.
 /// </summary>
 private static void MainMenu_OnSpawn_Postfix()
 {
     PPatchManager.RunAll(RunAt.InMainMenu);
 }
Exemple #10
0
 /// <summary>
 /// Applied to Db to run postload handlers.
 /// </summary>
 private static void Initialize_Postfix()
 {
     PPatchManager.RunAll(RunAt.AfterDbInit);
 }
Exemple #11
0
 /// <summary>
 /// Applied to Game to run postload handlers.
 /// </summary>
 private static void Game_OnPrefabInit_Postfix()
 {
     PPatchManager.RunAll(RunAt.OnStartGame);
 }
Exemple #12
0
 /// <summary>
 /// Applied to Game to run postload handlers.
 /// </summary>
 private static void Game_DestroyInstances_Postfix()
 {
     PPatchManager.RunAll(RunAt.OnEndGame);
 }