using System; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: AssemblyProduct("AnyDirectionParry")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("AnyDirectionParry")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("1.1.1.0")] namespace AnyDirectionParry; public static class PluginInfo { public const string PLUGIN_GUID = "supidowagon.AnyDirectionParry"; public const string PLUGIN_NAME = "Any Direction Parry"; public const string PLUGIN_VERSION = "1.1.1"; } [BepInPlugin("supidowagon.AnyDirectionParry", "Any Direction Parry", "1.1.1")] public class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(EffectDealer), "FacingRuleCheck", new Type[] { typeof(DamageDealer), typeof(Vector3), typeof(Vector2) })] private static class Patch_EffectDealer_FacingRuleCheck { private static void Postfix(EffectDealer __instance, ref bool __result) { if (!__result && IgnoreParryDirection != null && IgnoreParryDirection.Value && (PlayerOnly == null || !PlayerOnly.Value || IsPlayerParryDealer(__instance))) { __result = true; } } } internal static ManualLogSource Logger; internal static ConfigEntry IgnoreParryDirection; internal static ConfigEntry PlayerOnly; private static PropertyInfo playerInstanceProp; private static FieldInfo playerHealthField; private static FieldInfo parryDealerField; private static bool reflectionReady; private static bool reflectionFailed; private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; IgnoreParryDirection = ((BaseUnityPlugin)this).Config.Bind("General", "IgnoreParryDirection", true, "Parry attacks coming from any direction, whichever way Yi happens to be facing. Turn off to restore the stock behaviour without removing the mod."); PlayerOnly = ((BaseUnityPlugin)this).Config.Bind("General", "PlayerOnly", true, "Only lift the facing requirement for the player. Leave this on unless you also want enemies that parry to ignore facing."); Logger.LogInfo((object)"Plugin supidowagon.AnyDirectionParry is loaded!"); Harmony val = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "supidowagon.AnyDirectionParry"); foreach (MethodBase patchedMethod in val.GetPatchedMethods()) { Logger.LogInfo((object)("Patched method: " + patchedMethod.DeclaringType.FullName + "." + patchedMethod.Name)); } if (val.GetPatchedMethods().Count() == 0) { Logger.LogError((object)"Failed to apply Harmony patches."); } } private static void EnsureReflection() { if (reflectionReady || reflectionFailed) { return; } Type type = AccessTools.TypeByName("Player"); if (type != null) { playerInstanceProp = AccessTools.Property(type, "i"); playerHealthField = AccessTools.Field(type, "health"); if (playerHealthField != null) { parryDealerField = AccessTools.Field(playerHealthField.FieldType, "parryDealer"); } } if (playerInstanceProp == null || playerHealthField == null || parryDealerField == null) { reflectionFailed = true; Logger.LogWarning((object)"Could not resolve Player.i.health.parryDealer; PlayerOnly cannot be enforced, so the facing rule is left untouched. Set PlayerOnly=false to apply it regardless."); } else { reflectionReady = true; } } internal static bool IsPlayerParryDealer(EffectDealer dealer) { if ((Object)(object)dealer == (Object)null) { return false; } EnsureReflection(); if (!reflectionReady) { return false; } object value = playerInstanceProp.GetValue(null, null); if (value == null) { return false; } object value2 = playerHealthField.GetValue(value); if (value2 == null) { return false; } return object.ReferenceEquals(dealer, parryDealerField.GetValue(value2)); } }