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 NoMineshaft v1.0.6
NoMineshaft.dll
Decompiled 8 hours agousing 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<DungeonTypeWatcher>(); 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<bool> Enabled { get; private set; } internal static ConfigEntry<bool> Verbose { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "When true, Mineshaft interiors are removed from dungeon rotation."); Verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("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"; } }