using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using RepoSteamNetworking.API; using RepoSteamNetworking.Networking; using RepoSteamNetworking.Networking.Serialization; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("TimerPlugin")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0")] [assembly: AssemblyProduct("Timer Plugin")] [assembly: AssemblyTitle("TimerPlugin")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace TimerPlugin { public class TimerPlugin_Config { private readonly ConfigFile _configFile; public static ConfigEntry configPluginEnabled; public static ConfigEntry configLevelTimerEnabled; public static ConfigEntry configIdleCountdownEnabled; public static ConfigEntry configEnemyTimerEnabled; public static ConfigEntry configEnemyShowType; public static ConfigEntry configEnemyNameLimit; public static ConfigEntry configEnemyTimerPositionX; public static ConfigEntry configEnemyTimerPositionY; public static ConfigEntry configLevelTimerPositionX; public static ConfigEntry configLevelTimerPositionY; public TimerPlugin_Config(ConfigFile configFile) { _configFile = configFile; } public void RegisterOptions() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Expected O, but got Unknown //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Expected O, but got Unknown //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Expected O, but got Unknown configPluginEnabled = _configFile.Bind("General", "PluginEnabled", true, new ConfigDescription("If enabled, plugin will be loaded", (AcceptableValueBase)(object)new AcceptableValueList(new bool[2] { true, false }), Array.Empty())); configLevelTimerEnabled = _configFile.Bind("Timers", "TimerEnabled", true, new ConfigDescription("If enabled, level timer will be shown", (AcceptableValueBase)(object)new AcceptableValueList(new bool[2] { true, false }), Array.Empty())); configIdleCountdownEnabled = _configFile.Bind("Timers", "CountdownEnabled", true, new ConfigDescription("If enabled, enemies' idle time will be shown", (AcceptableValueBase)(object)new AcceptableValueList(new bool[2] { true, false }), Array.Empty())); configEnemyTimerEnabled = _configFile.Bind("Timers", "EnemyTimerEnabled", true, new ConfigDescription("If enabled, enemies' respawn time will be shown", (AcceptableValueBase)(object)new AcceptableValueList(new bool[2] { true, false }), Array.Empty())); configEnemyShowType = _configFile.Bind("Timers.Enemy", "EnemyTimerShowType", "ALL", new ConfigDescription("What to show on enemy list\nEnemyList - Shows what enemies are on level\nAlive - Enemy displayed only if it's alive\nDead - Enemy displayed only if it's dead(without time)\nDeadTimer - Shows dead enemies with respawn times\nALL - Shows all info", (AcceptableValueBase)(object)new AcceptableValueList(new string[5] { "ALL", "Alive", "Dead", "DeadTimer", "EnemyList" }), Array.Empty())); configEnemyNameLimit = _configFile.Bind("Timers.Enemy", "EnemyNameLimit", 30, new ConfigDescription("How many characters of enemy name will be dispalyed", (AcceptableValueBase)(object)new AcceptableValueRange(5, 60), Array.Empty())); configEnemyTimerPositionX = _configFile.Bind("Position.Enemy", "EnemyTimerPositionX", 240, new ConfigDescription("Enemy list X position (horizontal)", (AcceptableValueBase)(object)new AcceptableValueRange(-500, 500), Array.Empty())); configEnemyTimerPositionY = _configFile.Bind("Position.Enemy", "EnemyTimerPositionY", 10, new ConfigDescription("Enemy list Y position (vertical)", (AcceptableValueBase)(object)new AcceptableValueRange(-400, 400), Array.Empty())); configLevelTimerPositionX = _configFile.Bind("Position.Level", "LevelTimerPositionX", -330, new ConfigDescription("Level timer X position (horizontal)", (AcceptableValueBase)(object)new AcceptableValueRange(-350, 320), Array.Empty())); configLevelTimerPositionY = _configFile.Bind("Position.Level", "LevelTimerPositionY", 120, new ConfigDescription("Level timer Y position (vertical)", (AcceptableValueBase)(object)new AcceptableValueRange(-170, 220), Array.Empty())); } } public class DespawnedTimerPacket : NetworkPacket { public Dictionary Enemies { get; set; } protected override void WriteData(SocketMessage socketMessage) { socketMessage.Write>(Enemies); } protected override void ReadData(SocketMessage socketMessage) { Enemies = socketMessage.Read>(); } } public class EnemyListUI : SemiUI { private TextMeshProUGUI headerText; public GameObject scanlineObject; private TextMeshProUGUI enemyNamesText; private TextMeshProUGUI respawnTimesText; private DateTime _lastSyncTime = DateTime.Now; private static Dictionary _enemies = new Dictionary(); private float showBigMessage; private string enemyToShow; private Difficulty difficultyToShow; public static EnemyListUI instance; private readonly Dictionary difficultyColors = new Dictionary { { (Difficulty)0, "56FF6D" }, { (Difficulty)1, "FF8D00" }, { (Difficulty)2, "CC0000" } }; protected override void Start() { if (base.doNotDisable == null) { base.doNotDisable = new List(); } ((SemiUI)this).Start(); instance = this; base.animateTheEntireObject = true; enemyNamesText = ((Component)((Component)this).transform.Find("EnemyNames")).GetComponent(); respawnTimesText = ((Component)((Component)this).transform.Find("RespawnTimes")).GetComponent(); headerText = ((Component)((Component)this).transform.Find("EnemiesHeader")).GetComponent(); ((TMP_Text)enemyNamesText).text = ""; ((TMP_Text)respawnTimesText).text = ""; ((TMP_Text)headerText).text = "Enemies"; ((TMP_Text)enemyNamesText).alignment = (TextAlignmentOptions)2052; ((TMP_Text)enemyNamesText).enableWordWrapping = false; ((TMP_Text)enemyNamesText).overflowMode = (TextOverflowModes)0; ((TMP_Text)enemyNamesText).fontStyle = (FontStyles)33; ((TMP_Text)respawnTimesText).alignment = (TextAlignmentOptions)2049; ((TMP_Text)respawnTimesText).enableWordWrapping = false; ((TMP_Text)respawnTimesText).overflowMode = (TextOverflowModes)0; ((TMP_Text)respawnTimesText).fontStyle = (FontStyles)33; ((Behaviour)headerText).enabled = false; scanlineObject.SetActive(false); UpdatePosition(); TimerPlugin_Config.configEnemyTimerPositionX.SettingChanged += OnEnemyTimerPositionChanged; TimerPlugin_Config.configEnemyTimerPositionY.SettingChanged += OnEnemyTimerPositionChanged; Plugin.Logger.LogDebug((object)"EnemyListUI: Start called"); } public string Truncate(string value, int maxChars) { return (value.Length <= maxChars) ? value : (value.Substring(0, maxChars) + ".."); } private void OnEnemyTimerPositionChanged(object sender, EventArgs e) { UpdatePosition(); } private void UpdatePosition() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) int value = TimerPlugin_Config.configEnemyTimerPositionX.Value; int value2 = TimerPlugin_Config.configEnemyTimerPositionY.Value; base.showPosition = new Vector2((float)value, (float)value2); if (value >= 0) { base.hidePosition = new Vector2(600f, (float)value2); } else { base.hidePosition = new Vector2(-700f, (float)value2); } } public void Fetch() { //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) ((TMP_Text)enemyNamesText).text = ""; ((TMP_Text)respawnTimesText).text = ""; ((TMP_Text)headerText).text = "Enemies"; ((Behaviour)headerText).enabled = false; scanlineObject.SetActive(false); StringBuilder stringBuilder = new StringBuilder(""); StringBuilder stringBuilder2 = new StringBuilder(""); foreach (EnemyParent item in EnemyDirector.instance.enemiesSpawned) { float value = item.DespawnedTimer; bool flag = false; flag = ((!SemiFunc.IsNotMasterClient()) ? ((double)value <= 1E-06) : (_enemies.TryGetValue(PunExtensions.GetPhotonView(((Component)item).gameObject).ViewID, out value) ? ((double)value <= 1E-06) : item.EnableObject.activeSelf)); string text = Truncate(item.enemyName, TimerPlugin_Config.configEnemyNameLimit.Value); string text2 = difficultyColors[item.difficulty]; if (flag) { if (TimerPlugin_Config.configEnemyShowType.Value == "Alive" || TimerPlugin_Config.configEnemyShowType.Value == "EnemyList" || TimerPlugin_Config.configEnemyShowType.Value == "ALL") { stringBuilder.Append("" + text + "\n"); if (TimerPlugin_Config.configEnemyShowType.Value == "ALL") { stringBuilder2.Append("ALIVE\n"); } } } else { if (!(TimerPlugin_Config.configEnemyShowType.Value != "Alive")) { continue; } stringBuilder.Append("" + text + "\n"); if (TimerPlugin_Config.configEnemyShowType.Value == "DeadTimer" || TimerPlugin_Config.configEnemyShowType.Value == "ALL") { if (value > 0f) { Color val = (Color)((value < 15f && (int)(value * 10f) % 10 < 5) ? new Color(0.8f, 0f, 0f, 1f) : Color.white); stringBuilder2.Append(SemiFunc.TimeToString(value, true, val, Color.white) + "\n"); } else { stringBuilder2.Append("Dead\n"); } } } } ((TMP_Text)enemyNamesText).text = stringBuilder.ToString(); ((TMP_Text)respawnTimesText).text = stringBuilder2.ToString(); if (((TMP_Text)enemyNamesText).text != "") { ((Behaviour)headerText).enabled = true; scanlineObject.SetActive(true); } } public void BigMessage(string enemyName, Difficulty difficulty) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) enemyToShow = Truncate(enemyName, TimerPlugin_Config.configEnemyNameLimit.Value); difficultyToShow = difficulty; showBigMessage = 3f; } internal static void OnDespawnedTimerPacketReceived(DespawnedTimerPacket packet) { _enemies = packet.Enemies; } protected override void Update() { //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) ((SemiUI)this).Update(); if (SemiFunc.IsMasterClient() && (DateTime.Now - _lastSyncTime).TotalMilliseconds >= 500.0) { Dictionary dictionary = new Dictionary(); foreach (EnemyParent item in EnemyDirector.instance.enemiesSpawned) { int viewID = PunExtensions.GetPhotonView(((Component)item).gameObject).ViewID; float despawnedTimer = item.DespawnedTimer; dictionary.Add(viewID, despawnedTimer); } DespawnedTimerPacket despawnedTimerPacket = new DespawnedTimerPacket { Enemies = dictionary }; RepoSteamNetwork.SendPacket(despawnedTimerPacket, (NetworkDestination)2); _lastSyncTime = DateTime.Now; } if (!TimerPlugin_Config.configEnemyTimerEnabled.Value) { ((SemiUI)this).Hide(); return; } if (showBigMessage > 0f) { showBigMessage -= Time.deltaTime; SemiFunc.UIBigMessage("" + enemyToShow + " respawned", "{!}", 20f, Color.white, Color.white); } ((SemiUI)this).Hide(); } } public class LevelTimerUI : SemiUI { public static LevelTimerUI instance; private TextMeshProUGUI Text; private bool setup = true; private float levelTimerElapsedTime; protected override void Start() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (base.doNotDisable == null) { base.doNotDisable = new List(); } ((SemiUI)this).Start(); instance = this; Text = ((Component)this).GetComponent(); ((TMP_Text)Text).text = "00:00"; ((Graphic)Text).color = new Color(0f, 0.65f, 1f, 1f); ((TMP_Text)Text).fontSize = 18f; levelTimerElapsedTime = 0f; UpdatePosition(); TimerPlugin_Config.configLevelTimerPositionX.SettingChanged += OnLevelTimerPositionChanged; TimerPlugin_Config.configLevelTimerPositionY.SettingChanged += OnLevelTimerPositionChanged; Plugin.Logger.LogDebug((object)"LevelTimerUI: Start called"); } private void OnLevelTimerPositionChanged(object sender, EventArgs e) { UpdatePosition(); } private void UpdatePosition() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) int value = TimerPlugin_Config.configLevelTimerPositionX.Value; int value2 = TimerPlugin_Config.configLevelTimerPositionY.Value; base.showPosition = new Vector2((float)value, (float)value2); if (value >= 0) { base.hidePosition = new Vector2(600f, (float)value2); } else { base.hidePosition = new Vector2(-600f, (float)value2); } } protected override void Update() { ((SemiUI)this).Update(); if (!TimerPlugin_Config.configLevelTimerEnabled.Value) { ((SemiUI)this).Hide(); } else if (setup) { if (LevelGenerator.Instance.Generated) { setup = false; instance = this; } } else if (!((Object)(object)Text == (Object)null)) { levelTimerElapsedTime += Time.deltaTime; int num = Mathf.FloorToInt(levelTimerElapsedTime / 60f); int num2 = Mathf.FloorToInt(levelTimerElapsedTime % 60f); ((TMP_Text)Text).text = $"{num:00}:{num2:00}"; } } } [HarmonyPatch(typeof(LevelGenerator), "GenerateDone")] public class LevelGenerator_GenerateDone_Patcher { private static readonly string hudParentPath = "UI/HUD/HUD Canvas/HUD/Game Hud"; private static GameObject CreateFromHealth(string name) where T : SemiUI { GameObject val = GameObject.Find(hudParentPath); GameObject gameObject = ((Component)val.transform.Find("Health")).gameObject; if ((Object)(object)val == (Object)null || (Object)(object)gameObject == (Object)null) { Plugin.Logger.LogError((object)$"CreateEnemyList: Required GameObjects not found (hudParent={val}, originalStats={gameObject})"); return null; } GameObject val2 = Object.Instantiate(gameObject, val.transform); ((Object)val2).name = name; Object.DestroyImmediate((Object)(object)val2.GetComponent()); for (int num = val2.transform.childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)val2.transform.GetChild(num)).gameObject, true); } val2.AddComponent(); Plugin.Logger.LogDebug((object)("CreateFromHealth: Created " + name)); return val2; } private static void CreateEnemyList() { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find(hudParentPath); GameObject gameObject = ((Component)val.transform.Find("Stats")).gameObject; if ((Object)(object)val == (Object)null || (Object)(object)gameObject == (Object)null) { Plugin.Logger.LogError((object)$"CreateEnemyList: Required GameObjects not found (hudParent={val}, originalStats={gameObject})"); return; } GameObject val2 = Object.Instantiate(gameObject, val.transform); ((Object)val2).name = "EnemyListUI"; GameObject gameObject2 = ((Component)val2.transform.Find("StatsNumbers")).gameObject; if ((Object)(object)gameObject2 != (Object)null) { ((Object)gameObject2).name = "RespawnTimes"; RectTransform component = gameObject2.GetComponent(); component.anchoredPosition = new Vector2(225f, 0f); GameObject val3 = Object.Instantiate(gameObject2.gameObject, val2.transform); ((Object)val3).name = "EnemyNames"; RectTransform component2 = val3.GetComponent(); component2.anchoredPosition = new Vector2(20f, 0f); } else { Plugin.Logger.LogWarning((object)"CreateEnemyList: Could not find StatsNumbers under cloned Stats prefab."); } GameObject gameObject3 = ((Component)val2.transform.Find("Upgrades Header")).gameObject; if ((Object)(object)gameObject3 != (Object)null) { ((Object)gameObject3).name = "EnemiesHeader"; ((TMP_Text)gameObject3.GetComponent()).text = "Enemies"; RectTransform component3 = gameObject3.GetComponent(); component3.anchoredPosition = Vector2.op_Implicit(new Vector3(-35f, 60f)); } else { Plugin.Logger.LogWarning((object)"CreateEnemyList: Could not find Upgrades Header under cloned Stats prefab."); } EnemyListUI enemyListUI = val2.AddComponent(); StatsUI component4 = val2.GetComponent(); if ((Object)(object)component4 != (Object)null) { enemyListUI.scanlineObject = component4.scanlineObject; Object.DestroyImmediate((Object)(object)component4); Object.DestroyImmediate((Object)(object)val2.GetComponent()); } else { Plugin.Logger.LogWarning((object)"CreateEnemyList: Could not find StatsUI"); } Plugin.Logger.LogDebug((object)"CreateEnemyList: Created"); LevelUI.instance.objectMoon.transform.localPosition = new Vector3(120f, 30f, 0f); ((Component)LevelUI.instance.objectMoon.transform.Find("Line")).transform.localPosition = new Vector3(-75f, -55f, 0f); ((Component)LevelUI.instance.objectMoon.transform.Find("Line")).transform.rotation = Quaternion.Euler(0f, 0f, 90f); } private static void Postfix() { try { if (SemiFunc.RunIsLevel()) { CreateFromHealth("LevelTimer"); CreateEnemyList(); } } catch (Exception arg) { Plugin.Logger.LogError((object)$"Exception in {MethodBase.GetCurrentMethod().Module} {MethodBase.GetCurrentMethod().Name} patch:\n{arg}"); } } } [HarmonyPatch(typeof(LevelUI), "Update")] public class LevelUI_Update_Patcher { private static Vector3 pos = new Vector3(0f, 40f, 0f); private static Vector3 pos2 = new Vector3(-60f, 40f, 0f); private static void Postfix(LevelUI __instance) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) try { if (!__instance.objectMoon.activeSelf) { ((Transform)__instance.transformOffset).localPosition = pos; } else { ((Transform)__instance.transformOffset).localPosition = pos2; } } catch (Exception arg) { Plugin.Logger.LogError((object)$"Exception in {MethodBase.GetCurrentMethod().Module} {MethodBase.GetCurrentMethod().Name} patch:\n{arg}"); } } } [HarmonyPatch(typeof(MapToolController), "Update")] public class MapToolController_Update_Patch { private static FieldRef photonViewRef = AccessTools.FieldRefAccess("photonView"); private static FieldRef activeRef = AccessTools.FieldRefAccess("Active"); private static void Postfix(MapToolController __instance) { if ((!GameManager.Multiplayer() || photonViewRef.Invoke(__instance).IsMine) && activeRef.Invoke(__instance) && (Object)(object)EnemyListUI.instance != (Object)null) { ((SemiUI)EnemyListUI.instance).Show(); EnemyListUI.instance.Fetch(); } } } [HarmonyPatch(typeof(MenuPage), "LockAndHide")] public class MenuPage_LockAndHide_Patch { private static void Postfix() { LevelTimerUI instance = LevelTimerUI.instance; if (instance != null) { ((SemiUI)instance).Hide(); } } } [HarmonyPatch(typeof(EnemyParent), "SpawnRPC")] public class EnemyParent_SpawnRPC_Patch { private static void Postfix(EnemyParent __instance) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (TimerPlugin_Config.configEnemyTimerEnabled.Value && Object.op_Implicit((Object)(object)EnemyListUI.instance)) { EnemyListUI.instance.BigMessage(__instance.enemyName, __instance.difficulty); } } } [BepInPlugin("TimerPlugin", "Timer Plugin", "1.2.0")] [BepInProcess("REPO.exe")] public class Plugin : BaseUnityPlugin { public static ManualLogSource Logger; public TimerPlugin_Config ConfigInstance; private static Harmony _harmony = new Harmony("TimerPlugin"); private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; ConfigInstance = new TimerPlugin_Config(((BaseUnityPlugin)this).Config); ConfigInstance.RegisterOptions(); RepoSteamNetwork.RegisterPacket(); RepoSteamNetwork.AddCallback((Action)EnemyListUI.OnDespawnedTimerPacketReceived); ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; if (TimerPlugin_Config.configPluginEnabled.Value) { _harmony.PatchAll(); Logger.LogInfo((object)"Plugin Loaded"); } else { Logger.LogWarning((object)"Plugin disabled in config"); } } private void OnDestroy() { Logger.LogWarning((object)"Plugin DESTROYED нахуй"); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "TimerPlugin"; public const string PLUGIN_NAME = "Timer Plugin"; public const string PLUGIN_VERSION = "1.2.0"; } }