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 BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using DunGen.Graph; using FacilityMeltdown.API; using HarmonyLib; using Microsoft.CodeAnalysis; using PizzaTowerEscapeMusic; using Unity.Netcode; using UnityEngine; using loaforcsSoundAPI.SoundPacks.Data.Conditions; [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("FacilityMeltdownBlacklist")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.0.2.0")] [assembly: AssemblyInformationalVersion("0.0.2")] [assembly: AssemblyProduct("FacilityMeltdownBlacklist")] [assembly: AssemblyTitle("FacilityMeltdownBlacklist")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.2.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 FacilityMeltdownBlacklist { internal class ConfigManager { internal ConfigEntry BlacklistedMoons { get; } internal ConfigEntry BlacklistedInteriors { get; } internal ConfigEntry BlacklistedMoonTags { get; } internal ConfigEntry BlacklistedInteriorTags { get; } internal ConfigManager(ConfigFile config) { BlacklistedMoons = config.Bind("Facility Meltdown Blacklist Options", "Blacklisted moons", "", "DawnLib moon namespaced keys where apparatus pulls cannot start FacilityMeltdown, separated by commas. E.g. 'lethal_company:experimentation,lethal_company:rend'"); BlacklistedInteriors = config.Bind("Facility Meltdown Blacklist Options", "Blacklisted interiors", "", "DawnLib interior namespaced keys where apparatus pulls cannot start FacilityMeltdown, separated by commas. E.g. 'lethal_company:facility,therubberrooms:rubberroomsflow'"); BlacklistedMoonTags = config.Bind("Facility Meltdown Blacklist Options", "Blacklisted moon tags", "", "DawnLib moon tag namespaced keys where apparatus pulls cannot start FacilityMeltdown, separated by commas. E.g. 'lethal_company:company,lethal_level_loader:valley,lunarcontenttag:argon'"); BlacklistedInteriorTags = config.Bind("Facility Meltdown Blacklist Options", "Blacklisted interior tags", "", "DawnLib interior tag namespaced keys where apparatus pulls cannot start FacilityMeltdown, separated by commas. E.g. 'lethal_company:indoor,gray_apartments_dungeon:dusty'"); } } internal static class FacilityMeltdownPatches { private class ApparatusValue { internal Item Item; internal int Minimum; internal int Maximum; internal ApparatusValue(Item item, int minimum, int maximum) { Item = item; Minimum = minimum; Maximum = maximum; } } private static Item? apparatusItem; private static int originalApparatusMinimumValue; private static int originalApparatusMaximumValue; private static readonly Dictionary originalApparatusValues = new Dictionary(); internal static void OriginalApparatusValue() { apparatusItem = ((Registry)(object)LethalContent.Items)[ItemKeys.Apparatus].Item; originalApparatusMinimumValue = apparatusItem.minValue; originalApparatusMaximumValue = apparatusItem.maxValue; } [HarmonyPatch(typeof(LungProp), "Start")] [HarmonyPrefix] [HarmonyBefore(new string[] { "me.loaforc.facilitymeltdown" })] private static void RememberApparatusValue(LungProp __instance) { if (MeltdownBlacklist.ShouldBlockThisRound()) { originalApparatusValues[((Object)__instance).GetInstanceID()] = ((GrabbableObject)__instance).scrapValue; } } [HarmonyPatch(typeof(LungProp), "Start")] [HarmonyPrefix] [HarmonyAfter(new string[] { "me.loaforc.facilitymeltdown" })] private static void RestoreApparatusValue(LungProp __instance) { if (originalApparatusValues.Remove(((Object)__instance).GetInstanceID(), out var value) && ((GrabbableObject)__instance).scrapValue != value) { ((GrabbableObject)__instance).scrapValue = value; Log.Info($"FacilityMeltdown apparatus value restored to {value}"); } } [HarmonyPatch("FacilityMeltdown.Patches.ApparaticePatch, FacilityMeltdown", "BeginMeltdownSequence")] [HarmonyPrefix] private static bool BeginMeltdownSequencePrefix(LungProp __0, ref bool __1) { return !((NetworkBehaviour)__0).IsHost || !__1 || MeltdownAPI.MeltdownStarted || !MeltdownBlacklist.ShouldBlockThisRound(); } [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] [HarmonyPrefix] private static void SpawnScrapInLevelPrefix(out ApparatusValue? __state) { __state = null; Item val = apparatusItem; if (Object.op_Implicit((Object)(object)val) && MeltdownBlacklist.ShouldBlockThisRound() && (val.minValue != originalApparatusMinimumValue || val.maxValue != originalApparatusMaximumValue)) { __state = new ApparatusValue(val, val.minValue, val.maxValue); val.minValue = originalApparatusMinimumValue; val.maxValue = originalApparatusMaximumValue; Log.Info($"Apparatus generated from vanilla value range {originalApparatusMinimumValue}-{originalApparatusMaximumValue}"); } } [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] [HarmonyPostfix] private static void SpawnScrapInLevelPostfix(ApparatusValue __state) { if (__state != null) { __state.Item.minValue = __state.Minimum; __state.Item.maxValue = __state.Maximum; } } } internal static class Log { internal static void Debug(string message) { Write((LogLevel)32, message); } internal static void Info(string message) { Write((LogLevel)16, message); } internal static void Warn(string message) { Write((LogLevel)4, message); } internal static void Error(string message) { Write((LogLevel)2, message); } internal static void Fatal(string message) { Write((LogLevel)1, message); } private static void Write(LogLevel logLevel, string message) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (Plugin.mls != null) { Plugin.mls.Log(logLevel, (object)message); } } } internal static class MeltdownBlacklist { internal static bool ShouldBlockThisRound() { RoundManager instance = RoundManager.Instance; DawnMoonInfo dawnInfo = SelectableLevelExtensions.GetDawnInfo(instance.currentLevel); if (Listed(Plugin.Configs.BlacklistedMoons.Value, ((DawnBaseInfo)(object)dawnInfo).Key) || Tagged((DawnBaseInfo)(object)dawnInfo, Plugin.Configs.BlacklistedMoonTags.Value)) { Log.Info($"Meltdown blocked on moon {((DawnBaseInfo)(object)dawnInfo).Key}"); return true; } DungeonFlow dungeonFlow = instance.dungeonFlowTypes[instance.currentDungeonType].dungeonFlow; DawnDungeonInfo val = default(DawnDungeonInfo); if (!DungeonFlowExtensions.TryGetDawnInfo(dungeonFlow, ref val)) { return false; } if (Listed(Plugin.Configs.BlacklistedInteriors.Value, ((DawnBaseInfo)(object)val).Key) || Tagged((DawnBaseInfo)(object)val, Plugin.Configs.BlacklistedInteriorTags.Value)) { Log.Info($"Meltdown blocked in interior {((DawnBaseInfo)(object)val).Key}"); return true; } return false; } private static bool Listed(string rawList, NamespacedKey key) { foreach (NamespacedKey item in Keys(rawList)) { if (((object)item).Equals((object?)key)) { return true; } } return false; } private static bool Tagged(DawnBaseInfo info, string rawTags) where T : DawnBaseInfo { foreach (NamespacedKey item in Keys(rawTags)) { if (info.HasTag(item)) { return true; } } return false; } private static IEnumerable Keys(string rawList) { string[] array = rawList.Split(','); NamespacedKey key = default(NamespacedKey); foreach (string rawEntry in array) { if (NamespacedKey.TryParse(rawEntry.Trim(), ref key)) { yield return key; } key = null; } } } [HarmonyPatch(typeof(LungProp), "Start")] internal static class MoreShipUpgradesCompatibilityPatches { private static readonly Dictionary originalApparatusValues = new Dictionary(); [HarmonyPrefix] [HarmonyBefore(new string[] { "me.loaforc.facilitymeltdown" })] private static void StartPrefixBeforeFM(LungProp __instance) { if (MeltdownBlacklist.ShouldBlockThisRound()) { originalApparatusValues[((Object)__instance).GetInstanceID()] = ((GrabbableObject)__instance).scrapValue; } } [HarmonyPostfix] [HarmonyBefore(new string[] { "com.malco.lethalcompany.moreshipupgrades" })] private static void StartPrefixBeforeLGU(LungProp __instance) { if (originalApparatusValues.Remove(((Object)__instance).GetInstanceID(), out var value) && ((GrabbableObject)__instance).scrapValue != value) { ((GrabbableObject)__instance).scrapValue = value; Log.Info($"FacilityMeltdown apparatus value removed before Midas Touch applied to {value}"); } } } internal static class PizzaTowerEscapeMusicCompatibilityPatches { [HarmonyPatch(typeof(GameEventListener), "CheckApparatusTaken")] [HarmonyPrefix] private static bool CheckApparatusTakenPrefix(ref LungProp? ____dockedApparatus) { if (!Object.op_Implicit((Object)(object)____dockedApparatus) || ____dockedApparatus.isLungDocked) { return true; } if (!MeltdownBlacklist.ShouldBlockThisRound()) { return true; } ____dockedApparatus = null; Plugin.mls.LogInfo((object)"PizzaTowerEscapeMusic blocked"); return false; } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("MrHat.FacilityMeltdownBlacklist", "FacilityMeltdownBlacklist", "0.0.2")] internal class Plugin : BaseUnityPlugin { internal const string modGUID = "MrHat.FacilityMeltdownBlacklist"; internal const string modName = "FacilityMeltdownBlacklist"; private const string modVersion = "0.0.2"; internal const string DawnLibGUID = "com.github.teamxiaolan.dawnlib"; internal const string DuskGUID = "com.github.teamxiaolan.dawnlib.dusk"; internal const string FacilityMeltdownGUID = "me.loaforc.facilitymeltdown"; internal const string SoundAPIGUID = "me.loaforc.soundapi"; internal const string PizzaTowerEscapeMusicGUID = "bgn.pizzatowerescapemusic"; internal const string MoreShipUpgradesGUID = "com.malco.lethalcompany.moreshipupgrades"; internal static Harmony _harmony; internal static ManualLogSource mls; internal static bool hasSoundAPI; internal static bool hasPizzaTowerEscapeMusic; internal static bool hasMoreShipUpgrades; internal static Plugin Instance { get; private set; } internal static ConfigManager Configs { get; private set; } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Instance = this; mls = Logger.CreateLogSource("MrHat.FacilityMeltdownBlacklist"); _harmony = new Harmony("MrHat.FacilityMeltdownBlacklist"); hasSoundAPI = Chainloader.PluginInfos.ContainsKey("me.loaforc.soundapi"); hasPizzaTowerEscapeMusic = Chainloader.PluginInfos.ContainsKey("bgn.pizzatowerescapemusic"); hasMoreShipUpgrades = Chainloader.PluginInfos.ContainsKey("com.malco.lethalcompany.moreshipupgrades"); ((Registry)(object)LethalContent.Items).BeforeFreeze += FacilityMeltdownPatches.OriginalApparatusValue; Configs = new ConfigManager(((BaseUnityPlugin)this).Config); Log.Info("Blacklisted moons " + (string.IsNullOrWhiteSpace(Configs.BlacklistedMoons.Value) ? "none" : Configs.BlacklistedMoons.Value)); Log.Info("Blacklisted interiors " + (string.IsNullOrWhiteSpace(Configs.BlacklistedInteriors.Value) ? "none" : Configs.BlacklistedInteriors.Value)); Log.Info("Blacklisted moon tags " + (string.IsNullOrWhiteSpace(Configs.BlacklistedMoonTags.Value) ? "none" : Configs.BlacklistedMoonTags.Value)); Log.Info("Blacklisted interior tags " + (string.IsNullOrWhiteSpace(Configs.BlacklistedInteriorTags.Value) ? "none" : Configs.BlacklistedInteriorTags.Value)); _harmony.PatchAll(typeof(FacilityMeltdownPatches)); if (hasSoundAPI) { _harmony.PatchAll(typeof(SoundAPICompatibilityPatches)); mls.LogDebug((object)"Ran SoundAPI compat"); } if (hasPizzaTowerEscapeMusic) { _harmony.PatchAll(typeof(PizzaTowerEscapeMusicCompatibilityPatches)); Log.Debug("Ran PizzaTowerEscapeMusic compat"); } if (hasMoreShipUpgrades) { _harmony.PatchAll(typeof(MoreShipUpgradesCompatibilityPatches)); Log.Debug("Ran LGU compat"); } } } internal static class SoundAPICompatibilityPatches { private static bool loggedIncompatibleCondition; [HarmonyPatch(typeof(Conditional), "Evaluate")] [HarmonyFinalizer] private static Exception? EvaluateFinalizer(Exception? __exception, ref bool __result) { if (!(__exception is TypeLoadException)) { return __exception; } __result = false; if (!loggedIncompatibleCondition) { loggedIncompatibleCondition = true; Log.Warn("SoundAPI did something I did not want it to do."); } return null; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "FacilityMeltdownBlacklist"; public const string PLUGIN_NAME = "FacilityMeltdownBlacklist"; public const string PLUGIN_VERSION = "0.0.2"; } }