public override void Entry(IModHelper helper) { ModConfig = helper.ReadConfig <ModConfig>(); helper.WriteConfig(ModConfig); HarmonyInstance harmony = HarmonyInstance.Create("zaneyork.CustomToolEffect"); harmony.Patch( original: AccessTools.DeclaredMethod(typeof(Tree), "performToolAction"), prefix: new HarmonyMethod(typeof(TreeRewrites.PerformToolActionRewrite), nameof(TreeRewrites.PerformToolActionRewrite.Prefix)) ); harmony.Patch( original: AccessTools.DeclaredMethod(typeof(FruitTree), "performToolAction"), prefix: new HarmonyMethod(typeof(FruitTreeRewrites.PerformToolActionRewrite), nameof(FruitTreeRewrites.PerformToolActionRewrite.Prefix)) ); harmony.Patch( original: AccessTools.DeclaredMethod(typeof(ResourceClump), "performToolAction"), prefix: new HarmonyMethod(typeof(ResourceClumpRewrites.PerformToolActionRewrite), nameof(ResourceClumpRewrites.PerformToolActionRewrite.Prefix)) ); harmony.Patch( original: AccessTools.DeclaredMethod(typeof(Pickaxe), "DoFunction"), prefix: new HarmonyMethod(typeof(PickaxeRewrites.DoFunctionRewrite), nameof(PickaxeRewrites.DoFunctionRewrite.Prefix)) ); harmony.Patch( original: AccessTools.DeclaredMethod(typeof(Tool), "tilesAffected"), prefix: new HarmonyMethod(typeof(ToolRewrites.TilesAffectedRewrite), nameof(ToolRewrites.TilesAffectedRewrite.Prefix)) ); AccessTools.GetDeclaredConstructors(typeof(TemporaryAnimatedSprite)).ForEach(ctor => { harmony.Patch( original: ctor, postfix: new HarmonyMethod(typeof(ToolRewrites.TilesAffectedRewrite), nameof(TemporaryAnimatedSpriteRewrites.ConstructorRewrite.Postfix)) ); }); }
public CashRegister(ModContentPack mod) { var type = AccessTools.TypeByName("CashRegister.Shifts.ITab_Register_Shifts"); MpCompat.RegisterLambdaMethod(type, "GetGizmos", 1).SetContext(SyncContext.MapSelected); MP.RegisterSyncWorker <object>(NoSync, type, shouldConstruct: true); MP.RegisterSyncMethod(typeof(CashRegister), nameof(SyncedSetShifts)).ExposeParameter(1).ExposeParameter(2).ExposeParameter(3).ExposeParameter(4).ExposeParameter(5).MinTime(100); MpCompat.harmony.Patch(AccessTools.Method(type, "FillTab"), prefix: new HarmonyMethod(typeof(CashRegister), nameof(PreFillTab)), postfix: new HarmonyMethod(typeof(CashRegister), nameof(PostFillTab))); type = AccessTools.TypeByName("CashRegister.Gizmo_Radius"); gizmoRadiusConstructor = AccessTools.GetDeclaredConstructors(type).First(x => x.GetParameters().Length == 1); gizmoSelectionField = AccessTools.FieldRefAccess <Building[]>(type, "selection"); MP.RegisterSyncMethod(AccessTools.DeclaredMethod(type, "ButtonDown")); MP.RegisterSyncMethod(AccessTools.DeclaredMethod(type, "ButtonUp")); MP.RegisterSyncMethod(AccessTools.DeclaredMethod(type, "ButtonCenter")); MP.RegisterSyncWorker <Gizmo>(SyncGizmoRadius, type); type = AccessTools.TypeByName("CashRegister.Building_CashRegister"); cashRegisterType = type.MakeArrayType(); shiftsListField = AccessTools.FieldRefAccess <IList>(type, "shifts"); type = AccessTools.TypeByName("CashRegister.Shifts.Shift"); shiftConstructor = AccessTools.Constructor(type); timetableField = AccessTools.FieldRefAccess <object>(type, "timetable"); assignedField = AccessTools.FieldRefAccess <List <Pawn> >(type, "assigned"); type = AccessTools.TypeByName("CashRegister.Timetable.TimetableBool"); timesField = AccessTools.FieldRefAccess <List <bool> >(type, "times"); }
public static List <ConstructorInfo> GetDeclaredConstructors(Type type) { // Harmony 1.x matched both static and instance constructors return (AccessTools.GetDeclaredConstructors(type, searchForStatic: false) ?? AccessTools.GetDeclaredConstructors(type, searchForStatic: true)); }
public static IEnumerable <MethodBase> TargetMethods() { foreach (var ctor in AccessTools.GetDeclaredConstructors(typeof(DialogueBox))) { yield return(ctor); } }
private void Start() { _logger = Logger; // UserData is universal across games. Run in Start to let the game create the dir. Don't use UserData.Path since it's broken in EC _fullUserDataPath = Path.GetFullPath(Path.Combine(Paths.GameRootPath, "UserData")); var h = HarmonyWrapper.PatchAll(typeof(RemoveToRecycleBin)); // Patch all FileStream to account for differences in internals of different framework versions var hook = new HarmonyMethod(typeof(RemoveToRecycleBin), nameof(FileStreamHook)); if (hook == null) { throw new ArgumentNullException(nameof(hook)); } foreach (var m in AccessTools.GetDeclaredConstructors(typeof(FileStream))) { var args = m.GetParameters(); if (args.Any(x => x.ParameterType == typeof(FileMode)) && args.Any(x => x.ParameterType == typeof(FileAccess))) { h.Patch(m, hook); //_logger.LogDebug("Patching " + m); } } }
public static void FindUnpatchedInType(Type type, string[] unsupportedTypes, List <string> systemRngLog, List <string> unityRngLog, List <string> logAllClasses = null) { // Don't mind all the try/catch blocks, I went for maximum safety try { if (unsupportedTypes.Any(t => type.Namespace != null && (type.Namespace == t || type.Namespace.StartsWith($"{t}.")))) { return; } } catch (Exception) { // ignored } if (logAllClasses != null) { lock (logAllClasses) logAllClasses.Add(type.FullName); } try { // Get all methods, constructors, getters, and setters (everything that should have IL instructions) var methods = AccessTools.GetDeclaredMethods(type).Cast <MethodBase>() .Concat(AccessTools.GetDeclaredConstructors(type)) .Concat(AccessTools.GetDeclaredProperties(type).SelectMany(p => new[] { p.GetGetMethod(true), p.GetSetMethod(true) }).Where(p => p != null)); foreach (var method in methods) { try { MpCompat.harmony.Patch(method, transpiler: new HarmonyMethod(typeof(DebugActions), nameof(FindRng))); } catch (Exception e) when((e?.InnerException ?? e) is PatchingCancelledException cancelled) { if (cancelled.foundSystemRng) { lock (systemRngLog) systemRngLog.Add($"{type.FullName}:{method.Name}"); } if (cancelled.foundUnityRng) { lock (unityRngLog) unityRngLog.Add($"{type.FullName}:{method.Name}"); } } catch (Exception) { // ignored } } } catch (Exception) { // ignored } }
private static MethodBase GetOriginalMethod(HarmonyMethod attribute) { if (attribute.declaringType == null) { return(null); } switch (attribute.methodType) { case MethodType.Normal: if (attribute.methodName == null) { return(null); } return(AccessTools.DeclaredMethod(attribute.declaringType, attribute.methodName, attribute.argumentTypes)); case MethodType.Getter: if (attribute.methodName == null) { return(null); } return(AccessTools.DeclaredProperty(attribute.declaringType, attribute.methodName) .GetGetMethod(true)); case MethodType.Setter: if (attribute.methodName == null) { return(null); } return(AccessTools.DeclaredProperty(attribute.declaringType, attribute.methodName) .GetSetMethod(true)); case MethodType.Constructor: return(AccessTools.GetDeclaredConstructors(attribute.declaringType) .FirstOrDefault((ConstructorInfo c) => { if (c.IsStatic) { return false; } ParameterInfo[] parameters = c.GetParameters(); if (attribute.argumentTypes == null && parameters.Length == 0) { return true; } return parameters .Select((p) => p.ParameterType) .SequenceEqual(attribute.argumentTypes); })); case MethodType.StaticConstructor: return(AccessTools.GetDeclaredConstructors(attribute.declaringType) .FirstOrDefault(c => c.IsStatic)); } return(null); }
public static MethodBase GetOriginalMethod(HarmonyMethod attr) { if (attr.declaringType == null) { return(null); } if (attr.methodType == null) { attr.methodType = MethodType.Normal; } switch (attr.methodType) { case MethodType.Normal: if (attr.methodName == null) { return(null); } return(AccessTools.DeclaredMethod( attr.declaringType, attr.methodName, attr.argumentTypes)); case MethodType.Getter: if (attr.methodName == null) { return(null); } return(AccessTools.DeclaredProperty(attr.declaringType, attr.methodName) .GetGetMethod(true)); case MethodType.Setter: if (attr.methodName == null) { return(null); } return(AccessTools.DeclaredProperty(attr.declaringType, attr.methodName) .GetSetMethod(true)); case MethodType.Constructor: return(AccessTools.DeclaredConstructor(attr.declaringType, attr.argumentTypes)); case MethodType.StaticConstructor: return(AccessTools.GetDeclaredConstructors(attr.declaringType) .FirstOrDefault(c => c.IsStatic)); } return(null); }
public static ParameterInfo[] GetConstructorExtraParameterInfo(Type type) { var constructors = AccessTools.GetDeclaredConstructors(type); if (constructors == null || constructors.Count == 0) { return(null); } // the first 3 parameters are always the same, we only want the extra return(constructors[0].GetParameters().Skip(3).ToArray()); }
private static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator generator) { // Player RoleType Vector3 float List <CodeInstruction> newInstructions = ListPool <CodeInstruction> .Shared.Rent(instructions); // Find the index of the ldarg.0 before the only ldfld CharacterClassManager::SpawnProtected const int offset = -1; int index = newInstructions.FindIndex(i => i.opcode == OpCodes.Ldfld && (FieldInfo)i.operand == AccessTools.Field(typeof(CharacterClassManager), nameof(CharacterClassManager.SpawnProtected))) + offset; // Remove all existing this._pms.OnPlayerClassChange calls (we will want to call this ourselves after our even fires, to allow their spawn position to change.) foreach (CodeInstruction instruction in newInstructions.FindAll(i => i.opcode == OpCodes.Call && (MethodInfo)i.operand == AccessTools.Method(typeof(PlayerMovementSync), nameof(PlayerMovementSync.OnPlayerClassChange)))) { newInstructions.Remove(instruction); } LocalBuilder ev = generator.DeclareLocal(typeof(SpawningEventArgs)); newInstructions.InsertRange(index, new[] { // Player.Get(this._hub) new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(CharacterClassManager), nameof(CharacterClassManager._hub))), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), // this.CurClass new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(CharacterClassManager), nameof(CharacterClassManager.CurClass))), // var ev = new SpawningEventArg(Player, RoleType) // Exiled.Events.Handlers.Player.OnSpawning(ev); new CodeInstruction(OpCodes.Newobj, AccessTools.GetDeclaredConstructors(typeof(SpawningEventArgs))[0]), new CodeInstruction(OpCodes.Dup), new CodeInstruction(OpCodes.Stloc, ev.LocalIndex), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Exiled.Events.Handlers.Player), nameof(Handlers.Player.OnSpawning))), // this._pms.OnPlayerClassChange(ev.Position, ev.RotationY) new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(CharacterClassManager), nameof(CharacterClassManager._pms))), new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex), new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(SpawningEventArgs), nameof(SpawningEventArgs.Position))), new CodeInstruction(OpCodes.Ldloc, ev.LocalIndex), new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(SpawningEventArgs), nameof(SpawningEventArgs.RotationY))), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(PlayerMovementSync), nameof(PlayerMovementSync.OnPlayerClassChange))), }); for (int z = 0; z < newInstructions.Count; z++) { yield return(newInstructions[z]); } ListPool <CodeInstruction> .Shared.Return(newInstructions); }
static ResourceDepotUtils() { foreach (var constructorInfo in AccessTools.GetDeclaredConstructors(typeof(ResourceDepot), false)) { var @params = constructorInfo.GetParameters(); if (@params.Length == 0) { V1 = AccessTools2.GetDelegate <V1Delegate>(constructorInfo); } if (@params.Length == 1 && @params[0].ParameterType == typeof(string)) { V2 = AccessTools2.GetDelegate <V2Delegate>(constructorInfo); } } }
public static MethodBase GetConstructorMethodBase(Type type, string ctorName) { List <ConstructorInfo> ctor_Infos = new List <ConstructorInfo>(); ctor_Infos = AccessTools.GetDeclaredConstructors(type); foreach (ConstructorInfo ctor_info in ctor_Infos) { GetConstructorInfo(ctor_info); if (ctor_info.Name == ctorName) { return(ctor_info as MethodBase); } } return(null); }
private static MethodBase GetConstructorMethodBase(Type type, string ctorName) { List <ConstructorInfo> ctor_Infos = new List <ConstructorInfo>(); ctor_Infos = AccessTools.GetDeclaredConstructors(type); foreach (ConstructorInfo ctor_info in ctor_Infos) { BZLogger.Debug($"found constructor [{ctorName}] in class [{type}]"); if (ctor_info.Name == ctorName) { return(ctor_info as MethodBase); } } BZLogger.Debug($"the required constructor [{ctorName}] in class [{type}] has not found!"); return(null); }
// Copied from Harmony.PatchProcessor public static MethodBase GetMethod(Type type, string methodName, MethodType methodType, Type[] args) { if (type == null) { return(null); } switch (methodType) { case MethodType.Normal: if (methodName == null) { return(null); } return(AccessTools.DeclaredMethod(type, methodName, args)); case MethodType.Getter: if (methodName == null) { return(null); } return(AccessTools.DeclaredProperty(type, methodName).GetGetMethod(true)); case MethodType.Setter: if (methodName == null) { return(null); } return(AccessTools.DeclaredProperty(type, methodName).GetSetMethod(true)); case MethodType.Constructor: return(AccessTools.DeclaredConstructor(type, args)); case MethodType.StaticConstructor: return(AccessTools.GetDeclaredConstructors(type) .Where(c => c.IsStatic) .FirstOrDefault()); } return(null); }
public static List <ConstructorInfo> GetDeclaredConstructors(Type type) { return(AccessTools.GetDeclaredConstructors(type, searchForStatic: true)); }
/// <summary>Get a constructor and assert that it was found.</summary> /// <param name="parameterCount">The the number of parameters in the overload signature.</param> /// <returns>The first constructor that matches the specified parameter count.</returns> /// <remarks>Useful when there's no compile-time access to one or more parameter types.</remarks> public static ConstructorInfo RequireConstructor(this Type type, int parametersCount) { return(AccessTools.GetDeclaredConstructors(type).First(c => c.GetParameters().Length == parametersCount)); }
private static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator generator) { List <CodeInstruction> newInstructions = ListPool <CodeInstruction> .Shared.Rent(instructions); Label continueLabel = generator.DefineLabel(); Label endLabel = generator.DefineLabel(); Label elseLabel = generator.DefineLabel(); LocalBuilder player = generator.DeclareLocal(typeof(API.Features.Player)); LocalBuilder ev = generator.DeclareLocal(typeof(ChangingSpectatedPlayerEventArgs)); int index = newInstructions.FindIndex(x => x.opcode == OpCodes.Ret) + 1; CodeInstruction firstLabel = new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]); newInstructions[index].WithLabels(endLabel); newInstructions.InsertRange( index, new CodeInstruction[] { /* * var player = Player.Get(__instance._hub); * if (player != null) * { * var ev = new ChangingSpectatedPlayerEventArgs(player, Player.Get(__instance.CurrentSpectatedPlayer), Player.Get(value)); * * Exiled.Events.Handlers.Player.OnChangingSpectatedPlayer(ev); * * if(!ev.IsAllowed) return; * * value = ev.NewTarget?.ReferenceHub ?? ev.Player.ReferenceHub; * } */ // var player = Player.Get(__instance._hub); firstLabel, new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(SpectatorManager), nameof(SpectatorManager._hub))), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new System.Type[] { typeof(ReferenceHub) })), new CodeInstruction(OpCodes.Dup), // if (player != null) new CodeInstruction(OpCodes.Stloc, player), new CodeInstruction(OpCodes.Brfalse_S, endLabel), new CodeInstruction(OpCodes.Ldloc, player), // Player.Get(__instance.CurrentSpectatedPlayer) new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(SpectatorManager), nameof(SpectatorManager._currentSpectatedPlayer))), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new System.Type[] { typeof(ReferenceHub) })), // Player.Get(value) new CodeInstruction(OpCodes.Ldarg_1), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new System.Type[] { typeof(ReferenceHub) })), // var ev = new ChangingSpectatedPlayerEventArgs(player, Player.Get(__instance.CurrentSpectatedPlayer), Player.Get(value)) new CodeInstruction(OpCodes.Ldc_I4_1), new CodeInstruction(OpCodes.Newobj, AccessTools.GetDeclaredConstructors(typeof(ChangingSpectatedPlayerEventArgs))[0]), new CodeInstruction(OpCodes.Dup), new CodeInstruction(OpCodes.Dup), new CodeInstruction(OpCodes.Stloc, ev), // Exiled.Events.Handlers.Player.OnChangingSpectatedPlayer(ev); new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Player), nameof(Player.OnChangingSpectatedPlayer))), // if(!ev.IsAllowed) return; new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(ChangingSpectatedPlayerEventArgs), nameof(ChangingSpectatedPlayerEventArgs.IsAllowed))), new CodeInstruction(OpCodes.Brtrue_S, continueLabel), new CodeInstruction(OpCodes.Ret), // ev.NewTarget; new CodeInstruction(OpCodes.Ldloc, ev).WithLabels(continueLabel), new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(ChangingSpectatedPlayerEventArgs), nameof(ChangingSpectatedPlayerEventArgs.NewTarget))), // if(ev.NewTarget == null) new CodeInstruction(OpCodes.Dup), new CodeInstruction(OpCodes.Brtrue_S, elseLabel), // value = ev.Player.ReferenceHub; new CodeInstruction(OpCodes.Pop), new CodeInstruction(OpCodes.Ldloc, ev), new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(ChangingSpectatedPlayerEventArgs), nameof(ChangingSpectatedPlayerEventArgs.Player))), // value = ev.NewTarget.ReferenceHub; new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(API.Features.Player), nameof(API.Features.Player.ReferenceHub))).WithLabels(elseLabel), new CodeInstruction(OpCodes.Starg_S, 1), }); for (int z = 0; z < newInstructions.Count; z++) { yield return(newInstructions[z]); } ListPool <CodeInstruction> .Shared.Return(newInstructions); yield break; }