using System; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DunGen; using DunGen.Graph; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("NoMineshaft")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.6.0")] [assembly: AssemblyInformationalVersion("1.0.6")] [assembly: AssemblyProduct("NoMineshaft")] [assembly: AssemblyTitle("NoMineshaft")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.6.0")] [module: UnverifiableCode] [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 NoMineshaft { internal sealed class DungeonTypeWatcher : MonoBehaviour { private static DungeonTypeWatcher? _instance; private float _next; private int _lastType = int.MinValue; internal static void EnsureExists() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("NoMineshaftWatcher"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent(); Plugin.Log.LogInfo((object)"[Watcher] created"); } } private void Awake() { _instance = this; } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private void LateUpdate() { if (Plugin.Enabled == null || !Plugin.Enabled.Value || Time.unscaledTime < _next) { return; } _next = Time.unscaledTime + 5f; RoundManager instance = RoundManager.Instance; StartOfRound instance2 = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { Plugin.Log.LogInfo((object)"[Watcher] RoundManager null"); } else if (instance.currentDungeonType != _lastType) { ManualLogSource log = Plugin.Log; string text = $"[Watcher] currentDungeonType {_lastType} -> {instance.currentDungeonType} "; object arg = instance.currentDungeonType == 4; SelectableLevel currentLevel = instance.currentLevel; log.LogInfo((object)(text + $"(mineshaft={arg}) level={((currentLevel != null) ? ((Object)currentLevel).name : null)} " + $"inShipPhase={instance2?.inShipPhase} isServer={((NetworkBehaviour)instance).IsServer} generating={instance.dungeonIsGenerating}")); _lastType = instance.currentDungeonType; if (instance.currentDungeonType == 4) { MineshaftScrubber.ScrubLevel(instance.currentLevel, "Watcher"); MineshaftScrubber.RemapDungeonType(instance, "Watcher"); } } else { ManualLogSource log2 = Plugin.Log; object arg2 = instance.currentDungeonType; SelectableLevel currentLevel2 = instance.currentLevel; log2.LogInfo((object)($"[Watcher] tick type={arg2} level={((currentLevel2 != null) ? ((Object)currentLevel2).name : null)} " + $"inShipPhase={instance2?.inShipPhase} isServer={((NetworkBehaviour)instance).IsServer} generating={instance.dungeonIsGenerating}")); } } } internal static class MineshaftIds { public const int VanillaMineshaftId = 4; public const string FlowName = "Level3Flow"; internal static bool IsMineshaftId(int id) { return id == 4; } internal static bool IsMineshaftFlow(DungeonFlow? flow) { if ((Object)(object)flow == (Object)null) { return false; } string text = ((Object)flow).name ?? ""; if (!(text == "Level3Flow") && text.IndexOf("Level3", StringComparison.OrdinalIgnoreCase) < 0) { if (text.IndexOf("Mine", StringComparison.OrdinalIgnoreCase) >= 0) { return text.IndexOf("Flow", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } return true; } } internal static class MineshaftScrubber { internal static bool ScrubLevel(SelectableLevel? level, string context) { if (level?.dungeonFlowTypes == null || level.dungeonFlowTypes.Length == 0) { Plugin.Log.LogInfo((object)(context + ": no dungeonFlowTypes on " + (((level != null) ? ((Object)level).name : null) ?? "null"))); return false; } string text = string.Join(", ", level.dungeonFlowTypes.Select((IntWithRarity f) => $"{f.id}:{f.rarity}")); IntWithRarity[] array = level.dungeonFlowTypes.Where((IntWithRarity f) => !MineshaftIds.IsMineshaftId(f.id)).ToArray(); if (array.Length == 0) { bool flag = false; for (int num = 0; num < level.dungeonFlowTypes.Length; num++) { IntWithRarity val = level.dungeonFlowTypes[num]; if (MineshaftIds.IsMineshaftId(val.id) && val.rarity != 0) { val.rarity = 0; level.dungeonFlowTypes[num] = val; flag = true; } } if (flag) { Plugin.Log.LogInfo((object)(context + ": zeroed Mineshaft rarity on " + ((Object)level).name + ". before=[" + text + "]")); } return flag; } if (array.Length == level.dungeonFlowTypes.Length) { Plugin.V(context + ": " + ((Object)level).name + " already has no Mineshaft id entries. flows=[" + text + "]"); return false; } level.dungeonFlowTypes = array; Plugin.Log.LogInfo((object)(context + ": stripped Mineshaft from " + ((Object)level).name + ". before=[" + text + "] after=[" + string.Join(", ", array.Select((IntWithRarity f) => $"{f.id}:{f.rarity}")) + "]")); return true; } internal static void ScrubAllLevels(string context) { StartOfRound instance = StartOfRound.Instance; if (instance?.levels == null) { Plugin.Log.LogInfo((object)(context + ": StartOfRound.levels is null")); return; } int num = 0; SelectableLevel[] levels = instance.levels; for (int i = 0; i < levels.Length; i++) { if (ScrubLevel(levels[i], context)) { num++; } } Plugin.Log.LogInfo((object)$"{context}: scrubbed {num}/{instance.levels.Length} moons"); } internal static bool RemapDungeonType(RoundManager manager, string context) { if ((Object)(object)manager == (Object)null || !MineshaftIds.IsMineshaftId(manager.currentDungeonType)) { return false; } SelectableLevel currentLevel = manager.currentLevel; if (currentLevel?.dungeonFlowTypes == null || currentLevel.dungeonFlowTypes.Length == 0) { Plugin.Log.LogWarning((object)(context + ": Mineshaft type set but level has no flows")); return false; } IntWithRarity[] array = currentLevel.dungeonFlowTypes.Where((IntWithRarity f) => !MineshaftIds.IsMineshaftId(f.id) && f.rarity > 0).ToArray(); if (array.Length == 0) { array = currentLevel.dungeonFlowTypes.Where((IntWithRarity f) => !MineshaftIds.IsMineshaftId(f.id)).ToArray(); } if (array.Length == 0) { Plugin.Log.LogWarning((object)(context + ": no alternate interiors on " + ((Object)currentLevel).name)); return false; } int num = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.randomMapSeed : Environment.TickCount); int[] array2 = array.Select((IntWithRarity f) => Math.Max(f.rarity, 1)).ToArray(); int num2 = manager.GetRandomWeightedIndex(array2, new Random(num ^ 0x4D1)); if (num2 < 0 || num2 >= array.Length) { num2 = 0; } int currentDungeonType = manager.currentDungeonType; manager.currentDungeonType = array[num2].id; Plugin.Log.LogInfo((object)$"{context}: remapped currentDungeonType {currentDungeonType} -> {manager.currentDungeonType} on {((Object)currentLevel).name}"); return true; } internal static DungeonFlow? PickAlternateFlow(RoundManager manager, out int newId) { newId = 0; SelectableLevel val = manager?.currentLevel; IndoorMapType[] array = manager?.dungeonFlowTypes; if (val?.dungeonFlowTypes == null || array == null) { return null; } IntWithRarity[] dungeonFlowTypes = val.dungeonFlowTypes; foreach (IntWithRarity val2 in dungeonFlowTypes) { if (!MineshaftIds.IsMineshaftId(val2.id) && val2.rarity > 0 && val2.id >= 0 && val2.id < array.Length) { DungeonFlow val3 = array[val2.id]?.dungeonFlow; if (!((Object)(object)val3 == (Object)null) && !MineshaftIds.IsMineshaftFlow(val3)) { newId = val2.id; return val3; } } } for (int j = 0; j < array.Length; j++) { DungeonFlow val4 = array[j]?.dungeonFlow; if (!((Object)(object)val4 == (Object)null) && !MineshaftIds.IsMineshaftFlow(val4)) { newId = j; return val4; } } return null; } } internal static class ManualPatches { internal static void Apply(Harmony harmony) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Expected O, but got Unknown //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Expected O, but got Unknown try { Patch(typeof(RoundManager), "GenerateNewFloor", typeof(GenFloorPatch), "Prefix"); MethodInfo methodInfo = AccessTools.Method(typeof(RoundManager), "GenerateNewFloor", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(GenFloorPostfixPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"Patched RoundManager.GenerateNewFloor postfix"); } Patch(typeof(RoundManager), "LoadNewLevel", typeof(LoadLevelPatch), "Prefix"); Patch(typeof(RoundManager), "GenerateNewLevelClientRpc", typeof(ClientRpcPatch), "Prefix"); MethodInfo methodInfo2 = AccessTools.Method(typeof(StartOfRound), "ChooseNewRandomMapSeed", (Type[])null, (Type[])null); Plugin.Log.LogInfo((object)("Resolve StartOfRound.ChooseNewRandomMapSeed => " + ((methodInfo2 == null) ? "NULL" : "ok"))); if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(MapSeedPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"Patched StartOfRound.ChooseNewRandomMapSeed"); } MethodInfo methodInfo3 = AccessTools.Method(typeof(StartOfRound), "Start", (Type[])null, (Type[])null); Plugin.Log.LogInfo((object)("Resolve StartOfRound.Start => " + ((methodInfo3 == null) ? "NULL" : "ok"))); if (methodInfo3 != null) { harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(StartPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"Patched StartOfRound.Start"); } MethodInfo methodInfo4 = AccessTools.Method(typeof(DungeonGenerator), "Generate", Type.EmptyTypes, (Type[])null) ?? AccessTools.Method(typeof(DungeonGenerator), "Generate", (Type[])null, (Type[])null); Plugin.Log.LogInfo((object)("Resolve DungeonGenerator.Generate => " + ((methodInfo4 == null) ? "NULL" : methodInfo4.ToString()))); if (methodInfo4 != null) { harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(DunGenPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"Patched DungeonGenerator.Generate"); } } catch (Exception arg) { Plugin.Log.LogError((object)$"ManualPatches.Apply failed: {arg}"); } void Patch(Type type, string name, Type patchClass, string prefixName, Type[]? args = null) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown MethodInfo methodInfo5 = ((args == null) ? AccessTools.Method(type, name, (Type[])null, (Type[])null) : AccessTools.Method(type, name, args, (Type[])null)); Plugin.Log.LogInfo((object)("Resolve " + type.Name + "." + name + " => " + ((methodInfo5 == null) ? "NULL" : (methodInfo5.IsPublic ? "public" : "nonpublic")))); if (!(methodInfo5 == null)) { harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(patchClass, prefixName, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)("Patched " + type.Name + "." + name)); } } } } internal static class GenFloorPatch { public static void Prefix(RoundManager __instance) { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return; } try { ManualLogSource log = Plugin.Log; SelectableLevel currentLevel = __instance.currentLevel; log.LogInfo((object)$"[GenerateNewFloor] level={((currentLevel != null) ? ((Object)currentLevel).name : null)} type={__instance.currentDungeonType} isServer={((NetworkBehaviour)__instance).IsServer}"); MineshaftScrubber.ScrubLevel(__instance.currentLevel, "GenerateNewFloor"); MineshaftScrubber.RemapDungeonType(__instance, "GenerateNewFloor"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[GenerateNewFloor] " + ex.Message)); } } } internal static class LoadLevelPatch { public static void Prefix(RoundManager __instance, int randomSeed, SelectableLevel newLevel) { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return; } try { Plugin.Log.LogInfo((object)$"[LoadNewLevel] seed={randomSeed} level={((newLevel != null) ? ((Object)newLevel).name : null)}"); MineshaftScrubber.ScrubLevel(newLevel, "LoadNewLevel"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[LoadNewLevel] " + ex.Message)); } } } internal static class ClientRpcPatch { public static void Prefix(RoundManager __instance, int randomSeed, int levelID) { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return; } try { Plugin.Log.LogInfo((object)$"[GenerateNewLevelClientRpc] seed={randomSeed} levelID={levelID} type={__instance.currentDungeonType}"); MineshaftScrubber.ScrubLevel(__instance.currentLevel, "GenerateNewLevelClientRpc"); MineshaftScrubber.RemapDungeonType(__instance, "GenerateNewLevelClientRpc"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[GenerateNewLevelClientRpc] " + ex.Message)); } } } internal static class MapSeedPatch { private static readonly Random Rng = new Random(); public static void Postfix(StartOfRound __instance) { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return; } try { RoundManager instance = RoundManager.Instance; ManualLogSource log = Plugin.Log; object arg = __instance.randomMapSeed; object arg2; if (instance == null) { arg2 = null; } else { SelectableLevel currentLevel = instance.currentLevel; arg2 = ((currentLevel != null) ? ((Object)currentLevel).name : null); } log.LogInfo((object)$"[ChooseNewRandomMapSeed] seed={arg} level={arg2}"); if ((Object)(object)instance?.currentLevel == (Object)null) { return; } MineshaftScrubber.ScrubLevel(instance.currentLevel, "ChooseNewRandomMapSeed"); IntWithRarity[] dungeonFlowTypes = instance.currentLevel.dungeonFlowTypes; if (dungeonFlowTypes == null || dungeonFlowTypes.Length == 0) { return; } if (dungeonFlowTypes.All((IntWithRarity f) => !MineshaftIds.IsMineshaftId(f.id) || f.rarity <= 0)) { Plugin.Log.LogInfo((object)"[ChooseNewRandomMapSeed] Mineshaft already absent/zeroed"); return; } for (int num = 0; num < 1000; num++) { int num2 = ((num == 0) ? __instance.randomMapSeed : Rng.Next(1, 100000000)); int? num3 = Predict(num2, instance); if (num3.HasValue && !MineshaftIds.IsMineshaftId(num3.Value)) { if (num2 != __instance.randomMapSeed) { __instance.randomMapSeed = num2; Plugin.Log.LogInfo((object)$"[ChooseNewRandomMapSeed] rerolled to {num2} (interior {num3}) after {num + 1} tries"); } else { Plugin.Log.LogInfo((object)$"[ChooseNewRandomMapSeed] seed {num2} ok (interior {num3})"); } return; } } Plugin.Log.LogWarning((object)"[ChooseNewRandomMapSeed] failed to find non-Mineshaft seed"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[ChooseNewRandomMapSeed] " + ex.Message)); } } private static int? Predict(int seed, RoundManager manager) { IntWithRarity[] dungeonFlowTypes = manager.currentLevel.dungeonFlowTypes; IntWithRarity[] array = dungeonFlowTypes.Where((IntWithRarity f) => f.rarity > 0).ToArray(); if (array.Length == 0) { array = dungeonFlowTypes; } Random random = new Random(seed); int[] array2 = array.Select((IntWithRarity f) => f.rarity).ToArray(); int randomWeightedIndex = manager.GetRandomWeightedIndex(array2, random); if (randomWeightedIndex < 0 || randomWeightedIndex >= array.Length) { return null; } return array[randomWeightedIndex].id; } } internal static class StartPatch { public static void Postfix() { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return; } Plugin.Log.LogInfo((object)"[StartOfRound.Start] ensuring watcher + scrubbing moons"); DungeonTypeWatcher.EnsureExists(); try { MineshaftScrubber.ScrubAllLevels("StartOfRound.Start"); } catch (Exception ex) { Plugin.Log.LogWarning((object)ex.Message); } } } internal static class DunGenPatch { public static void Prefix(DungeonGenerator __instance) { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return; } try { DungeonFlow dungeonFlow = __instance.DungeonFlow; string text = (((Object)(object)dungeonFlow != (Object)null) ? ((Object)dungeonFlow).name : "null"); Plugin.Log.LogInfo((object)("[DunGen.Generate] flow=" + text)); if (!MineshaftIds.IsMineshaftFlow(dungeonFlow)) { return; } RoundManager instance = RoundManager.Instance; if ((Object)(object)instance == (Object)null) { Plugin.Log.LogWarning((object)"[DunGen.Generate] Mineshaft flow but RoundManager null"); return; } MineshaftScrubber.ScrubLevel(instance.currentLevel, "DunGen.Generate"); int newId; DungeonFlow val = MineshaftScrubber.PickAlternateFlow(instance, out newId); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[DunGen.Generate] no alternate DungeonFlow available"); return; } Plugin.Log.LogInfo((object)$"[DunGen.Generate] REPLACING Mineshaft flow {text} with {((Object)val).name} (id {newId})"); __instance.DungeonFlow = val; instance.currentDungeonType = newId; } catch (Exception arg) { Plugin.Log.LogWarning((object)$"[DunGen.Generate] {arg}"); } } } internal static class GenFloorPostfixPatch { public static void Postfix(RoundManager __instance) { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return; } try { ManualLogSource log = Plugin.Log; object arg = __instance.currentDungeonType; SelectableLevel currentLevel = __instance.currentLevel; log.LogInfo((object)$"[GenerateNewFloor.Post] type={arg} level={((currentLevel != null) ? ((Object)currentLevel).name : null)} isServer={((NetworkBehaviour)__instance).IsServer}"); if (!MineshaftIds.IsMineshaftId(__instance.currentDungeonType)) { return; } MineshaftScrubber.RemapDungeonType(__instance, "GenerateNewFloor.Post"); int newId; DungeonFlow val = MineshaftScrubber.PickAlternateFlow(__instance, out newId); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[GenerateNewFloor.Post] still Mineshaft, no alternate flow"); return; } __instance.currentDungeonType = newId; if (__instance.dungeonGenerator?.Generator != null) { __instance.dungeonGenerator.Generator.DungeonFlow = val; Plugin.Log.LogInfo((object)$"[GenerateNewFloor.Post] forced DungeonFlow={((Object)val).name} id={newId}"); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[GenerateNewFloor.Post] " + ex.Message)); } } } [BepInPlugin("com.benhough.lethal.NoMineshaft", "NoMineshaft", "1.0.6")] public class Plugin : BaseUnityPlugin { public const string ModGuid = "com.benhough.lethal.NoMineshaft"; public const string ModName = "NoMineshaft"; public const string ModVersion = "1.0.6"; private readonly Harmony _harmony = new Harmony("com.benhough.lethal.NoMineshaft"); internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ConfigEntry Enabled { get; private set; } internal static ConfigEntry Verbose { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "When true, Mineshaft interiors are removed from dungeon rotation."); Verbose = ((BaseUnityPlugin)this).Config.Bind("General", "VerboseLogging", true, "Extra Info logs for dungeon scrub/remap/DunGen (debugging)."); if (!Enabled.Value) { Log.LogInfo((object)"NoMineshaft is disabled via config."); return; } ManualPatches.Apply(_harmony); DungeonTypeWatcher.EnsureExists(); Log.LogInfo((object)string.Format("{0} v{1} loaded. Verbose={2}", "NoMineshaft", "1.0.6", Verbose.Value)); } internal static void V(string msg) { if (Verbose != null && Verbose.Value) { Log.LogInfo((object)msg); } } } internal static class PluginInfo { public const string PLUGIN_GUID = "com.benhough.lethal.NoMineshaft"; public const string PLUGIN_NAME = "NoMineshaft"; public const string PLUGIN_VERSION = "1.0.6"; } }