using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [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("HostInteriorSelector")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.3.0")] [assembly: AssemblyInformationalVersion("0.1.3")] [assembly: AssemblyProduct("HostInteriorSelector")] [assembly: AssemblyTitle("HostInteriorSelector")] [assembly: AssemblyVersion("0.1.3.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 HostInteriorSelector { [HarmonyPatch(typeof(RoundManager), "GenerateNewFloor")] internal static class InteriorFilterPatch { private enum VanillaInterior { Unknown, Factory, Mansion, Mineshaft } internal sealed class FilterState { internal SelectableLevel? Level; internal IntWithRarity[]? Original; } [HarmonyPrefix] private static void Prefix(RoundManager __instance, out FilterState __state) { __state = new FilterState(); try { if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost || (Plugin.FactoryEnabled.Value && Plugin.MansionEnabled.Value && Plugin.MineshaftEnabled.Value)) { return; } SelectableLevel currentLevel = __instance.currentLevel; IntWithRarity[] array = currentLevel?.dungeonFlowTypes; if ((Object)(object)currentLevel == (Object)null || array == null || array.Length == 0) { Plugin.Log.LogWarning((object)"Interior filtering skipped: the current level has no dungeon-flow choices."); return; } Dictionary discovered = new Dictionary(); for (int i = 0; i < __instance.dungeonFlowTypes.Length; i++) { string displayName; VanillaInterior vanillaInterior = Identify(__instance.dungeonFlowTypes[i], i, out displayName); discovered[i] = vanillaInterior; Plugin.Log.LogInfo((object)$"Interior definition [{i}] '{displayName}' classified as {vanillaInterior}."); } IntWithRarity[] array2 = array.Where((IntWithRarity entry) => IsAllowed(entry, discovered)).ToArray(); if (array2.Length == array.Length) { Plugin.Log.LogInfo((object)"Host interior settings did not remove any choices for this level."); return; } if (array2.Length == 0) { array2 = CreateFallbackChoices(discovered); if (array2.Length == 0) { Plugin.Log.LogWarning((object)"Interior settings left no valid choice and no enabled vanilla definition could be found; using the game's unmodified list for safe generation."); return; } Plugin.Log.LogInfo((object)$"This moon offered none of the enabled vanilla interiors; supplied {array2.Length} enabled global choice(s) to generation."); } __state.Level = currentLevel; __state.Original = array; currentLevel.dungeonFlowTypes = array2; Plugin.Log.LogInfo((object)$"Host filtered interior choices from {array.Length} to {array2.Length}; unknown/custom interiors were preserved."); } catch (Exception arg) { Restore(__state); Plugin.Log.LogError((object)$"Interior filtering failed safely; vanilla selection will be used. {arg}"); } } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, RoundManager __instance, FilterState __state) { if (__state.Original != null && __instance.currentDungeonType >= 0 && __instance.currentDungeonType < __instance.dungeonFlowTypes.Length) { string displayName; VanillaInterior vanillaInterior = Identify(__instance.dungeonFlowTypes[__instance.currentDungeonType], __instance.currentDungeonType, out displayName); Plugin.Log.LogInfo((object)$"Host selected interior [{__instance.currentDungeonType}] '{displayName}' classified as {vanillaInterior}."); if (!IsKindEnabled(vanillaInterior)) { Plugin.Log.LogWarning((object)$"The game selected disabled interior {vanillaInterior}; please report the surrounding Interior Selector log lines."); } } Restore(__state); return __exception; } private static bool IsAllowed(IntWithRarity entry, Dictionary discovered) { if (!discovered.TryGetValue(entry.id, out var value)) { return true; } return IsKindEnabled(value); } private static IntWithRarity[] CreateFallbackChoices(Dictionary discovered) { return (from pair in discovered where pair.Value != VanillaInterior.Unknown && IsKindEnabled(pair.Value) group pair by pair.Value).Select((Func>, IntWithRarity>)((IGrouping> group) => new IntWithRarity(group.First().Key, 1, (LevelAmbienceLibrary)null))).ToArray(); } private static bool IsKindEnabled(VanillaInterior kind) { return kind switch { VanillaInterior.Factory => Plugin.FactoryEnabled.Value, VanillaInterior.Mansion => Plugin.MansionEnabled.Value, VanillaInterior.Mineshaft => Plugin.MineshaftEnabled.Value, _ => true, }; } private static VanillaInterior Identify(IndoorMapType map, int index, out string displayName) { object obj = ((object)map)?.GetType().GetField("dungeonFlow", BindingFlags.Instance | BindingFlags.Public)?.GetValue(map); Object val = (Object)((obj is Object) ? obj : null); displayName = ((val != null) ? val.name : (obj?.ToString() ?? "")); string text = new string(displayName.Where(char.IsLetterOrDigit).Select(char.ToLowerInvariant).ToArray()); if (text.Contains("mine") || text.Contains("cave")) { return VanillaInterior.Mineshaft; } if (text.Contains("mansion") || text.Contains("manor")) { return VanillaInterior.Mansion; } if (text.Contains("factory") || text.Contains("facility")) { return VanillaInterior.Factory; } if (text.StartsWith("level1flow", StringComparison.Ordinal)) { return VanillaInterior.Factory; } if (text.StartsWith("level2flow", StringComparison.Ordinal)) { return VanillaInterior.Mansion; } if (text.StartsWith("level3flow", StringComparison.Ordinal) || text.StartsWith("level4flow", StringComparison.Ordinal)) { return VanillaInterior.Mineshaft; } switch (index) { case 0: case 2: case 3: return VanillaInterior.Factory; case 1: return VanillaInterior.Mansion; case 4: return VanillaInterior.Mineshaft; default: return VanillaInterior.Unknown; } } private static void Restore(FilterState? state) { if ((Object)(object)state?.Level != (Object)null && state.Original != null) { state.Level.dungeonFlowTypes = state.Original; state.Level = null; state.Original = null; } } } [HarmonyPatch(typeof(MenuManager), "Start")] internal static class MenuPatch { [HarmonyPostfix] private static void Postfix(MenuManager __instance) { if (!((Object)(object)__instance == (Object)null) && !__instance.isInitScene && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { Transform val = (((Object)(object)__instance.menuButtons != (Object)null) ? __instance.menuButtons.transform.parent : null); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"Main-menu canvas was not found; Interior Selector UI was not created."); } else { ((Component)__instance).gameObject.AddComponent().Build(val, __instance.versionNumberText); } } } } internal sealed class InteriorSelectorMenu : MonoBehaviour { private GameObject _panel; private Toggle _factory; private Toggle _mansion; private Toggle _mineshaft; private TextMeshProUGUI _validationText; private TMP_FontAsset? _font; internal void Build(Transform menuRoot, TextMeshProUGUI fontSource) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Expected O, but got Unknown _font = (((Object)(object)fontSource != (Object)null) ? ((TMP_Text)fontSource).font : null); ((UnityEvent)CreateButton(menuRoot, "Interior Selector", new Vector2(0.5f, 0f), new Vector2(0f, 72f), new Vector2(260f, 48f)).onClick).AddListener(new UnityAction(Open)); _panel = CreateRect("InteriorSelectorPanel", menuRoot, new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(460f, 410f)); _panel.transform.SetAsLastSibling(); ((Graphic)_panel.AddComponent()).color = new Color(0.035f, 0.055f, 0.045f, 0.97f); CreateText(_panel.transform, "Interior Selector", new Vector2(0f, 150f), new Vector2(400f, 55f), 30f, (TextAlignmentOptions)514); CreateText(_panel.transform, "Used only when you host", new Vector2(0f, 112f), new Vector2(400f, 35f), 17f, (TextAlignmentOptions)514); _factory = CreateToggle(_panel.transform, "Factory", 55f); _mansion = CreateToggle(_panel.transform, "Mansion", 0f); _mineshaft = CreateToggle(_panel.transform, "Mineshaft", -55f); _validationText = CreateText(_panel.transform, string.Empty, new Vector2(0f, -98f), new Vector2(400f, 32f), 16f, (TextAlignmentOptions)514); ((Graphic)_validationText).color = new Color(1f, 0.45f, 0.4f, 1f); ((UnityEvent)CreateButton(_panel.transform, "Save & Close", new Vector2(0.5f, 0.5f), new Vector2(0f, -140f), new Vector2(220f, 48f)).onClick).AddListener(new UnityAction(SaveAndClose)); _panel.SetActive(false); Plugin.Log.LogInfo((object)"Interior Selector button added to the current main menu."); } private void Open() { _factory.isOn = Plugin.FactoryEnabled.Value; _mansion.isOn = Plugin.MansionEnabled.Value; _mineshaft.isOn = Plugin.MineshaftEnabled.Value; ((TMP_Text)_validationText).text = string.Empty; _panel.SetActive(true); } private void SaveAndClose() { if (!_factory.isOn && !_mansion.isOn && !_mineshaft.isOn) { ((TMP_Text)_validationText).text = "Select at least one interior."; Plugin.Log.LogWarning((object)"Interior settings were not saved because every option was disabled."); return; } Plugin.FactoryEnabled.Value = _factory.isOn; Plugin.MansionEnabled.Value = _mansion.isOn; Plugin.MineshaftEnabled.Value = _mineshaft.isOn; Plugin.Settings.Save(); _panel.SetActive(false); Plugin.Log.LogInfo((object)$"Saved interior settings: Factory={_factory.isOn}, Mansion={_mansion.isOn}, Mineshaft={_mineshaft.isOn}."); } private Toggle CreateToggle(Transform parent, string label, float y) { //IL_0016: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) GameObject val = CreateRect(label + "Toggle", parent, new Vector2(0.5f, 0.5f), new Vector2(0f, y), new Vector2(310f, 44f)); Toggle obj = val.AddComponent(); GameObject val2 = CreateRect("Box", val.transform, new Vector2(0f, 0.5f), new Vector2(22f, 0f), new Vector2(32f, 32f)); Image val3 = val2.AddComponent(); ((Graphic)val3).color = new Color(0.16f, 0.2f, 0.17f, 1f); Image val4 = CreateRect("Checkmark", val2.transform, new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(22f, 22f)).AddComponent(); ((Graphic)val4).color = new Color(0.42f, 0.85f, 0.5f, 1f); ((Selectable)obj).targetGraphic = (Graphic)(object)val3; obj.graphic = (Graphic)(object)val4; CreateText(val.transform, label, new Vector2(48f, 0f), new Vector2(250f, 44f), 23f, (TextAlignmentOptions)513); return obj; } private Button CreateButton(Transform parent, string label, Vector2 anchor, Vector2 position, Vector2 size) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) GameObject val = CreateRect(label.Replace(" ", "") + "Button", parent, anchor, position, size); Image val2 = val.AddComponent(); ((Graphic)val2).color = new Color(0.12f, 0.24f, 0.16f, 0.98f); Button obj = val.AddComponent