/// <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)"); } } }
/// <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!"); } }
/// <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); }
/// <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); }
/// <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; } } } }
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); } }
/// <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); }
/// <summary> /// Applied to MainMenu to run postload handlers. /// </summary> private static void MainMenu_OnSpawn_Postfix() { PPatchManager.RunAll(RunAt.InMainMenu); }
/// <summary> /// Applied to Db to run postload handlers. /// </summary> private static void Initialize_Postfix() { PPatchManager.RunAll(RunAt.AfterDbInit); }
/// <summary> /// Applied to Game to run postload handlers. /// </summary> private static void Game_OnPrefabInit_Postfix() { PPatchManager.RunAll(RunAt.OnStartGame); }
/// <summary> /// Applied to Game to run postload handlers. /// </summary> private static void Game_DestroyInstances_Postfix() { PPatchManager.RunAll(RunAt.OnEndGame); }