Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PPR v1.0.0
BepInEx\plugins\PPR\AnimationSpeedManager.dll
Decompiled 6 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("AnimationSpeedManager")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AnimationSpeedManager")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("B3A6D52C-449A-4665-9FD0-BB48C8CF2CDF")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } public static class AnimationSpeedManager { public delegate double Handler(Character character, double speed); private static readonly Harmony harmony = new Harmony("AnimationSpeedManager"); private static bool hasMarkerPatch = false; private static readonly MethodInfo method = AccessTools.DeclaredMethod(typeof(CharacterAnimEvent), "CustomFixedUpdate", (Type[])null, (Type[])null); private static int index = 0; private static bool changed = false; private static Handler[][] handlers = Array.Empty<Handler[]>(); private static readonly Dictionary<int, List<Handler>> handlersPriorities = new Dictionary<int, List<Handler>>(); [PublicAPI] public static void Add(Handler handler, int priority = 400) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown if (!hasMarkerPatch) { harmony.Patch((MethodBase)method, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(AnimationSpeedManager), "markerPatch", (Type[])null, (Type[])null)), (HarmonyMethod)null); hasMarkerPatch = true; } if (!handlersPriorities.TryGetValue(priority, out List<Handler> value)) { handlersPriorities.Add(priority, value = new List<Handler>()); harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(AnimationSpeedManager), "wrapper", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } value.Add(handler); handlers = (from kv in handlersPriorities orderby kv.Key select kv.Value.ToArray()).ToArray(); } private static void wrapper(Character ___m_character, Animator ___m_animator) { Character ___m_character2 = ___m_character; double num = (double)___m_animator.speed * 10000000.0 % 100.0; if ((!(num > 10.0) || !(num < 30.0)) && !(___m_animator.speed <= 0.001f)) { double num2 = ___m_animator.speed; double num3 = handlers[index++].Aggregate(num2, (double current, Handler handler) => handler(___m_character2, current)); if (num3 != num2) { ___m_animator.speed = (float)(num3 - num3 % 1E-05); changed = true; } } } private static void markerPatch(Animator ___m_animator) { if (changed) { double num = (double)___m_animator.speed * 10000000.0 % 100.0; if ((num < 10.0 || num > 30.0) ? true : false) { ___m_animator.speed += 1.9E-06f; } changed = false; } index = 0; } }
BepInEx\plugins\PPR\PPR.dll
Decompiled 6 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PPR { internal static class PPRAccess { public static ItemData GetCurrentWeapon(Humanoid h) { return Traverse.Create((object)h).Method("GetCurrentWeapon", Array.Empty<object>()).GetValue<ItemData>(); } public static ItemData GetCurrentBlocker(Humanoid h) { return Traverse.Create((object)h).Method("GetCurrentBlocker", Array.Empty<object>()).GetValue<ItemData>(); } public static bool HaveSecondaryAttack(ItemData item) { return Traverse.Create((object)item).Method("HaveSecondaryAttack", Array.Empty<object>()).GetValue<bool>(); } public static bool HaveStamina(Character c, float amount) { return Traverse.Create((object)c).Method("HaveStamina", new Type[1] { typeof(float) }, new object[1] { amount }).GetValue<bool>(); } public static bool IsStaggering(Character c) { return Traverse.Create((object)c).Method("IsStaggering", Array.Empty<object>()).GetValue<bool>(); } public static bool InAttack(Character c) { return Traverse.Create((object)c).Method("InAttack", Array.Empty<object>()).GetValue<bool>(); } public static bool CanMove(Character c) { return Traverse.Create((object)c).Method("CanMove", Array.Empty<object>()).GetValue<bool>(); } } [HarmonyPatch(typeof(Humanoid), "StartAttack")] public static class PPRStartAttackPatch { [HarmonyPrefix] public static void Prefix(Humanoid __instance, bool secondaryAttack) { try { if (!PPRConfig.Enable.Value || !secondaryAttack) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && PPRState.IsParryWindowActive(val)) { ItemData currentWeapon = PPRAccess.GetCurrentWeapon(__instance); if (currentWeapon == null || !PPRAccess.HaveSecondaryAttack(currentWeapon)) { Plugin.Log.LogWarning((object)"[PPR] 카운터 실패 - 현재 무기에 특수 공격 없음"); PPRState.ConsumeParry(val); } else { PPRState.ConsumeParry(val); PPRState.ActivateCounterSpeed(val); Plugin.Log.LogInfo((object)$"[PPR] 카운터 발동! InAttack={PPRAccess.InAttack((Character)(object)__instance)}, CanMove={PPRAccess.CanMove((Character)(object)__instance)}"); } } } catch (Exception ex) { Plugin.Log.LogError((object)("[PPR] StartAttackPatch 오류: " + ex.Message)); } } } [HarmonyPatch(typeof(Player), "Update")] public static class PPRTickPatch { [HarmonyPostfix] public static void Postfix(Player __instance) { try { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { PPRState.Tick(__instance, Time.deltaTime); PPRState.TickCounterSpeed(__instance, PPRAccess.InAttack((Character)(object)__instance)); } } catch (Exception ex) { Plugin.Log.LogError((object)("[PPR] TickPatch 오류: " + ex.Message)); } } } [HarmonyPatch(typeof(Humanoid), "BlockAttack")] public static class PPRBlockPatch { [HarmonyPostfix] public static void Postfix(Humanoid __instance, HitData hit, Character attacker, bool __result, float ___m_blockTimer) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Invalid comparison between Unknown and I4 //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Invalid comparison between Unknown and I4 try { if (!__result || !PPRConfig.Enable.Value) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return; } ItemData currentWeapon = PPRAccess.GetCurrentWeapon(__instance); if (currentWeapon == null) { return; } ItemType itemType = currentWeapon.m_shared.m_itemType; if (((int)itemType == 3 || (int)itemType == 14 || (int)itemType == 22) && PPRAccess.HaveSecondaryAttack(currentWeapon)) { ItemData currentBlocker = PPRAccess.GetCurrentBlocker(__instance); if (currentBlocker != null && !(currentBlocker.m_shared.m_timedBlockBonus <= 1f) && PPRAccess.HaveStamina((Character)(object)__instance, 0f) && !PPRAccess.IsStaggering((Character)(object)__instance) && !(___m_blockTimer < 0f) && !(___m_blockTimer >= PPRConfig.ParryWindow.Value)) { PPRState.ActivateParry(val); PPRState.SpawnParryVFX(val); Plugin.Log.LogInfo((object)$"[PPR] 패링 감지 (blockTimer={___m_blockTimer:F3}s)"); } } } catch (Exception ex) { Plugin.Log.LogError((object)("[PPR] BlockPatch 오류: " + ex.Message)); } } } public static class PPRConfig { private const string SEC = "Perfect Parry"; private const string SEC_DMG = "Perfect Parry - Damage Reduction"; private const string SEC_VFX = "Perfect Parry - Effect"; public static ConfigEntry<bool> Enable; public static ConfigEntry<float> ParryWindow; public static ConfigEntry<float> CounterWindow; public static ConfigEntry<float> CounterSpeedMultiplier; public static ConfigEntry<bool> DamageReductionEnabled; public static ConfigEntry<float> DamageReductionPercent; public static ConfigEntry<bool> VFXEnabled; public static ConfigEntry<string> VFXPrefab; public static ConfigEntry<float> VFXOffsetX; public static ConfigEntry<float> VFXOffsetY; public static ConfigEntry<float> VFXOffsetZ; public static void Init(ConfigFile cfg) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Expected O, but got Unknown Enable = cfg.Bind<bool>("Perfect Parry", "(Enable) Perfect Parry", true, "Enable or disable the Perfect Parry feature."); ParryWindow = cfg.Bind<float>("Perfect Parry", "(Parry) Detection Window (sec)", 0.1f, new ConfigDescription("Time window to register a perfect parry. Must be shorter than the base perfect block window (0.25s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.24f), Array.Empty<object>())); CounterWindow = cfg.Bind<float>("Perfect Parry", "(Counter) Input Window (sec)", 0.6f, new ConfigDescription("Time after a successful parry during which you can press the secondary attack key to trigger a counter.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>())); CounterSpeedMultiplier = cfg.Bind<float>("Perfect Parry", "(Counter) Animation Speed Multiplier", 2.5f, new ConfigDescription("Animation speed multiplier for the counter special attack. 2.5 = 2.5x faster.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>())); DamageReductionEnabled = cfg.Bind<bool>("Perfect Parry - Damage Reduction", "(Enable) Damage Reduction", true, "Reduce incoming damage during the counter window after a successful parry."); DamageReductionPercent = cfg.Bind<float>("Perfect Parry - Damage Reduction", "(Damage Reduction) Reduction Rate (%)", 50f, new ConfigDescription("Damage reduction percentage during the counter window. 50 = 50% less damage.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); VFXEnabled = cfg.Bind<bool>("Perfect Parry - Effect", "(Enable) Head Effect", true, "Show a VFX above the player's head on successful parry."); VFXPrefab = cfg.Bind<string>("Perfect Parry - Effect", "(Effect) VFX Name", "vfx_blocked", "Name of the VFX prefab to display. Must be a valid ZNetScene prefab name."); VFXOffsetX = cfg.Bind<float>("Perfect Parry - Effect", "(Effect) Offset X", 0f, new ConfigDescription("Horizontal offset (left/right) relative to the player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>())); VFXOffsetY = cfg.Bind<float>("Perfect Parry - Effect", "(Effect) Offset Y", 2.5f, new ConfigDescription("Vertical offset (height) relative to the player. Default 2.5 = above head.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 8f), Array.Empty<object>())); VFXOffsetZ = cfg.Bind<float>("Perfect Parry - Effect", "(Effect) Offset Z", 0f, new ConfigDescription("Depth offset (forward/back) relative to the player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>())); } } [HarmonyPatch(typeof(Character), "ApplyDamage")] public static class PPRDamagePatch { [HarmonyPrefix] public static void Prefix(Character __instance, HitData hit) { try { if (PPRConfig.Enable.Value && PPRConfig.DamageReductionEnabled.Value) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && PPRState.IsParryWindowActive(val) && hit != null) { float num = 1f - PPRConfig.DamageReductionPercent.Value / 100f; ((DamageTypes)(ref hit.m_damage)).Modify(num); Plugin.Log.LogInfo((object)$"[PPR] 데미지 감소 적용 ({PPRConfig.DamageReductionPercent.Value}%)"); } } } catch (Exception ex) { Plugin.Log.LogError((object)("[PPR] DamagePatch 오류: " + ex.Message)); } } } [HarmonyPatch(typeof(Game), "Awake")] public static class PPRSpeedRegistrar { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Handler <>9__1_0; internal double <Postfix>b__1_0(Character character, double speed) { try { if (!PPRConfig.Enable.Value) { return speed; } Player val = (Player)(object)((character is Player) ? character : null); if (val == null) { return speed; } if (!PPRState.IsCounterSpeedActive(val)) { return speed; } if (!PPRAccess.InAttack((Character)(object)val)) { return speed; } return speed * (double)PPRConfig.CounterSpeedMultiplier.Value; } catch (Exception ex) { Plugin.Log.LogError((object)("[PPR] SpeedCallback 오류: " + ex.Message)); return speed; } } } private static bool _registered; [HarmonyPostfix] public static void Postfix() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (_registered) { return; } _registered = true; object obj = <>c.<>9__1_0; if (obj == null) { Handler val = delegate(Character character, double speed) { try { if (!PPRConfig.Enable.Value) { return speed; } Player val2 = (Player)(object)((character is Player) ? character : null); if (val2 == null) { return speed; } if (!PPRState.IsCounterSpeedActive(val2)) { return speed; } if (!PPRAccess.InAttack((Character)(object)val2)) { return speed; } return speed * (double)PPRConfig.CounterSpeedMultiplier.Value; } catch (Exception ex) { Plugin.Log.LogError((object)("[PPR] SpeedCallback 오류: " + ex.Message)); return speed; } }; <>c.<>9__1_0 = val; obj = (object)val; } AnimationSpeedManager.Add((Handler)obj, 400); Plugin.Log.LogInfo((object)"[PPR] AnimationSpeedManager 콜백 등록 완료."); } } public static class PPRState { private static readonly Dictionary<Player, float> _counterWindow = new Dictionary<Player, float>(); private static readonly HashSet<Player> _speedActive = new HashSet<Player>(); private static readonly Dictionary<Player, bool> _prevInAttack = new Dictionary<Player, bool>(); private static readonly Dictionary<Player, GameObject> _parryVFX = new Dictionary<Player, GameObject>(); public static void ActivateParry(Player player) { _counterWindow[player] = PPRConfig.CounterWindow.Value; Plugin.Log.LogInfo((object)"[PPR] 퍼펙트 패링 성공!"); } public static bool IsParryWindowActive(Player player) { float value; return _counterWindow.TryGetValue(player, out value) && value > 0f; } public static void ConsumeParry(Player player) { _counterWindow[player] = 0f; DestroyParryVFX(player); } public static void Tick(Player player, float dt) { if (_counterWindow.TryGetValue(player, out var value) && !(value <= 0f)) { float num = Mathf.Max(0f, value - dt); _counterWindow[player] = num; if (num <= 0f) { DestroyParryVFX(player); } } } public static void ActivateCounterSpeed(Player player) { _speedActive.Add(player); _prevInAttack[player] = false; } public static bool IsCounterSpeedActive(Player player) { return _speedActive.Contains(player); } public static void TickCounterSpeed(Player player, bool isInAttack) { bool value; if (!_speedActive.Contains(player)) { _prevInAttack.Remove(player); } else if (_prevInAttack.TryGetValue(player, out value) && value && !isInAttack) { DeactivateCounterSpeed(player); } else { _prevInAttack[player] = isInAttack; } } public static void DeactivateCounterSpeed(Player player) { _speedActive.Remove(player); _prevInAttack.Remove(player); Plugin.Log.LogInfo((object)"[PPR] 카운터 속도 해제"); } public static void SpawnParryVFX(Player player) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) DestroyParryVFX(player); if (!PPRConfig.VFXEnabled.Value) { return; } string value = PPRConfig.VFXPrefab.Value; if (string.IsNullOrEmpty(value) || (Object)(object)ZNetScene.instance == (Object)null) { return; } GameObject prefab = ZNetScene.instance.GetPrefab(value); if ((Object)(object)prefab == (Object)null) { Plugin.Log.LogWarning((object)("[PPR] VFX 프리팹 없음: " + value)); return; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(PPRConfig.VFXOffsetX.Value, PPRConfig.VFXOffsetY.Value, PPRConfig.VFXOffsetZ.Value); GameObject val2 = Object.Instantiate<GameObject>(prefab, ((Component)player).transform.position + val, Quaternion.identity); val2.transform.SetParent(((Component)player).transform, false); val2.transform.localPosition = val; ZNetView[] componentsInChildren = val2.GetComponentsInChildren<ZNetView>(true); foreach (ZNetView val3 in componentsInChildren) { Object.Destroy((Object)(object)val3); } ZSyncTransform[] componentsInChildren2 = val2.GetComponentsInChildren<ZSyncTransform>(true); foreach (ZSyncTransform val4 in componentsInChildren2) { Object.Destroy((Object)(object)val4); } _parryVFX[player] = val2; Plugin.Log.LogInfo((object)("[PPR] VFX 스폰: " + value)); } public static void DestroyParryVFX(Player player) { if (_parryVFX.TryGetValue(player, out var value) && (Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } _parryVFX.Remove(player); } } [BepInPlugin("com.KorCaptain.PPR", "PPR", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "com.KorCaptain.PPR"; public const string PluginName = "PPR"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; private readonly Harmony _harmony = new Harmony("com.KorCaptain.PPR"); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; PPRConfig.Init(((BaseUnityPlugin)this).Config); _harmony.PatchAll(); Log.LogInfo((object)"PPR v1.0.0 loaded."); } } }