Decompiled source of CiCisTrinketAndBindingFramework v2.1.4
plugins\TrinketAndBindingFramework\TrinketAndBindingFramework.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TMPro; using UnityEngine; using UnityEngine.EventSystems; 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("TrinketAndBindingFramework")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("TrinketAndBindingFramework")] [assembly: AssemblyTitle("TrinketAndBindingFramework")] [assembly: AssemblyVersion("1.0.0.0")] [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 TrinketAndBindingFramework { public static class CustomModeRegistry { public enum Difficulty { Easy, Medium, Hard, Extreme } public class Mode { public string Id; public string DisplayName; public string Description; public Difficulty Difficulty; public Action<bool> OnToggle; public List<string> ExclusiveSettingIds; public bool DisablesLeaderboards; public string HoverCreditText; internal GamemodeSetting RuntimeSetting; public string SourceMod; public string SourceModGuid; } internal static readonly Dictionary<string, Mode> _modes = new Dictionary<string, Mode>(StringComparer.Ordinal); internal static readonly List<(string[] ids, string display)> _combos = new List<(string[], string)>(); internal static readonly Dictionary<string, string> _disabledLocks = new Dictionary<string, string>(StringComparer.Ordinal); internal static readonly List<(string a, string b)> _mutualLinks = new List<(string, string)>(); internal static readonly HashSet<string> _injectedGamemodes = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly Dictionary<string, string> _gamemodeAliases = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); internal static Color LinkColor = new Color(1f, 0.55f, 0.1f, 1f); public static IReadOnlyDictionary<string, Mode> All => _modes; public static void Register(string id, string displayName, string description, Difficulty difficulty, Action<bool> onToggle, string[] exclusiveSettingIds = null, bool disablesLeaderboards = true, string hoverCreditText = null) { if (string.IsNullOrEmpty(id)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[CustomModeRegistry] empty id, skipped"); } return; } TrinketRegistry.DetectCallingMod(out var name, out var guid); _modes[id] = new Mode { Id = id, DisplayName = (displayName ?? id), Description = (description ?? ""), Difficulty = difficulty, OnToggle = onToggle, ExclusiveSettingIds = ((exclusiveSettingIds != null) ? new List<string>(exclusiveSettingIds) : new List<string>()), DisablesLeaderboards = disablesLeaderboards, HoverCreditText = hoverCreditText, SourceMod = name, SourceModGuid = guid }; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[CustomModeRegistry] mode: " + id + ((name != null) ? (" (from " + name + ")") : ""))); } } public static void RegisterCombo(string[] modeIds, string displayName) { if (modeIds != null && modeIds.Length >= 2 && !string.IsNullOrEmpty(displayName)) { string[] array = (string[])modeIds.Clone(); Array.Sort(array, (IComparer<string>?)StringComparer.Ordinal); _combos.Add((array, displayName)); } } public static void RegisterDisabledLock(string modeId, string lockText = "WIP") { if (!string.IsNullOrEmpty(modeId)) { _disabledLocks[modeId] = lockText ?? "WIP"; } } public static void RegisterMutualLink(string idA, string idB) { if (!string.IsNullOrEmpty(idA) && !string.IsNullOrEmpty(idB)) { _mutualLinks.Add((idA, idB)); } } public static void InjectIntoGamemode(string gamemodeName) { if (!string.IsNullOrEmpty(gamemodeName)) { _injectedGamemodes.Add(gamemodeName); } } public static void RegisterGamemodeAlias(string aliasGamemodeName, string sourceGamemodeName) { if (!string.IsNullOrEmpty(aliasGamemodeName) && !string.IsNullOrEmpty(sourceGamemodeName)) { _gamemodeAliases[aliasGamemodeName] = sourceGamemodeName; } } public static bool IsActive(string id) { if (string.IsNullOrEmpty(id)) { return false; } M_Gamemode currentGamemode = CL_GameManager.GetCurrentGamemode(); if ((Object)(object)currentGamemode == (Object)null) { return false; } try { return currentGamemode.HasActiveSetting(id); } catch { return false; } } public static bool AnyActive() { M_Gamemode currentGamemode = CL_GameManager.GetCurrentGamemode(); if ((Object)(object)currentGamemode == (Object)null) { return false; } foreach (string key in _modes.Keys) { try { if (currentGamemode.HasActiveSetting(key)) { return true; } } catch { } } return false; } public static bool IsDisabled(string id) { if (!string.IsNullOrEmpty(id)) { return _disabledLocks.ContainsKey(id); } return false; } public static string GetLockText(string id) { if (!_disabledLocks.TryGetValue(id ?? "", out var value)) { return "WIP"; } return value; } internal static bool ShouldShowLinkColor(string id) { if (IsDisabled(id)) { return false; } foreach (var (id2, text) in _mutualLinks) { if (id == text && IsActive(id2) && !IsActive(text)) { return true; } } return false; } internal static Color DifficultyColor(Difficulty d) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_0079: Unknown result type (might be due to invalid IL or missing references) return (Color)(d switch { Difficulty.Easy => new Color(0f, 1f, 0f), Difficulty.Medium => new Color(1f, 0.65f, 0f), Difficulty.Hard => new Color(1f, 0f, 0f), Difficulty.Extreme => new Color(0.7f, 0.12f, 0f), _ => Color.white, }); } } internal static class CustomModePickerIntegration { private static ProgressionUnlock _alwaysUnlocked; private static bool _built; private static int _builtModeCount; internal static void EnsureBuilt() { //IL_00f9: 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) if (_built && _builtModeCount == CustomModeRegistry._modes.Count) { return; } if ((Object)(object)_alwaysUnlocked == (Object)null) { _alwaysUnlocked = ScriptableObject.CreateInstance<ProgressionUnlock>(); ((Object)_alwaysUnlocked).name = "CiCi_CustomMode_AlwaysUnlocked"; _alwaysUnlocked.unlockRequirements = new List<UnlockRequirement>(); _alwaysUnlocked.state = true; _alwaysUnlocked.unlockHint = ""; _alwaysUnlocked.progressionString = ""; Object.DontDestroyOnLoad((Object)(object)_alwaysUnlocked); } foreach (KeyValuePair<string, CustomModeRegistry.Mode> mode in CustomModeRegistry._modes) { CustomModeRegistry.Mode value = mode.Value; if (!((Object)(object)value.RuntimeSetting != (Object)null)) { GamemodeSetting val = ScriptableObject.CreateInstance<GamemodeSetting>(); ((Object)val).name = "GamemodeSetting_CustomMode_" + value.Id; val.id = value.Id; val.title = value.DisplayName; val.description = value.Description; val.color = CustomModeRegistry.DifficultyColor(value.Difficulty); val.unlock = _alwaysUnlocked; val.exclusiveSettings = new List<string>(value.ExclusiveSettingIds ?? new List<string>()); val.nameAppend = ""; val.leaderboardAppendID = ""; Object.DontDestroyOnLoad((Object)(object)val); value.RuntimeSetting = val; } } _built = true; _builtModeCount = CustomModeRegistry._modes.Count; } internal static void InjectInto(M_Gamemode gm) { if ((Object)(object)gm == (Object)null) { return; } EnsureBuilt(); string item = gm.gamemodeName ?? ""; if (!CustomModeRegistry._injectedGamemodes.Contains(item)) { return; } if (gm.gamemodeSettings == null) { gm.gamemodeSettings = new List<GamemodeSetting>(); } foreach (CustomModeRegistry.Mode value in CustomModeRegistry._modes.Values) { if (!((Object)(object)value.RuntimeSetting == (Object)null) && !gm.gamemodeSettings.Contains(value.RuntimeSetting)) { gm.gamemodeSettings.Add(value.RuntimeSetting); } } } } [HarmonyPatch(typeof(UI_GamemodeSetting), "ToggleSetting")] internal static class CustomModeToggleSyncPatch { [HarmonyPostfix] private static void Postfix(UI_GamemodeSetting __instance, bool b) { GamemodeSetting val = __instance?.gamemodeSetting; if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(val.id) || !CustomModeRegistry._modes.TryGetValue(val.id, out var value)) { return; } if (CustomModeRegistry.IsDisabled(val.id)) { try { value.OnToggle?.Invoke(obj: false); } catch { } if ((Object)(object)__instance.toggle != (Object)null && __instance.toggle.isOn) { try { __instance.toggle.SetIsOnWithoutNotify(false); } catch { try { __instance.toggle.isOn = false; } catch { } } } UI_GamemodeScreen_Panel panel = GamemodeSettingUnlockBypass.GetPanel(__instance); M_Gamemode val2 = ((panel != null) ? panel.GetGamemode() : null); object obj4; if (!((Object)(object)val2 != (Object)null)) { obj4 = null; } else { SaveData saveData = StatManager.saveData; obj4 = ((saveData != null) ? saveData.GetGameMode(val2.gamemodeName) : null); } ((GameModeData)(obj4?)).activeSettings?.Remove(val.id); return; } try { value.OnToggle?.Invoke(b); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CustomMode] Toggle " + val.id + " failed: " + ex.Message)); } } UI_GamemodeScreen_Panel panel2 = GamemodeSettingUnlockBypass.GetPanel(__instance); M_Gamemode val3 = ((panel2 != null) ? panel2.GetGamemode() : null); if ((Object)(object)val3 != (Object)null) { LeaderboardGate.Apply(LeaderboardGate.ShouldDisableForGamemode(val3)); } LeaderboardWarning.RefreshAll(); CustomModeLinks.RefreshLinkedSetting(__instance); UI_GamemodeOptionsText[] array = Object.FindObjectsOfType<UI_GamemodeOptionsText>(); foreach (UI_GamemodeOptionsText val4 in array) { if ((Object)(object)val4 != (Object)null) { try { val4.Refresh(); } catch { } } } } } [HarmonyPatch(typeof(UI_GamemodeSetting), "ToggleSetting")] internal static class CustomModeDisabledToggleBlockPatch { [HarmonyPrefix] private static bool Prefix(UI_GamemodeSetting __instance) { return !CustomModeRegistry.IsDisabled(__instance?.gamemodeSetting?.id); } } [HarmonyPatch(typeof(M_Gamemode), "StartFreshGamemode")] internal static class CustomModeStartSyncPatch { [HarmonyPostfix] private static void Postfix(M_Gamemode __instance) { if ((Object)(object)__instance == (Object)null || CustomModeRegistry._modes.Count == 0) { return; } string text = __instance.gamemodeName ?? ""; string text2 = text; if (CustomModeRegistry._gamemodeAliases.TryGetValue(text, out var value)) { text2 = value; } if (!CustomModeRegistry._injectedGamemodes.Contains(text2)) { foreach (CustomModeRegistry.Mode value2 in CustomModeRegistry._modes.Values) { try { value2.OnToggle?.Invoke(obj: false); } catch { } } return; } M_Gamemode val = ((text2 == text) ? __instance : FindGamemodeByName(text2)); foreach (KeyValuePair<string, CustomModeRegistry.Mode> mode in CustomModeRegistry._modes) { if (CustomModeRegistry.IsDisabled(mode.Key)) { try { mode.Value.OnToggle?.Invoke(obj: false); } catch { } continue; } bool obj3 = false; try { obj3 = val != null && val.HasActiveSetting(mode.Key); } catch { } try { mode.Value.OnToggle?.Invoke(obj3); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CustomMode] Start sync " + mode.Key + " failed: " + ex.Message)); } } } } private static M_Gamemode FindGamemodeByName(string name) { M_Gamemode[] array = Resources.FindObjectsOfTypeAll<M_Gamemode>(); if (array == null) { return null; } foreach (M_Gamemode val in array) { if ((Object)(object)val != (Object)null && string.Equals(val.gamemodeName, name, StringComparison.OrdinalIgnoreCase)) { return val; } } return null; } } [HarmonyPatch(typeof(UI_GamemodeScreen), "Initialize")] internal static class CustomModeSaveDataCleanupPatch { [HarmonyPostfix] private static void Postfix(M_Gamemode mode) { if ((Object)(object)mode == (Object)null || CustomModeRegistry._disabledLocks.Count == 0) { return; } SaveData saveData = StatManager.saveData; List<string> list = ((saveData != null) ? saveData.GetGameMode(mode.gamemodeName) : null)?.activeSettings; if (list == null) { return; } for (int num = list.Count - 1; num >= 0; num--) { if (CustomModeRegistry.IsDisabled(list[num])) { list.RemoveAt(num); } } foreach (string key in CustomModeRegistry._disabledLocks.Keys) { if (CustomModeRegistry._modes.TryGetValue(key, out var value)) { try { value.OnToggle?.Invoke(obj: false); } catch { } } } } } internal static class CustomModeLinks { private static readonly MethodInfo _updateColorMethod = AccessTools.Method(typeof(UI_GamemodeSetting), "UpdateColor", (Type[])null, (Type[])null); public static void RefreshLinkedSetting(UI_GamemodeSetting source) { string text = source?.gamemodeSetting?.id; if (string.IsNullOrEmpty(text)) { return; } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (var (text2, text3) in CustomModeRegistry._mutualLinks) { if (text2 == text) { hashSet.Add(text3); } if (text3 == text) { hashSet.Add(text2); } } if (hashSet.Count == 0) { return; } UI_GamemodeScreen_Panel panel = GamemodeSettingUnlockBypass.GetPanel(source); if ((Object)(object)panel == (Object)null) { return; } UI_GamemodeSetting[] componentsInChildren = ((Component)panel).GetComponentsInChildren<UI_GamemodeSetting>(true); foreach (UI_GamemodeSetting val in componentsInChildren) { string text4 = val?.gamemodeSetting?.id; if (text4 == null || !hashSet.Contains(text4)) { continue; } try { _updateColorMethod?.Invoke(val, null); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CustomModeLinks] Refresh " + text4 + " failed: " + ex.Message)); } } } } } [HarmonyPatch(typeof(UI_GamemodeSetting), "UpdateColor")] [HarmonyPriority(200)] internal static class CustomModeLinkColorPatch { [HarmonyPostfix] private static void Postfix(UI_GamemodeSetting __instance) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if (!CustomModeRegistry.ShouldShowLinkColor(__instance?.gamemodeSetting?.id)) { return; } Color linkColor = CustomModeRegistry.LinkColor; if ((Object)(object)__instance.outline != (Object)null) { ((Graphic)__instance.outline).color = linkColor; } if ((Object)(object)__instance.titleText != (Object)null) { ((Graphic)__instance.titleText).color = linkColor; } if ((Object)(object)__instance.descriptionText != (Object)null) { ((Graphic)__instance.descriptionText).color = linkColor; } if ((Object)(object)__instance.toggle != (Object)null) { if ((Object)(object)((Selectable)__instance.toggle).targetGraphic != (Object)null) { ((Selectable)__instance.toggle).targetGraphic.color = linkColor; } if ((Object)(object)__instance.toggle.graphic != (Object)null) { __instance.toggle.graphic.color = linkColor; } } } } [HarmonyPatch(typeof(UI_GamemodeSetting), "UpdateColor")] [HarmonyPriority(200)] internal static class CustomModeDisabledLockColorPatch { [HarmonyPostfix] private static void Postfix(UI_GamemodeSetting __instance) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) string id = __instance?.gamemodeSetting?.id; if (!CustomModeRegistry.IsDisabled(id)) { return; } if ((Object)(object)__instance.toggle != (Object)null) { ((Selectable)__instance.toggle).interactable = false; } if ((Object)(object)__instance.lockObject != (Object)null) { __instance.lockObject.SetActive(true); } if ((Object)(object)__instance.descriptionText != (Object)null) { __instance.descriptionText.text = CustomModeRegistry.GetLockText(id); } Color grey = Color.grey; if ((Object)(object)__instance.outline != (Object)null) { ((Graphic)__instance.outline).color = grey; } if ((Object)(object)__instance.titleText != (Object)null) { ((Graphic)__instance.titleText).color = grey; } if ((Object)(object)__instance.descriptionText != (Object)null) { ((Graphic)__instance.descriptionText).color = grey; } if ((Object)(object)__instance.unlockHint != (Object)null) { ((Graphic)__instance.unlockHint).color = grey; } if ((Object)(object)__instance.toggle != (Object)null) { if ((Object)(object)((Selectable)__instance.toggle).targetGraphic != (Object)null) { ((Selectable)__instance.toggle).targetGraphic.color = grey; } if ((Object)(object)__instance.toggle.graphic != (Object)null) { __instance.toggle.graphic.color = grey; } } } } [HarmonyPatch(typeof(GamemodeSettingUnlockBypass), "ForceUnlocked")] internal static class CustomModeSkipForceUnlockPatch { [HarmonyPrefix] private static bool Prefix(UI_GamemodeSetting inst) { return !CustomModeRegistry.IsDisabled(inst?.gamemodeSetting?.id); } } internal static class CustomModeCredit { private const string ObjectName = "CiCi_CustomModeCreditText"; private static readonly Dictionary<UI_GamemodeScreen_Panel, TextMeshProUGUI> _byPanel = new Dictionary<UI_GamemodeScreen_Panel, TextMeshProUGUI>(); public static void EnsureForPanel(UI_GamemodeScreen_Panel panel) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)panel == (Object)null || (_byPanel.TryGetValue(panel, out var value) && (Object)(object)value != (Object)null)) { return; } Transform settingRoot = panel.settingRoot; if ((Object)(object)settingRoot == (Object)null) { return; } Transform parent = settingRoot.parent; if ((Object)(object)parent != (Object)null && ((Object)parent).name == "CiCi_SettingsScrollViewport") { parent = parent.parent; } RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (!((Object)(object)val == (Object)null)) { TMP_FontAsset val2 = null; TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null) { val2 = ((TMP_Text)componentInChildren).font; } GameObject val3 = new GameObject("CiCi_CustomModeCreditText", new Type[1] { typeof(RectTransform) }); RectTransform val4 = (RectTransform)val3.transform; ((Transform)val4).SetParent((Transform)(object)val, false); val4.anchorMin = new Vector2(0f, 0f); val4.anchorMax = new Vector2(1f, 0f); val4.pivot = new Vector2(0.5f, 0f); val4.anchoredPosition = new Vector2(0f, 4f); val4.sizeDelta = new Vector2(-20f, 22f); TextMeshProUGUI val5 = val3.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val5).text = ""; ((TMP_Text)val5).fontSize = 14f; ((TMP_Text)val5).alignment = (TextAlignmentOptions)514; ((Graphic)val5).color = new Color(0.72f, 0.72f, 0.72f, 0.95f); ((TMP_Text)val5).fontStyle = (FontStyles)2; ((Graphic)val5).raycastTarget = false; if ((Object)(object)val2 != (Object)null) { ((TMP_Text)val5).font = val2; } val3.SetActive(false); _byPanel[panel] = val5; } } public static void Show(UI_GamemodeScreen_Panel panel, string text) { if (!((Object)(object)panel == (Object)null) && !string.IsNullOrEmpty(text) && _byPanel.TryGetValue(panel, out var value) && !((Object)(object)value == (Object)null)) { ((TMP_Text)value).text = text; if (!((Component)value).gameObject.activeSelf) { ((Component)value).gameObject.SetActive(true); } } } public static void Hide(UI_GamemodeScreen_Panel panel) { if (!((Object)(object)panel == (Object)null) && _byPanel.TryGetValue(panel, out var value) && !((Object)(object)value == (Object)null) && ((Component)value).gameObject.activeSelf) { ((Component)value).gameObject.SetActive(false); } } public static string GetCreditFor(string modeId) { if (!CustomModeRegistry._modes.TryGetValue(modeId ?? "", out var value)) { return null; } return value.HoverCreditText; } } public class CustomModeCreditHover : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { public UI_GamemodeSetting setting; public static void AttachTo(UI_GamemodeSetting setting) { if (!((Object)(object)setting == (Object)null) && !((Object)(object)((Component)setting).gameObject == (Object)null)) { CustomModeCreditHover component = ((Component)setting).GetComponent<CustomModeCreditHover>(); if ((Object)(object)component != (Object)null) { component.setting = setting; } else { ((Component)setting).gameObject.AddComponent<CustomModeCreditHover>().setting = setting; } } } public void OnPointerEnter(PointerEventData _) { if ((Object)(object)setting == (Object)null) { return; } string creditFor = CustomModeCredit.GetCreditFor(setting.gamemodeSetting?.id); if (!string.IsNullOrEmpty(creditFor)) { UI_GamemodeScreen_Panel panel = GamemodeSettingUnlockBypass.GetPanel(setting); if ((Object)(object)panel != (Object)null) { CustomModeCredit.Show(panel, creditFor); } } } public void OnPointerExit(PointerEventData _) { if (!((Object)(object)setting == (Object)null)) { UI_GamemodeScreen_Panel panel = GamemodeSettingUnlockBypass.GetPanel(setting); if ((Object)(object)panel != (Object)null) { CustomModeCredit.Hide(panel); } } } } [HarmonyPatch(typeof(UI_GamemodeOptionsText), "Refresh")] internal static class CustomModeComboDisplayPatch { [HarmonyPostfix] private static void Postfix(UI_GamemodeOptionsText __instance) { if ((Object)(object)__instance == (Object)null || CustomModeRegistry._combos.Count == 0) { return; } TMP_Text component = ((Component)__instance).GetComponent<TMP_Text>(); if ((Object)(object)component == (Object)null) { return; } M_Gamemode currentGamemode = CL_GameManager.GetCurrentGamemode(); if ((Object)(object)currentGamemode == (Object)null) { return; } List<string> list = new List<string>(); foreach (string key in CustomModeRegistry._modes.Keys) { try { if (currentGamemode.HasActiveSetting(key)) { list.Add(key); } } catch { } } if (list.Count < 2) { return; } list.Sort(StringComparer.Ordinal); for (int i = 0; i < CustomModeRegistry._combos.Count; i++) { var (array, text) = CustomModeRegistry._combos[i]; if (array.Length != list.Count) { continue; } bool flag = true; for (int j = 0; j < array.Length; j++) { if (array[j] != list[j]) { flag = false; break; } } if (flag) { component.text = text; break; } } } } [BepInPlugin("com.cicismods.trinketandbindingframework", "CiCi's Trinket & Binding Framework", "2.1.4")] public class Plugin : BaseUnityPlugin { public const string GUID = "com.cicismods.trinketandbindingframework"; public const string NAME = "CiCi's Trinket & Binding Framework"; public const string VERSION = "2.1.4"; public static ManualLogSource Log; private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Harmony val = new Harmony("com.cicismods.trinketandbindingframework"); Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { try { val.CreateClassProcessor(type).Patch(); } catch (Exception ex) { Log.LogError((object)("[Harmony] patch " + type.FullName + " failed: " + ex.Message)); } } Log.LogInfo((object)"CiCi's Trinket & Binding Framework 2.1.4 loaded"); } } public static class TrinketRegistry { public enum Bucket { Vanilla, Parasite, Chimney } public enum Category { Consumable, Tool, Other, Artifact, Perk } internal class Entry { public string id; public string title; public string description; public string flavorText; public bool isBinding; public int cost; public float scoreMultiplierBonus; public float scoreBonus; public Sprite icon; public Func<List<Item_Object>> itemsToGrantFactory; public Func<List<Perk>> perksToGrantFactory; public int pouchesToGrant; public Trinket runtime; public string idLower; public string runtimeNameLower; public int stackCount = 1; public int maxStacks = 1; public string titleColor; public Bucket bucket; public Category category = Category.Other; public int tier; public bool isFrameworkRegistered; public bool pinToVanilla; public bool isVanillaContent; public string sourceMod; public string sourceModGuid; public bool disablesLeaderboards = true; } internal static readonly Dictionary<string, Entry> _registry = new Dictionary<string, Entry>(); internal static readonly Dictionary<Trinket, Entry> _byRuntime = new Dictionary<Trinket, Entry>(); internal static readonly Dictionary<string, List<string>> _mutexGroups = new Dictionary<string, List<string>>(); internal static Bucket BucketFromColor(string colorHex) { if (string.IsNullOrEmpty(colorHex)) { return Bucket.Vanilla; } string text = colorHex.TrimStart('#').ToUpperInvariant(); if (text == "18420F") { return Bucket.Parasite; } if (text == "8DDDF5") { return Bucket.Chimney; } return Bucket.Vanilla; } internal static bool IsGrey(string colorHex) { if (string.IsNullOrEmpty(colorHex)) { return true; } return colorHex.TrimStart('#').ToUpperInvariant() == "D3D3D3"; } internal static Entry FindEntryForTrinket(Trinket t) { if ((Object)(object)t == (Object)null) { return null; } if (!_byRuntime.TryGetValue(t, out var value)) { return null; } return value; } internal static void RegisterRuntime(Trinket runtime, Entry entry) { if (!((Object)(object)runtime == (Object)null) && entry != null) { _byRuntime[runtime] = entry; entry.runtimeNameLower = ((Object)runtime).name?.ToLowerInvariant() ?? ""; } } public static void RegisterMutexGroup(string groupId, params string[] entryIds) { if (!string.IsNullOrEmpty(groupId) && entryIds != null) { List<string> value = new List<string>(entryIds); _mutexGroups[groupId] = value; } } public static Trinket GetRuntimeTrinket(string id) { if (string.IsNullOrEmpty(id)) { return null; } if (!_registry.TryGetValue(id, out var value)) { return null; } return value.runtime; } public static void RegisterTrinket(string id, string title, string description, string flavorText = "", int cost = 1, float scoreMultiplierBonus = 0f, float scoreBonus = 0f, Sprite icon = null, Func<List<Item_Object>> itemsToGrantFactory = null, Func<List<Perk>> perksToGrantFactory = null, int pouchesToGrant = 0) { Register(id, title, description, flavorText, isBinding: false, cost, scoreMultiplierBonus, scoreBonus, icon, itemsToGrantFactory, perksToGrantFactory, pouchesToGrant); } public static void RegisterBinding(string id, string title, string description, string flavorText = "", int cost = 1, float scoreMultiplierBonus = 0f, float scoreBonus = 0f, Sprite icon = null, Func<List<Item_Object>> itemsToGrantFactory = null, Func<List<Perk>> perksToGrantFactory = null, int pouchesToGrant = 0) { Register(id, title, description, flavorText, isBinding: true, cost, scoreMultiplierBonus, scoreBonus, icon, itemsToGrantFactory, perksToGrantFactory, pouchesToGrant); } private static void Register(string id, string title, string description, string flavorText, bool isBinding, int cost, float scoreMultiplierBonus, float scoreBonus, Sprite icon, Func<List<Item_Object>> itemsToGrantFactory, Func<List<Perk>> perksToGrantFactory, int pouchesToGrant) { if (string.IsNullOrEmpty(id)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[Registry] empty id, skipped"); } return; } _registry[id] = new Entry { id = id, idLower = id.ToLowerInvariant(), title = title, description = description, flavorText = (flavorText ?? ""), isBinding = isBinding, cost = cost, scoreMultiplierBonus = scoreMultiplierBonus, scoreBonus = scoreBonus, icon = icon, itemsToGrantFactory = itemsToGrantFactory, perksToGrantFactory = perksToGrantFactory, pouchesToGrant = pouchesToGrant }; DetectCallingMod(out var name, out var guid); _registry[id].sourceMod = name; _registry[id].sourceModGuid = guid; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[Registry] " + (isBinding ? "binding" : "trinket") + ": " + id + ((name != null) ? (" (from " + name + ")") : ""))); } } internal static void DetectCallingMod(out string name, out string guid) { name = null; guid = null; try { Assembly assembly = typeof(TrinketRegistry).Assembly; StackTrace stackTrace = new StackTrace(0, fNeedFileInfo: false); for (int i = 0; i < stackTrace.FrameCount; i++) { Assembly assembly2 = (stackTrace.GetFrame(i)?.GetMethod())?.DeclaringType?.Assembly; if (assembly2 == null || assembly2 == assembly) { continue; } string name2 = assembly2.GetName().Name; if (string.IsNullOrEmpty(name2) || name2.StartsWith("UnityEngine") || name2.StartsWith("Unity.") || name2.StartsWith("System")) { continue; } switch (name2) { case "mscorlib": case "netstandard": case "Assembly-CSharp": case "Assembly-CSharp-firstpass": continue; } if (!name2.StartsWith("BepInEx") && !(name2 == "0Harmony")) { if (TryGetBepInPluginInfo(assembly2, out var name3, out var guid2)) { name = ((!string.IsNullOrEmpty(name3)) ? name3 : name2); guid = guid2; } else { name = name2; } return; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Registry] DetectCallingMod failed: " + ex.Message)); } } } private static bool TryGetBepInPluginInfo(Assembly a, out string name, out string guid) { name = null; guid = null; try { Type[] types = a.GetTypes(); for (int i = 0; i < types.Length; i++) { object[] customAttributes = types[i].GetCustomAttributes(typeof(BepInPlugin), inherit: false); if (customAttributes != null && customAttributes.Length != 0) { object obj = customAttributes[0]; BepInPlugin val = (BepInPlugin)((obj is BepInPlugin) ? obj : null); if (val != null) { name = val.Name; guid = val.GUID; return true; } } } } catch { } return false; } } internal static class ContortionIconCache { private static Sprite _cached; public static Sprite Get() { if ((Object)(object)_cached != (Object)null) { return _cached; } Trinket[] array = Resources.FindObjectsOfTypeAll<Trinket>(); if (array == null) { return null; } foreach (Trinket val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name == "Trinket_Totem" && (Object)(object)val.icon != (Object)null) { _cached = val.icon; return _cached; } } foreach (Trinket val2 in array) { if ((Object)(object)val2 != (Object)null && val2.title != null && val2.title.IndexOf("Contortion", StringComparison.OrdinalIgnoreCase) >= 0 && (Object)(object)val2.icon != (Object)null) { _cached = val2.icon; return _cached; } } return null; } } [HarmonyPatch(typeof(Trinket), "IsUnlocked")] public static class TrinketUnlockBypassPatch { [HarmonyPostfix] public static void Postfix(ref bool __result) { __result = true; } } [HarmonyPatch(typeof(UI_TrinketPicker), "SelectTrinket")] public static class MutexEnforcePatch { [HarmonyPrefix] public static void Prefix(UI_TrinketPicker __instance, Trinket t) { if ((Object)(object)__instance == (Object)null || __instance.selectedTrinkets == null || (Object)(object)t == (Object)null || TrinketRegistry._mutexGroups.Count == 0) { return; } TrinketRegistry.Entry entry = TrinketRegistry.FindEntryForTrinket(t); if (entry == null) { return; } List<string> list = null; foreach (KeyValuePair<string, List<string>> mutexGroup in TrinketRegistry._mutexGroups) { if (mutexGroup.Value.Contains(entry.id)) { list = mutexGroup.Value; break; } } if (list == null || __instance.selectedTrinkets.Contains(t)) { return; } for (int num = __instance.selectedTrinkets.Count - 1; num >= 0; num--) { TrinketRegistry.Entry entry2 = TrinketRegistry.FindEntryForTrinket(__instance.selectedTrinkets[num]); if (entry2 != null && list.Contains(entry2.id)) { __instance.selectedTrinkets.RemoveAt(num); } } } } [HarmonyPatch(typeof(Trinket), "GetDescription")] public static class TrinketCustomColorPatch { [HarmonyPostfix] public static void Postfix(Trinket __instance, ref string __result) { if (!((Object)(object)__instance == (Object)null)) { TrinketRegistry.Entry entry = TrinketRegistry.FindEntryForTrinket(__instance); if (entry != null && !string.IsNullOrEmpty(entry.titleColor)) { string text = (__instance.isBinding ? "Binding" : "Trinket"); string text2 = (__instance.isBinding ? ("<shake a=0.01>" + __instance.description + "</shake>") : __instance.description); __result = "<color=grey>" + text + ":</color> <color=" + entry.titleColor + "><shimmer s=0.1>" + __instance.title + "</shimmer></color>. " + text2 + "\n<color=grey>" + __instance.flavorText + "</color>"; } } } } [HarmonyPatch(typeof(Trinket), "Activate")] public static class StackableActivateRebuildPatch { [HarmonyPrefix] public static void Prefix(Trinket __instance) { if ((Object)(object)__instance == (Object)null) { return; } TrinketRegistry.Entry entry = TrinketRegistry.FindEntryForTrinket(__instance); if (entry == null || (Object)(object)entry.runtime == (Object)null) { return; } if (entry.itemsToGrantFactory != null) { try { entry.runtime.itemsToGrant = entry.itemsToGrantFactory() ?? new List<Item_Object>(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[ActivateRebuild] " + entry.id + " items: " + ex.Message)); } } } if (entry.perksToGrantFactory == null) { return; } try { entry.runtime.perksToGrant = entry.perksToGrantFactory() ?? new List<Perk>(); } catch (Exception ex2) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[ActivateRebuild] " + entry.id + " perks: " + ex2.Message)); } } } } [HarmonyPatch(typeof(Trinket), "GetLockedDescription")] public static class LockedDescriptionNullGuardPatch { [HarmonyPrefix] public static bool Prefix(Trinket __instance, ref string __result) { if ((Object)(object)__instance == (Object)null) { return true; } if ((Object)(object)__instance.progressionUnlock == (Object)null && !__instance.comingSoon) { __result = __instance.GetDescription() + "\n<color=grey>(Locked by current selection.)</color>"; return false; } return true; } } [HarmonyPatch(typeof(CL_AssetManager), "GetTrinketAsset")] public static class TrinketAssetLookupPatch { [HarmonyPostfix] public static void Postfix(string id, ref Trinket __result) { if ((Object)(object)__result != (Object)null || string.IsNullOrEmpty(id)) { return; } string value = id.ToLowerInvariant(); foreach (KeyValuePair<string, TrinketRegistry.Entry> item in TrinketRegistry._registry) { TrinketRegistry.Entry value2 = item.Value; if (!((Object)(object)value2.runtime == (Object)null) && !string.IsNullOrEmpty(value2.runtimeNameLower) && value2.runtimeNameLower.Contains(value)) { __result = value2.runtime; break; } } } } [HarmonyPatch(typeof(UI_TrinketPicker), "ReloadTrinkets")] public static class TrinketInjectionPatch { private static readonly FieldInfoCache CurrentGamemodeField = new FieldInfoCache(typeof(UI_TrinketPicker), "currentGamemode"); private static List<Trinket> _orderedTrinkets; private static List<Trinket> _orderedBindings; private static int _cachedRegistryCount = -1; [HarmonyPrefix] public static void Prefix(UI_TrinketPicker __instance) { object obj = CurrentGamemodeField.Get(__instance); InjectInto((M_Gamemode)(((obj is M_Gamemode) ? obj : null) ?? CL_GameManager.GetBaseGamemode())); } internal static void InjectInto(M_Gamemode gamemode) { if ((Object)(object)gamemode == (Object)null) { return; } PerkBindingAutoRegistrar.TryRun(); ItemTrinketAutoRegistrar.TryRun(); ArtifactTrinketAutoRegistrar.TryRun(); ConsumableTrinketAutoRegistrar.TryRun(); ClimbingItemTrinketAutoRegistrar.TryRun(); MiscTrinketAutoRegistrar.TryRun(); UnusedVanillaTrinketAutoRegistrar.TryRun(); NoHammerBindingRegistrar.TryRun(); if (TrinketRegistry._registry.Count == 0) { return; } if ((Object)(object)gamemode.availableTrinkets == (Object)null) { TrinketList val = ScriptableObject.CreateInstance<TrinketList>(); ((Object)val).name = "TrinketList_CiCi_Auto_" + (gamemode.gamemodeName ?? "unknown"); val.trinkets = new List<Trinket>(); val.bindings = new List<Trinket>(); Object.DontDestroyOnLoad((Object)(object)val); gamemode.availableTrinkets = val; } if (gamemode.availableTrinkets.trinkets == null) { gamemode.availableTrinkets.trinkets = new List<Trinket>(); } if (gamemode.availableTrinkets.bindings == null) { gamemode.availableTrinkets.bindings = new List<Trinket>(); } gamemode.useGamemodeSettings = true; GamemodeSettingsAugmenter.Apply(gamemode); BuildRegistryRuntimes(gamemode); RebuildMasterListsIfStale(); List<Trinket> trinkets = gamemode.availableTrinkets.trinkets; List<Trinket> bindings = gamemode.availableTrinkets.bindings; trinkets.Clear(); bindings.Clear(); foreach (Trinket orderedTrinket in _orderedTrinkets) { trinkets.Add(orderedTrinket); } foreach (Trinket orderedBinding in _orderedBindings) { bindings.Add(orderedBinding); } foreach (KeyValuePair<string, TrinketRegistry.Entry> item in TrinketRegistry._registry) { TrinketRegistry.Entry value = item.Value; if (!((Object)(object)value.runtime == (Object)null) && value.pinToVanilla) { List<Trinket> list = (value.isBinding ? bindings : trinkets); if (!list.Contains(value.runtime)) { list.Add(value.runtime); } } } List<Trinket> list2 = new List<Trinket>(); List<Trinket> list3 = new List<Trinket>(); foreach (KeyValuePair<string, TrinketRegistry.Entry> item2 in TrinketRegistry._registry) { TrinketRegistry.Entry value2 = item2.Value; if (!((Object)(object)value2.runtime == (Object)null) && !value2.pinToVanilla) { (value2.isBinding ? list3 : list2).Add(value2.runtime); } } list2.Sort(CompareTrinkets); list3.Sort(CompareTrinkets); foreach (Trinket item3 in list2) { if (!trinkets.Contains(item3)) { trinkets.Add(item3); } } foreach (Trinket item4 in list3) { if (!bindings.Contains(item4)) { bindings.Add(item4); } } } internal static int CompareTrinkets(Trinket a, Trinket b) { TrinketRegistry.Entry entry = TrinketRegistry.FindEntryForTrinket(a); TrinketRegistry.Entry entry2 = TrinketRegistry.FindEntryForTrinket(b); bool flag = entry?.isFrameworkRegistered ?? false; bool flag2 = entry2?.isFrameworkRegistered ?? false; if (flag != flag2) { if (!flag) { return -1; } return 1; } int num = (int)(entry?.bucket ?? TrinketRegistry.Bucket.Vanilla); int num2 = (int)(entry2?.bucket ?? TrinketRegistry.Bucket.Vanilla); if (num != num2) { return num - num2; } int num3 = (int)(entry?.category ?? TrinketRegistry.Category.Other); int num4 = (int)(entry2?.category ?? TrinketRegistry.Category.Other); if (num3 != num4) { return num3 - num4; } bool flag3 = TrinketRegistry.IsGrey(entry?.titleColor); bool flag4 = TrinketRegistry.IsGrey(entry2?.titleColor); if (flag3 != flag4) { if (!flag3) { return 1; } return -1; } int num5 = entry?.tier ?? 0; int num6 = entry2?.tier ?? 0; if (num5 != num6) { return num5 - num6; } return string.Compare(a?.title ?? "", b?.title ?? "", StringComparison.OrdinalIgnoreCase); } private static void BuildRegistryRuntimes(M_Gamemode gamemode) { Sprite val = FindBorrowableIcon(gamemode.availableTrinkets?.trinkets); Sprite val2 = FindBorrowableIcon(gamemode.availableTrinkets?.bindings); foreach (KeyValuePair<string, TrinketRegistry.Entry> item in TrinketRegistry._registry) { TrinketRegistry.Entry value = item.Value; if ((Object)(object)value.runtime == (Object)null) { value.runtime = BuildTrinketSO(value); if ((Object)(object)value.runtime != (Object)null) { TrinketRegistry.RegisterRuntime(value.runtime, value); } } if ((Object)(object)value.runtime == (Object)null) { continue; } if ((Object)(object)value.runtime.icon == (Object)null) { Sprite val3 = (value.isBinding ? val2 : val); value.runtime.icon = value.icon ?? val3; value.runtime.lockIcon = value.runtime.icon; } if (value.itemsToGrantFactory != null) { try { value.runtime.itemsToGrant = value.itemsToGrantFactory() ?? new List<Item_Object>(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Registry] " + value.id + " items factory: " + ex.Message)); } } } if (value.perksToGrantFactory == null) { continue; } try { value.runtime.perksToGrant = value.perksToGrantFactory() ?? new List<Perk>(); } catch (Exception ex2) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Registry] " + value.id + " perks factory: " + ex2.Message)); } } } } private static void RebuildMasterListsIfStale() { if (_orderedTrinkets != null && _orderedBindings != null && _cachedRegistryCount == TrinketRegistry._registry.Count) { return; } List<Trinket> list = new List<Trinket>(); List<Trinket> list2 = new List<Trinket>(); HashSet<Trinket> hashSet = new HashSet<Trinket>(); M_Gamemode val = FindOrderingSourceGamemode(); if ((Object)(object)val != (Object)null && (Object)(object)val.availableTrinkets != (Object)null) { if (val.availableTrinkets.trinkets != null) { foreach (Trinket trinket in val.availableTrinkets.trinkets) { if (!((Object)(object)trinket == (Object)null) && hashSet.Add(trinket) && TrinketRegistry.FindEntryForTrinket(trinket) == null) { list.Add(trinket); } } } if (val.availableTrinkets.bindings != null) { foreach (Trinket binding in val.availableTrinkets.bindings) { if (!((Object)(object)binding == (Object)null) && hashSet.Add(binding) && TrinketRegistry.FindEntryForTrinket(binding) == null) { list2.Add(binding); } } } } Trinket[] array = Resources.FindObjectsOfTypeAll<Trinket>(); if (array != null) { foreach (Trinket val2 in array) { if (!((Object)(object)val2 == (Object)null) && hashSet.Add(val2) && TrinketRegistry.FindEntryForTrinket(val2) == null) { if (val2.isBinding) { list2.Add(val2); } else { list.Add(val2); } } } } _orderedTrinkets = list; _orderedBindings = list2; _cachedRegistryCount = TrinketRegistry._registry.Count; } private static M_Gamemode FindOrderingSourceGamemode() { M_Gamemode[] array = Resources.FindObjectsOfTypeAll<M_Gamemode>(); if (array == null) { return null; } foreach (M_Gamemode val in array) { if ((Object)(object)val != (Object)null && (Object)(object)val.availableTrinkets != (Object)null && val.gamemodeName == "Campaign") { return val; } } M_Gamemode result = null; int num = -1; foreach (M_Gamemode val2 in array) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.availableTrinkets == (Object)null)) { int num2 = (val2.availableTrinkets.trinkets?.Count ?? 0) + (val2.availableTrinkets.bindings?.Count ?? 0); if (num2 > num) { num = num2; result = val2; } } } return result; } private static Sprite FindBorrowableIcon(List<Trinket> source) { if (source == null) { return null; } foreach (Trinket item in source) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item.icon == (Object)null) && !item.comingSoon && item.IsUnlocked()) { return item.icon; } } foreach (Trinket item2 in source) { if ((Object)(object)item2 != (Object)null && (Object)(object)item2.icon != (Object)null) { return item2.icon; } } return null; } private static Trinket BuildTrinketSO(TrinketRegistry.Entry e) { Trinket obj = ScriptableObject.CreateInstance<Trinket>(); ((Object)obj).name = "Trinket_" + e.id; obj.title = e.title; obj.description = e.description; obj.flavorText = e.flavorText; obj.isBinding = e.isBinding; obj.cost = e.cost; obj.scoreMultiplierBonus = e.scoreMultiplierBonus; obj.scoreBonus = e.scoreBonus; obj.comingSoon = false; obj.settingBlacklist = new List<string>(); obj.itemsToGrant = new List<Item_Object>(); obj.perksToGrant = new List<Perk>(); obj.pouchesToGrant = e.pouchesToGrant; obj.progressionUnlock = null; obj.icon = e.icon; obj.lockIcon = e.icon; Object.DontDestroyOnLoad((Object)(object)obj); return obj; } } internal static class GamemodeSettingsAugmenter { private static GamemodeSetting _hardmode; private static GamemodeSetting _ironknuckle; private static GamemodeSetting _unlimited; private static void EnsureLookup() { if ((Object)(object)_hardmode != (Object)null && (Object)(object)_ironknuckle != (Object)null && (Object)(object)_unlimited != (Object)null) { return; } GamemodeSetting[] array = Resources.FindObjectsOfTypeAll<GamemodeSetting>(); if (array == null) { return; } foreach (GamemodeSetting val in array) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.id)) { if ((Object)(object)_hardmode == (Object)null && val.id == "hardmode") { _hardmode = val; } else if ((Object)(object)_ironknuckle == (Object)null && val.id == "ironknuckle") { _ironknuckle = val; } else if ((Object)(object)_unlimited == (Object)null && val.id == "unlimited") { _unlimited = val; } } } } private static bool NameContains(M_Gamemode gm, string needle) { string text = gm?.gamemodeName; if (!string.IsNullOrEmpty(text)) { return text.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } public static bool IsAugmentedMode(M_Gamemode gm) { if ((Object)(object)gm != (Object)null) { if (!NameContains(gm, "Parasite")) { return NameContains(gm, "Chimney"); } return true; } return false; } public static void Apply(M_Gamemode gm) { if (!((Object)(object)gm == (Object)null)) { EnsureLookup(); if (gm.gamemodeSettings == null) { gm.gamemodeSettings = new List<GamemodeSetting>(); } if (NameContains(gm, "Parasite")) { gm.allowHardmode = true; gm.allowIronKnuckle = true; AddIfMissing(gm, _hardmode); AddIfMissing(gm, _ironknuckle); } else if (NameContains(gm, "Chimney")) { AddIfMissing(gm, _unlimited); } CustomModePickerIntegration.InjectInto(gm); } } private static void AddIfMissing(M_Gamemode gm, GamemodeSetting setting) { if (!((Object)(object)setting == (Object)null) && !gm.gamemodeSettings.Contains(setting)) { gm.gamemodeSettings.Add(setting); } } } [HarmonyPatch(typeof(UI_GamemodeScreen), "Initialize")] public static class GamemodeScreenInitInjectPatch { [HarmonyPrefix] public static void Prefix(M_Gamemode mode) { if (!((Object)(object)mode == (Object)null)) { TrinketInjectionPatch.InjectInto(mode); } } [HarmonyPostfix] public static void Postfix(UI_GamemodeScreen __instance) { if (__instance?.activePanels == null) { return; } foreach (KeyValuePair<string, UI_GamemodeScreen_Panel> activePanel in __instance.activePanels) { UI_GamemodeScreen_Panel value = activePanel.Value; if ((Object)(object)value == (Object)null) { continue; } UI_TrinketPicker[] componentsInChildren = ((Component)value).GetComponentsInChildren<UI_TrinketPicker>(true); foreach (UI_TrinketPicker val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } if ((Object)(object)val.parentPanel == (Object)null) { val.parentPanel = value; } try { val.Initialize(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("picker init failed on " + ((Object)value).name + ": " + ex.Message)); } } } } } } internal static class GamemodeSettingUnlockBypass { private static readonly FieldInfoCache PanelField = new FieldInfoCache(typeof(UI_GamemodeSetting), "gamemodePanel"); public static UI_GamemodeScreen_Panel GetPanel(UI_GamemodeSetting inst) { object obj = PanelField.Get(inst); return (UI_GamemodeScreen_Panel)((obj is UI_GamemodeScreen_Panel) ? obj : null); } public static void ForceUnlocked(UI_GamemodeSetting inst) { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inst == (Object)null || (Object)(object)inst.gamemodeSetting == (Object)null || (Object)(object)inst.toggle == (Object)null) { return; } object obj = PanelField.Get(inst); object obj2 = ((obj is UI_GamemodeScreen_Panel) ? obj : null); M_Gamemode val = ((obj2 != null) ? ((UI_GamemodeScreen_Panel)obj2).GetGamemode() : null); GamemodeSetting gamemodeSetting = inst.gamemodeSetting; if (!GamemodeSettingsAugmenter.IsAugmentedMode(val) && (Object)(object)val != (Object)null && gamemodeSetting.exclusiveSettings != null) { foreach (string exclusiveSetting in gamemodeSetting.exclusiveSettings) { if (val.HasActiveSetting(exclusiveSetting) && !val.HasActiveSetting(gamemodeSetting.id)) { return; } } } if ((Object)(object)inst.lockObject != (Object)null) { inst.lockObject.SetActive(false); } ((Selectable)inst.toggle).interactable = true; if ((Object)(object)inst.descriptionText != (Object)null) { inst.descriptionText.text = gamemodeSetting.description; } Color val2 = gamemodeSetting.color; if (!inst.toggle.isOn) { val2 *= Color.grey; } if ((Object)(object)inst.outline != (Object)null) { ((Graphic)inst.outline).color = val2; } if ((Object)(object)((Selectable)inst.toggle).targetGraphic != (Object)null) { ((Selectable)inst.toggle).targetGraphic.color = val2; } if ((Object)(object)inst.toggle.graphic != (Object)null) { inst.toggle.graphic.color = val2; } if ((Object)(object)inst.titleText != (Object)null) { ((Graphic)inst.titleText).color = val2; } if ((Object)(object)inst.descriptionText != (Object)null) { ((Graphic)inst.descriptionText).color = val2; } if ((Object)(object)inst.unlockHint != (Object)null) { ((Graphic)inst.unlockHint).color = val2; } } } [HarmonyPatch(typeof(UI_GamemodeSetting), "Initialize")] public static class GamemodeSettingInitUnlockBypassPatch { [HarmonyPostfix] public static void Postfix(UI_GamemodeSetting __instance) { GamemodeSettingUnlockBypass.ForceUnlocked(__instance); CustomModeCreditHover.AttachTo(__instance); } } [HarmonyPatch(typeof(UI_GamemodeSetting), "UpdateColor")] public static class GamemodeSettingUpdateColorUnlockBypassPatch { [HarmonyPostfix] public static void Postfix(UI_GamemodeSetting __instance) { GamemodeSettingUnlockBypass.ForceUnlocked(__instance); } } internal sealed class FieldInfoCache { private readonly FieldInfo _field; public FieldInfoCache(Type type, string name) { _field = AccessTools.Field(type, name); } public object Get(object instance) { return _field?.GetValue(instance); } } internal static class PickerReflection { public static readonly FieldInfoCache DescriptionTextField = new FieldInfoCache(typeof(UI_TrinketPicker), "descriptionText"); public static readonly FieldInfoCache ParentPickerField = new FieldInfoCache(typeof(UI_TrinketPicker_Icon), "parentPicker"); public static bool HasDescriptionText(UI_TrinketPicker picker) { if ((Object)(object)picker == (Object)null) { return false; } object obj = DescriptionTextField.Get(picker); Object val = (Object)((obj is Object) ? obj : null); if (val != null) { return val != (Object)null; } return false; } public static UI_TrinketPicker GetParentPicker(UI_TrinketPicker_Icon icon) { if (!((Object)(object)icon == (Object)null)) { object obj = ParentPickerField.Get(icon); return (UI_TrinketPicker)((obj is UI_TrinketPicker) ? obj : null); } return null; } } [HarmonyPatch(typeof(UI_TrinketPicker), "HideDescription")] public static class HideDescriptionNullGuardPatch { [HarmonyPrefix] public static bool Prefix(UI_TrinketPicker __instance) { return PickerReflection.HasDescriptionText(__instance); } } [HarmonyPatch(typeof(UI_TrinketPicker), "ShowDescription")] public static class ShowDescriptionNullGuardPatch { [HarmonyPrefix] public static bool Prefix(UI_TrinketPicker __instance) { return PickerReflection.HasDescriptionText(__instance); } } [HarmonyPatch(typeof(UI_TrinketPicker), "ShowTrinketDescription")] public static class ShowTrinketDescriptionNullGuardPatch { [HarmonyPrefix] public static bool Prefix(UI_TrinketPicker __instance, Trinket t) { if ((Object)(object)t != (Object)null) { return PickerReflection.HasDescriptionText(__instance); } return false; } } [HarmonyPatch(typeof(UI_TrinketPicker_Icon), "OnPointerEnter")] public static class IconPointerEnterNullGuardPatch { [HarmonyPrefix] public static bool Prefix(UI_TrinketPicker_Icon __instance) { if ((Object)(object)PickerReflection.GetParentPicker(__instance) != (Object)null) { return (Object)(object)__instance.trinket != (Object)null; } return false; } } [HarmonyPatch(typeof(UI_TrinketPicker_Icon), "OnPointerExit")] public static class IconPointerExitNullGuardPatch { [HarmonyPrefix] public static bool Prefix(UI_TrinketPicker_Icon __instance) { return (Object)(object)PickerReflection.GetParentPicker(__instance) != (Object)null; } } [HarmonyPatch(typeof(UI_TrinketPicker_Icon), "OnSelect")] public static class IconSelectNullGuardPatch { [HarmonyPrefix] public static bool Prefix(UI_TrinketPicker_Icon __instance) { if ((Object)(object)PickerReflection.GetParentPicker(__instance) != (Object)null) { return (Object)(object)__instance.trinket != (Object)null; } return false; } } [HarmonyPatch(typeof(UI_TrinketPicker_Icon), "OnDeselect")] public static class IconDeselectNullGuardPatch { [HarmonyPrefix] public static bool Prefix(UI_TrinketPicker_Icon __instance) { return (Object)(object)PickerReflection.GetParentPicker(__instance) != (Object)null; } } [HarmonyPatch(typeof(UI_TrinketPicker_Icon), "OnClick")] public static class IconClickNullGuardPatch { [HarmonyPrefix] public static bool Prefix(UI_TrinketPicker_Icon __instance) { if ((Object)(object)PickerReflection.GetParentPicker(__instance) != (Object)null) { return (Object)(object)__instance.trinket != (Object)null; } return false; } } public class PerkBindingClickOverride : MonoBehaviour, IPointerDownHandler, IEventSystemHandler { public string bindingId; public TextMeshProUGUI stackText; private int _lastProcessedFrame = -1; private static readonly MethodInfo _updateTrinketActivation = AccessTools.Method(typeof(UI_TrinketPicker), "UpdateTrinketActivation", (Type[])null, (Type[])null); public void OnPointerDown(PointerEventData eventData) { int frameCount = Time.frameCount; if (frameCount == _lastProcessedFrame) { return; } _lastProcessedFrame = frameCount; bool mouseButtonDown = Input.GetMouseButtonDown(0); bool mouseButtonDown2 = Input.GetMouseButtonDown(1); bool flag = mouseButtonDown2 && !mouseButtonDown; bool flag2 = mouseButtonDown && !mouseButtonDown2; if ((!flag && !flag2) || !TrinketRegistry._registry.TryGetValue(bindingId, out var value)) { return; } UI_TrinketPicker_Icon component = ((Component)this).GetComponent<UI_TrinketPicker_Icon>(); if ((Object)(object)component == (Object)null || (Object)(object)component.trinket == (Object)null) { return; } UI_TrinketPicker parentPicker = PickerReflection.GetParentPicker(component); if ((Object)(object)parentPicker == (Object)null) { return; } bool flag3 = parentPicker.selectedTrinkets != null && parentPicker.selectedTrinkets.Contains(component.trinket); bool flag4 = false; if (flag2) { if (!flag3) { value.stackCount = 1; parentPicker.SelectTrinket(component.trinket); } else if (value.stackCount < value.maxStacks) { value.stackCount++; flag4 = true; } } else if (flag && flag3) { if (value.stackCount > 1) { value.stackCount--; flag4 = true; } else { value.stackCount = 1; parentPicker.SelectTrinket(component.trinket); } } if (flag4) { try { _updateTrinketActivation?.Invoke(parentPicker, null); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Stack] activation refresh failed: " + ex.Message)); } } } if ((Object)(object)value.runtime != (Object)null) { if (value.perksToGrantFactory != null) { try { value.runtime.perksToGrant = value.perksToGrantFactory(); } catch (Exception ex2) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[Stack] perksToGrant rebuild failed for " + value.id + ": " + ex2.Message)); } } } if (value.itemsToGrantFactory != null) { try { value.runtime.itemsToGrant = value.itemsToGrantFactory(); } catch (Exception ex3) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[Stack] itemsToGrant rebuild failed for " + value.id + ": " + ex3.Message)); } } } } UpdateStackVisual(value); } private void UpdateStackVisual(TrinketRegistry.Entry entry) { if (!((Object)(object)stackText == (Object)null)) { ((TMP_Text)stackText).text = ((entry.stackCount > 1) ? $"x{entry.stackCount}" : ""); } } } [HarmonyPatch(typeof(UI_TrinketPicker_Icon), "SetTrinket")] public static class PerkBindingIconAttachPatch { [HarmonyPostfix] public static void Postfix(UI_TrinketPicker_Icon __instance, Trinket t) { if ((Object)(object)__instance == (Object)null || (Object)(object)t == (Object)null || string.IsNullOrEmpty(((Object)t).name)) { return; } TrinketRegistry.Entry entry = TrinketRegistry.FindEntryForTrinket(t); if (entry != null && entry.maxStacks > 1) { Button component = ((Component)__instance).GetComponent<Button>(); if ((Object)(object)component != (Object)null) { ((UnityEventBase)component.onClick).RemoveAllListeners(); } PerkBindingClickOverride perkBindingClickOverride = ((Component)__instance).GetComponent<PerkBindingClickOverride>() ?? ((Component)__instance).gameObject.AddComponent<PerkBindingClickOverride>(); perkBindingClickOverride.bindingId = entry.id; if (entry.maxStacks > 1) { perkBindingClickOverride.stackText = EnsureStackText(((Component)__instance).transform); ((TMP_Text)perkBindingClickOverride.stackText).text = ((entry.stackCount > 1) ? $"x{entry.stackCount}" : ""); } } } private static TextMeshProUGUI EnsureStackText(Transform iconRoot) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) Transform val = iconRoot.Find("CiCi_StackCount"); if ((Object)(object)val != (Object)null) { TextMeshProUGUI component = ((Component)val).GetComponent<TextMeshProUGUI>(); if ((Object)(object)component != (Object)null) { return component; } } GameObject val2 = new GameObject("CiCi_StackCount", new Type[1] { typeof(RectTransform) }); RectTransform val3 = (RectTransform)val2.transform; ((Transform)val3).SetParent(iconRoot, false); val3.anchorMin = new Vector2(1f, 1f); val3.anchorMax = new Vector2(1f, 1f); val3.pivot = new Vector2(1f, 1f); val3.anchoredPosition = new Vector2(-2f, -2f); val3.sizeDelta = new Vector2(40f, 20f); TextMeshProUGUI obj = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).alignment = (TextAlignmentOptions)260; ((TMP_Text)obj).fontSize = 16f; ((Graphic)obj).color = Color.white; ((Graphic)obj).raycastTarget = false; ((TMP_Text)obj).text = ""; return obj; } } [HarmonyPatch(typeof(UI_TrinketPicker), "UpdatePips")] public static class PipsStackInflatePatch { [HarmonyPrefix] public static void Prefix(UI_TrinketPicker __instance, int totalBudget, ref int usedBudget) { if ((Object)(object)__instance == (Object)null || __instance.selectedTrinkets == null) { return; } int num = 0; foreach (Trinket selectedTrinket in __instance.selectedTrinkets) { if (!((Object)(object)selectedTrinket == (Object)null) && !selectedTrinket.isBinding) { TrinketRegistry.Entry entry = TrinketRegistry.FindEntryForTrinket(selectedTrinket); num += ((entry == null) ? 1 : Mathf.Max(1, entry.stackCount)); } } usedBudget = num; } } [HarmonyPatch(typeof(UI_TrinketPicker), "UpdatePips")] public static class PipsOverflowPatch { private const int VisibleCap = 5; private const string OverflowName = "CiCi_PipOverflow"; private static readonly FieldInfo PipsField = AccessTools.Field(typeof(UI_TrinketPicker), "pips"); [HarmonyPostfix] public static void Postfix(UI_TrinketPicker __instance, int totalBudget, int usedBudget) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.pipHolder == (Object)null || !(PipsField?.GetValue(__instance) is List<Image> list)) { return; } for (int i = 0; i < list.Count; i++) { if (!((Object)(object)list[i] == (Object)null)) { bool flag = i < 5; if (((Component)list[i]).gameObject.activeSelf != flag) { ((Component)list[i]).gameObject.SetActive(flag); } } } int num = Mathf.Max(totalBudget, usedBudget) - 5; TextMeshProUGUI val = EnsureOverflowText(__instance.pipHolder); if ((Object)(object)val == (Object)null) { return; } Transform parent = ((TMP_Text)val).transform.parent; if ((Object)(object)parent != (Object)null) { parent.SetAsLastSibling(); } if (num > 0) { ((TMP_Text)val).text = $"[+{num}]"; ((Graphic)val).color = ((usedBudget > totalBudget) ? Color.red : Color.white); if ((Object)(object)parent != (Object)null && !((Component)parent).gameObject.activeSelf) { ((Component)parent).gameObject.SetActive(true); } if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } RectTransform rectTransform = ((TMP_Text)val).rectTransform; if ((Object)(object)rectTransform != (Object)null) { rectTransform.anchoredPosition = new Vector2(8f, -5f); } } else if ((Object)(object)parent != (Object)null && ((Component)parent).gameObject.activeSelf) { ((Component)parent).gameObject.SetActive(false); } } private static TextMeshProUGUI EnsureOverflowText(Transform pipHolder) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0056: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) Transform obj = pipHolder.Find("CiCi_PipOverflow"); RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); TextMeshProUGUI componentInChildren; if ((Object)(object)val != (Object)null) { componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null) { return componentInChildren; } } else { GameObject val2 = new GameObject("CiCi_PipOverflow", new Type[1] { typeof(RectTransform) }); val = (RectTransform)val2.transform; ((Transform)val).SetParent(pipHolder, false); val.sizeDelta = new Vector2(50f, 22f); LayoutElement obj2 = val2.AddComponent<LayoutElement>(); obj2.preferredWidth = 50f; obj2.preferredHeight = 22f; obj2.flexibleWidth = 0f; obj2.flexibleHeight = 0f; } GameObject val3 = new GameObject("Text", new Type[1] { typeof(RectTransform) }); RectTransform val4 = (RectTransform)val3.transform; ((Transform)val4).SetParent((Transform)(object)val, false); val4.anchorMin = Vector2.zero; val4.anchorMax = Vector2.one; val4.pivot = new Vector2(0.5f, 0.5f); val4.anchoredPosition = Vector2.zero; val4.sizeDelta = Vector2.zero; componentInChildren = val3.AddComponent<TextMeshProUGUI>(); ((TMP_Text)componentInChildren).fontSize = 18f; ((TMP_Text)componentInChildren).alignment = (TextAlignmentOptions)4097; ((Graphic)componentInChildren).color = Color.white; ((TMP_Text)componentInChildren).fontStyle = (FontStyles)1; ((Graphic)componentInChildren).raycastTarget = false; ((TMP_Text)componentInChildren).text = ""; UI_TrinketPicker componentInParent = ((Component)pipHolder).GetComponentInParent<UI_TrinketPicker>(); TMP_Text val5 = (((Object)(object)componentInParent != (Object)null) ? componentInParent.costText : null); if ((Object)(object)val5 != (Object)null && (Object)(object)val5.font != (Object)null) { ((TMP_Text)componentInChildren).font = val5.font; } return componentInChildren; } } public static class ItemTrinketAutoRegistrar { private struct ItemDef { public string title; public string prefabName; public string color; public string description; public string flavor; } private static bool _done; private const string LightGrey = "#D3D3D3"; private const string MutexGroup = "tools"; private static readonly ItemDef[] _tools = new ItemDef[5] { new ItemDef { title = "Cryo-Gun", prefabName = "Item_Cryogun", color = "#8DDDF5", description = "Start with a cryo-gun.", flavor = "" }, new ItemDef { title = "Flare Gun", prefabName = "Item_Flaregun", color = "#D3D3D3", description = "Start with a flare gun.", flavor = "" }, new ItemDef { title = "Flashlight", prefabName = "Item_Flashlight", color = "#D3D3D3", description = "Start with a flashlight.", flavor = "" }, new ItemDef { title = "Wrench", prefabName = "Item_Hammer_Cosmetic_Wrench", color = "#18420F", description = "Start with a wrench.", flavor = "" }, new ItemDef { title = "Scanner", prefabName = "Item_EntityScanner", color = "#18420F", description = "Start with an entity scanner.", flavor = "" } }; internal static void TryRun() { if (_done) { return; } List<(ItemDef, Item_Object)> list = new List<(ItemDef, Item_Object)>(); ItemDef[] tools = _tools; for (int i = 0; i < tools.Length; i++) { ItemDef item = tools[i]; Item_Object val = null; try { GameObject assetGameObject = CL_AssetManager.GetAssetGameObject(item.prefabName, ""); val = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null); } catch { } if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[AutoTools] '" + item.prefabName + "' not yet loaded — deferring")); } return; } list.Add((item, val)); } Sprite val2 = ContortionIconCache.Get(); List<string> list2 = new List<string>(); foreach (var item4 in list) { ItemDef item2 = item4.Item1; Item_Object item3 = item4.Item2; string text = "cici_tool_" + item2.prefabName; if (TrinketRegistry._registry.ContainsKey(text)) { list2.Add(text); continue; } Sprite icon = val2 ?? item3.itemData?.normalSprite; Item_Object ioRef = item3; TrinketRegistry.RegisterTrinket(text, item2.title, item2.description, item2.flavor, 1, 0f, 0f, icon, () => new List<Item_Object> { ioRef }); if (TrinketRegistry._registry.TryGetValue(text, out var value)) { value.titleColor = item2.color; value.category = TrinketRegistry.Category.Tool; value.bucket = TrinketRegistry.BucketFromColor(item2.color); value.isFrameworkRegistered = true; value.isVanillaContent = true; } list2.Add(text); } TrinketRegistry.RegisterMutexGroup("tools", list2.ToArray()); _done = true; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)string.Format("[AutoTools] Registered {0} tool trinkets in mutex group '{1}'", list2.Count, "tools")); } } } public static class NoHammerBindingRegistrar { private static bool _done; public const string BindingId = "cici_nohammer"; private static Sprite _icon; private static bool _cachedActive; private static bool _cacheValid; public static bool Active { get { if (!_cacheValid) { Recompute(); } return _cachedActive; } } public static void Invalidate() { _cacheValid = false; } private static void Recompute() { _cachedActive = ComputeActiveNow(); _cacheValid = true; } private static bool ComputeActiveNow() { try { M_Gamemode currentGamemode = CL_GameManager.GetCurrentGamemode(); if ((Object)(object)currentGamemode == (Object)null) { return false; } SaveData saveData = StatManager.saveData; List<string> list = ((saveData != null) ? saveData.GetGamemodeTrinkets(currentGamemode.GetGamemodeName(true)) : null); if (list == null) { return false; } foreach (string item in list) { if (!string.IsNullOrEmpty(item) && item.ToLowerInvariant().Contains("cici_nohammer")) { return true; } } } catch { } return false; } internal static void TryRun() { if (_done) { return; } if (TrinketRegistry._registry.ContainsKey("cici_nohammer")) { _done = true; return; } if ((Object)(object)_icon == (Object)null) { _icon = TryLoadIcon("No_Hammer_Icon.png"); } TrinketRegistry.RegisterBinding("cici_nohammer", "No Hammer", "Start the run without a hammer.", "", 1, 0f, 0f, _icon ?? ContortionIconCache.Get(), () => new List<Item_Object>()); if (TrinketRegistry._registry.TryGetValue("cici_nohammer", out var value)) { value.titleColor = "#D3D3D3"; value.category = TrinketRegistry.Category.Perk; value.bucket = TrinketRegistry.Bucket.Vanilla; value.isFrameworkRegistered = true; } _done = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[NoHammer] Registered binding"); } } private static Sprite TryLoadIcon(string filename) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) try { string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), filename); if (!File.Exists(path)) { return null; } byte[] array = File.ReadAllBytes(path); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false) { filterMode = (FilterMode)0 }; if (!ImageConversion.LoadImage(val, array)) { return null; } ((Texture)val).wrapMode = (TextureWrapMode)1; ((Object)val).name = filename; return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[NoHammer] icon load failed: " + ex.Message)); } return null; } } } [HarmonyPatch(typeof(Item_Object), "Start")] public static class NoHammerBanItemSpawnPatch { [HarmonyPostfix] public static void Postfix(Item_Object __instance) { if (NoHammerBindingRegistrar.Active && __instance?.itemData != null && __instance.itemData.prefabName == "Item_Hammer") { ((Component)__instance).gameObject.SetActive(false); } } } [HarmonyPatch(typeof(M_Gamemode), "StartFreshGamemode")] public static class NoHammerCacheStartInvalidatePatch { [HarmonyPostfix] public static void Postfix() { NoHammerBindingRegistrar.Invalidate(); } } [HarmonyPatch(typeof(UI_TrinketPicker), "SelectTrinket")] public static class NoHammerCacheSelectInvalidatePatch { [HarmonyPostfix] public static void Postfix() { NoHammerBindingRegistrar.Invalidate(); } } [HarmonyPatch(typeof(SaveData), "GetGamemodeTrinkets")] public static class GetGamemodeTrinketsLogSilencePatch { [HarmonyPrefix] public static bool Prefix(SaveData __instance, string gameModeName, ref List<string> __result) { GameModeData gameMode = __instance.GetGameMode(gameModeName); __result = ((gameMode != null && gameMode.activeTrinkets != null) ? gameMode.activeTrinkets : new List<string>()); return false; } } public static class ConsumableTrinketAutoRegistrar { private struct ConsumableDef { public string title; public string prefabName; public string color; public string description; } private static bool _done; private const string LightGrey = "#D3D3D3"; private const int MaxStacks = 12; private static readonly ConsumableDef[] _items = new ConsumableDef[13] { new ConsumableDef { title = "Blink Eye", prefabName = "Item_BlinkEye", color = "#ED4040", description = "Start with Blink Eye(s)." }, new ConsumableDef { title = "Canned Food", prefabName = "Item_Beans", color = "#D3D3D3", description = "Start with canned food." }, new ConsumableDef { title = "Delta-0052", prefabName = "Item_Beans_Periphery", color = "#8EF6DD", description = "Start with Delta-0052." }, new ConsumableDef { title = "Food Bar", prefabName = "Item_Food_Bar", color = "#D3D3D3", description = "Start with food bars." }, new ConsumableDef { title = "Grub", prefabName = "Denizen_SlugGrub", color = "#D3D3D3", description = "Start with grubs." }, new ConsumableDef { title = "Injector", prefabName = "Item_Injector", color = "#D3D3D3", description = "Start with injectors." }, new ConsumableDef { title = "Inoculator", prefabName = "Item_Inoculator", color = "#18420F", description = "Start with inoculators." }, new ConsumableDef { title = "Lemon Roach", prefabName = "Denizen_Roach_Lemon", color = "#FDED56", description = "Start with lemon roaches." }, new ConsumableDef { title = "Milk", prefabName = "Item_Milk", color = "#8DDDF5", description = "Start with milk cartons." }, new ConsumableDef { title = "Pills", prefabName = "Item_Pillbottle", color = "#D3D3D3", description = "Start with pill bottles." }, new ConsumableDef { title = "Hot Cocoa", prefabName = "Item_Cocoa_Full", color = "#8DDDF5", description = "Start with hot cocoa." }, new ConsumableDef { title = "Cookie", prefabName = "Item_Food_Cookie", color = "#8DDDF5", description = "Start with cookies." }, new ConsumableDef { title = "Candy Cauldron", prefabName = "Item_CandyCauldron", color = "#FFD454", description = "Start with candy cauldrons." } }; internal static void TryRun() { if (_done) { return; } Sprite val = ContortionIconCache.Get(); bool flag = false; bool flag2 = true; ConsumableDef[] items = _items; for (int i = 0; i < items.Length; i++) { ConsumableDef consumableDef = items[i]; string text = "cici_consumable_" + consumableDef.prefabName; if (TrinketRegistry._registry.ContainsKey(text)) { flag = true; continue; } Item_Object val2 = null; try { GameObject assetGameObject = CL_AssetManager.GetAssetGameObject(consumableDef.prefabName, ""); val2 = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null); } catch { } if ((Object)(object)val2 == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[AutoConsumables] '" + consumableDef.prefabName + "' not yet loaded — skipping")); } flag2 = false; continue; } flag = true; Sprite icon = val ?? val2.itemData?.normalSprite; Item_Object ioRef = val2; string idCopy = text; TrinketRegistry.RegisterTrinket(text, consumableDef.title, consumableDef.description, "", 1, 0f, 0f, icon, delegate { TrinketRegistry.Entry value2; int num = ((!TrinketRegistry._registry.TryGetValue(idCopy, out value2)) ? 1 : Mathf.Max(1, value2.stackCount)); List<Item_Object> list = new List<Item_Object>(num); for (int j = 0; j < num; j++) { list.Add(ioRef); } return list; }); if (TrinketRegistry._registry.TryGetValue(text, out var value)) { value.titleColor = consumableDef.color; value.maxStacks = 12; value.stackCount = 1; value.category = TrinketRegistry.Category.Consumable; value.bucket = TrinketRegistry.BucketFromColor(consumableDef.color); value.isFrameworkRegistered = true; value.isVanillaContent = true; } } if (flag2) { _done = true; } if (flag) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[AutoConsumables] Pass complete — allResolved={flag2}"); } } } } public static class ClimbingItemTrinketAutoRegistrar { private struct ClimbingItemDef { public string title; public string prefabName; public string color; public string description; } private static bool _done; private const string LightGrey = "#D3D3D3"; private const int MaxStacks = 12; private static readonly ClimbingItemDef[] _items = new ClimbingItemDef[10] { new ClimbingItemDef { title = "Rope Rebar", prefabName = "Item_RebarRope", color = "#D3D3D3", description = "Start with rope rebar." }, new ClimbingItemDef { title = "Explosive Rebar", prefabName = "Item_Rebar_Explosive", color = "#D3D3D3", description = "Start with explosive rebar." }, new ClimbingItemDef { title = "Rope", prefabName = "Item_Rope", color = "#D3D3D3", description = "Start with rope." }, new ClimbingItemDef { title = "Auto Piton", prefabName = "Item_AutoPiton", color = "#D3D3D3", description = "Start with auto pitons." }, new ClimbingItemDef { title = "Brick", prefabName = "Item_Rubble", color = "#D3D3D3", description = "Start with bricks." }, new ClimbingItemDef { title = "Piton", prefabName = "Item_Piton", color = "#D3D3D3", description = "Start with pitons." }, new ClimbingItemDef { title = "Rebar", prefabName = "Item_Rebar", color = "#D3D3D3", description = "Start with rebar." }, new ClimbingItemDef { title = "Holiday Piton", prefabName = "Item_Piton_Holiday", color = "#8DDDF5", description = "Start with holiday pitons." }, new ClimbingItemDef { title = "Holiday Rebar", prefabName = "Item_Rebar_Holiday", color = "#8DDDF5", description = "Start with holiday rebar." }, new ClimbingItemDef { title = "Holiday Rope Rebar", prefabName = "Item_RebarRope_Holiday", color = "#8DDDF5", description = "Start with holiday rope rebar." } }; internal static void TryRun() { if (_done) { return; } Sprite val = ContortionIconCache.Get(); bool flag = false; bool flag2 = true; ClimbingItemDef[] items = _items; for (int i = 0; i < items.Length; i++) { ClimbingItemDef climbingItemDef = items[i]; string text = "cici_climb_" + climbingItemDef.prefabName; if (TrinketRegistry._registry.ContainsKey(text)) { flag = true; continue; } Item_Object val2 = null; try { GameObject assetGameObject = CL_AssetManager.GetAssetGameObject(climbingItemDef.prefabName, ""); val2 = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null); } catch { } if ((Object)(object)val2 == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[AutoClimb] '" + climbingItemDef.prefabName + "' not yet loaded — skipping")); } flag2 = false; continue; } flag = true; Sprite icon = val ?? val2.itemData?.normalSprite; Item_Object ioRef = val2; string idCopy = text; TrinketRegistry.RegisterTrinket(text, climbingItemDef.title, climbingItemDef.description, "", 1, 0f, 0f, icon, delegate { TrinketRegistry.Entry value2; int num = ((!TrinketRegistry._registry.TryGetValue(idCopy, out value2)) ? 1 : Mathf.Max(1, value2.stackCount)); List<Item_Object> list = new List<Item_Object>(num); for (int j = 0; j < num; j++) { list.Add(ioRef); } return list; }); if (TrinketRegistry._registry.TryGetValue(text, out var value)) { value.titleColor = climbingItemDef.color; value.maxStacks = 12; value.stackCount = 1; value.category = TrinketRegistry.Category.Other; value.bucket = TrinketRegistry.BucketFromColor(climbingItemDef.color); value.isFrameworkRegistered = true; value.isVanillaContent = true; } } if (flag2) { _done = true; } if (flag) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[AutoClimb] Pass complete — allResolved={flag2}"); } } } } public static class UnusedVanillaTrinketAutoRegistrar { private struct UnusedDef { public string title; public string prefabName; public string description; } private static bool _done; private static readonly UnusedDef[] _items = new UnusedDef[1] { new UnusedDef { title = "Calming Buddy", prefabName = "Item_Trinket_CalmingBuddy", description = "Start with the Calming Buddy trinket." } }; internal static void TryRun() { if (_done) { return; } bool flag = false; bool flag2 = true; UnusedDef[] items = _items; for (int i = 0; i < items.Length; i++) { UnusedDef unusedDef = items[i]; string text = "cici_unused_" + unusedDef.prefabName; if (TrinketRegistry._registry.ContainsKey(text)) { flag = true; continue; } Item_Object val = null; try { GameObject assetGameObject = CL_AssetManager.GetAssetGameObject(unusedDef.prefabName, ""); val = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null); } catch { } if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[AutoUnused] '" + unusedDef.prefabName + "' not yet loaded — skipping")); } flag2 = false; continue; } flag = true; Sprite icon = val.itemData?.normalSprite; Item_Object ioRef = val; TrinketRegistry.RegisterTrinket(text, unusedDef.title, unusedDef.description, "", 1, 0f, 0f, icon, () => new List<Item_Object> { ioRef }); if (TrinketRegistry._registry.TryGetValue(text, out var value)) { value.pinToVanilla = true; value.isFrameworkRegistered = true; value.isVanillaContent = true; } } if (flag2) { _done = true; } if (flag) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[AutoUnused] Pass complete — allResolved={flag2}"); } } } } public static class MiscTrinketAutoRegistrar { private struct MiscDef { public string title; public string prefabName; public string color; public int tier; public string description; } private static bool _done; private const string LightGrey = "#D3D3D3"; private const int MaxStacks = 12; private static readonly MiscDef[] _items = new MiscDef[7] { new MiscDef { title = "Flare", prefabName = "Item_Flaregun_Ammo", color = "#D3D3D3", tier = 0, description = "Start with flare(s)." }, new MiscDef { title = "Gold Roach", prefabName = "Denizen_Roach_Gold", color = "#FFD700", tier = 0, description = "Start with gold roaches." }, new MiscDef { title = "Platinum Roach", prefabName = "Denizen_Roach_Platinum", color = "#C0C0C0", tier = 0, description = "Start with platinum roaches." }, new MiscDef { title = "Ruby Roach", prefabName = "Denizen_Roach_Flying_Ruby", color = "#ED4040", tier = 0, description = "Start with ruby roaches." }, new MiscDef { title = "Tier 1 Floppy Disk", prefabName = "Item_Floppy_T1", color = "#D3D3D3", tier = 1, description = "Start with tier 1 floppy disks." }, new MiscDef { title = "Tier 2 Floppy Disk", prefabName = "Item_Floppy_T2", color = "#662E1C", tier = 2, description = "Start with tier 2 floppy disks." }, new MiscDef { title = "Tier 3 Floppy Disk", prefabName = "Item_Floppy_T3", color = "#493D06", tier = 3, description = "Start with tier 3 floppy disks." } }; internal static void TryRun() { if (_done) { return; } Sprite val = ContortionIconCache.Get(); bool flag = false; bool flag2 = true; MiscDef[] items = _items; for (int i = 0; i < items.Length; i++) { MiscDef miscDef = items[i]; string text = "cici_misc_" + miscDef.prefabName; if (TrinketRegistry._registry.ContainsKey(text)) { flag = true; continue; } Item_Object val2 = null; try { GameObject assetGameObject = CL_AssetManager.GetAssetGameObject(miscDef.prefabName, ""); val2 = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null); } catch { } if ((Object)(object)val2 == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[AutoMisc] '" + miscDef.prefabName + "' not yet loaded — skipping")); } flag2 = false; continue; } flag = true; Sprite icon = val ?? val2.itemData?.normalSprite; Item_Object ioRef = val2; string idCopy = text; TrinketRegistry.RegisterTrinket(text, miscDef.title, miscDef.description, "", 1, 0f, 0f, icon, delegate { TrinketRegistry.Entry value2; int num = ((!TrinketRegistry._registry.TryGetValue(idCopy, out value2)) ? 1 : Mathf.Max(1, value2.stackCount)); List<Item_Object> list = new List<Item_Object>(num); for (int j = 0; j < num; j++) { list.Add(ioRef); } return list; }); if (TrinketRegistry._registry.TryGetValue(text, out var value)) { value.titleColor = miscDef.color; value.maxStacks = 12; value.stackCount = 1; value.category = TrinketRegistry.Category.Other; value.bucket = TrinketRegistry.BucketFromColor(miscDef.color); value.tier = miscDef.tier; value.isFrameworkRegistered = true; value.isVanillaContent = true; } } if (flag2) { _done = true; } if (flag) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[AutoMisc] Pass complete — allResolved={flag2}"); } } } } public static class ArtifactTrinketAutoRegistrar { private struct ArtifactDef { public string title; public string prefabName; public string color; public string description; public string flavor; } private static bool _done; private const string MutexGroup = "artifacts"; private static readonly ArtifactDef[] _artifacts = new ArtifactDef[5] { new ArtifactDef { title = "Glove", prefabName = "Item_Artifact_EVAGlove", color = "#6DFDFD", description = "Start with the EVA Glove artifact.", flavor = "" }, new ArtifactDef { title = "Remote", prefabName = "Item_Artifact_Remote", color = "#C0C0C0", description = "Start with the Remote artifact.", flavor = "" }, new ArtifactDef { title = "Spear", prefabName = "Item_Artifact_Rebar_Return", color = "#ED4040", description = "Start with the Returning Spear artifact.", flavor = "" }, new ArtifactDef { title = "Timepiece", prefabName = "Item_Artifact_Timepiece", color = "#8EF6DD", description = "Start with the Timepiece artifact.", flavor = "" }, new ArtifactDef { title = "Translocator", prefabName = "Item_Artifact_Translocator", color = "#ED4040", description = "Start with the Translocator artifact.", flavor = "" } }; internal static void TryRun() { if (_done) { return; } List<(ArtifactDef, Item_Object)> list = new List<(ArtifactDef, Item_Object)>(); ArtifactDef[] artifacts = _artifacts; for (int i = 0; i < artifacts.Length; i++) { ArtifactDef item = artifacts[i]; Item_Object val = null; try { GameObject assetGameObject = CL_AssetManager.GetAssetGameObject(item.prefabName, ""); val = (((Object)(object)assetGameObject != (Object)null) ? assetGameObject.GetComponent<Item_Object>() : null); } catch { } if ((Object)(object)val == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[AutoArtifacts] '" + item.prefabName + "' not yet loaded — deferring")); } return; } list.Add((item, val)); } Sprite val2 = ContortionIconCache.Get(); List<string> list2 = new List<string>(); foreach (var item4 in list) { ArtifactDef item2 = item4.Item1; Item_Object item3 = item4.Item2; string text = "cici_artifact_" + item2.prefabName; if (TrinketRegistry._registry.ContainsKey(text)) { list2.Add(text); continue; } Sprite icon = val2 ?? item3.itemData?.normalSprite; Item_Object ioRef = item3; TrinketRegistry.RegisterTrinket(text, item2.title, item2.description, item2.flavor, 1, 0f, 0f, icon, () => new List<Item_Object> { ioRef }); if (TrinketRegistry._registry.TryGetValue(text, out var value)) { value.titleCo