Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of UnlockChecklist v0.1.1
UnlockChecklist.dll
Decompiled 15 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HG.Reflection; using HarmonyLib; using Microsoft.CodeAnalysis; using RoR2; using RoR2.Skills; using RoR2.UI; 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: OptIn] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("UnlockChecklist")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("UnlockChecklist")] [assembly: AssemblyTitle("UnlockChecklist")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 UnlockChecklist { internal static class ChecklistStore { private static readonly List<string> order = new List<string>(); private static readonly HashSet<string> tagged = new HashSet<string>(StringComparer.Ordinal); private static bool loaded; public static IReadOnlyList<string> Tags => order; public static int Count => order.Count; private static string FilePath => Path.Combine(Paths.ConfigPath, "com.bdub.UnlockChecklist.tags.txt"); public static event Action onChanged; public static bool IsTagged(string unlockableName) { if (!string.IsNullOrEmpty(unlockableName)) { return tagged.Contains(unlockableName); } return false; } public static bool Toggle(string unlockableName) { if (string.IsNullOrEmpty(unlockableName)) { return false; } if (tagged.Remove(unlockableName)) { order.Remove(unlockableName); Changed(); return false; } tagged.Add(unlockableName); order.Add(unlockableName); Changed(); return true; } public static bool Add(string unlockableName) { if (string.IsNullOrEmpty(unlockableName) || !tagged.Add(unlockableName)) { return false; } order.Add(unlockableName); Changed(); return true; } public static bool Remove(string unlockableName) { if (string.IsNullOrEmpty(unlockableName) || !tagged.Remove(unlockableName)) { return false; } order.Remove(unlockableName); Changed(); return true; } public static int ClearCompleted() { int num = 0; for (int num2 = order.Count - 1; num2 >= 0; num2--) { if (UnlockIndex.IsUnlocked(order[num2])) { tagged.Remove(order[num2]); order.RemoveAt(num2); num++; } } if (num > 0) { Changed(); } return num; } public static int Clear() { int count = order.Count; if (count == 0) { return 0; } order.Clear(); tagged.Clear(); Changed(); return count; } public static void Load() { order.Clear(); tagged.Clear(); try { if (File.Exists(FilePath)) { string[] array = File.ReadAllLines(FilePath); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0 && text[0] != '#' && tagged.Add(text)) { order.Add(text); } } } } catch (Exception ex) { Plugin.Log.LogError((object)("Could not read " + FilePath + ": " + ex.Message)); } loaded = true; ChecklistStore.onChanged?.Invoke(); } private static void Changed() { Save(); ChecklistStore.onChanged?.Invoke(); } private static void Save() { if (!loaded) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# UnlockChecklist tags - one UnlockableDef name per line, in list order."); stringBuilder.AppendLine("# Safe to edit by hand; lines starting with # are ignored."); stringBuilder.AppendLine("# Names that do not resolve are kept and shown as unresolved, not dropped."); foreach (string item in order) { stringBuilder.AppendLine(item); } try { File.WriteAllText(FilePath, stringBuilder.ToString()); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not write " + FilePath + ": " + ex.Message)); } } } public class ChecklistUI : MonoBehaviour { private struct RowEntry { public string unlockableName; public TextMeshProUGUI title; public TextMeshProUGUI requirement; public Image badge; public TextMeshProUGUI badgeLabel; public bool wasUnlocked; } [CompilerGenerated] private static class <>O { public static UnityAction <0>__Close; } private static ChecklistUI instance; private RectTransform window; private RectTransform content; private LayoutElement listAreaElement; private TextMeshProUGUI titleText; private TextMeshProUGUI statusText; private readonly List<RowEntry> rows = new List<RowEntry>(); private float nextStateCheck; private const float WindowWidth = 1020f; private const float MaxWindowHeight = 1000f; private const int WindowPadding = 24; private const int ListPadding = 8; private const float RowSpacing = 6f; private const float RowHeight = 76f; private const int MaxRows = 8; private const float IconSize = 56f; private const float StateCheckInterval = 1f; private const float Chrome = 196f; private static readonly Color WindowColor = new Color(0.07f, 0.08f, 0.1f, 0.97f); private static readonly Color PanelColor = new Color(0.12f, 0.13f, 0.16f, 0.9f); private static readonly Color RowColor = new Color(0.16f, 0.17f, 0.21f, 0.85f); private static readonly Color ButtonIdle = new Color(0.18f, 0.19f, 0.23f, 1f); private static readonly Color ButtonActive = new Color(0.9f, 0.58f, 0.16f, 1f); private static readonly Color DoneColor = new Color(0.38f, 0.8f, 0.42f, 1f); private static readonly Color TextColor = new Color(0.9f, 0.91f, 0.94f, 1f); private static readonly Color DimTextColor = new Color(0.55f, 0.56f, 0.6f, 1f); public static bool IsOpen => (Object)(object)instance != (Object)null; public static void Toggle() { if (IsOpen) { Close(); } else { Open(); } } public static void Open() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) Close(); GameObject val = new GameObject("UnlockChecklistUI"); val.SetActive(false); Canvas obj = val.AddComponent<Canvas>(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 520; CanvasScaler obj2 = val.AddComponent<CanvasScaler>(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); obj2.screenMatchMode = (ScreenMatchMode)0; obj2.matchWidthOrHeight = 0.5f; val.AddComponent<GraphicRaycaster>(); MPEventSystemProvider val2 = val.AddComponent<MPEventSystemProvider>(); val2.fallBackToMainEventSystem = true; val.AddComponent<MPEventSystemLocator>(); LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); MPEventSystem val3 = ((firstLocalUser != null) ? firstLocalUser.eventSystem : null); CursorOpener val4 = (Object.op_Implicit((Object)(object)Run.instance) ? val.AddComponent<CursorOpener>() : null); ChecklistUI checklistUI = val.AddComponent<ChecklistUI>(); checklistUI.Build(val); instance = checklistUI; val.SetActive(true); if (Object.op_Implicit((Object)(object)val4)) { val4.forceCursorForGamePad = true; } if (Object.op_Implicit((Object)(object)val3)) { val2.eventSystem = val3; } } public static void Close() { if (Object.op_Implicit((Object)(object)instance)) { Object.Destroy((Object)(object)((Component)instance).gameObject); } instance = null; } private void OnEnable() { ChecklistStore.onChanged += OnStoreChanged; } private void OnDisable() { ChecklistStore.onChanged -= OnStoreChanged; } private void OnDestroy() { if ((Object)(object)instance == (Object)(object)this) { instance = null; } } private void OnStoreChanged() { RebuildRows(); } private void Build(GameObject root) { //IL_001f: 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_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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Expected O, but got Unknown //IL_01b9: Unknown result type (might be due to invalid IL or missing references) CreateStretched("Backdrop", root.transform, new Color(0f, 0f, 0f, 0.72f)); window = CreatePanel("Window", root.transform, WindowColor); window.anchorMin = new Vector2(0.5f, 0.5f); window.anchorMax = new Vector2(0.5f, 0.5f); window.pivot = new Vector2(0.5f, 0.5f); window.anchoredPosition = Vector2.zero; window.sizeDelta = new Vector2(1020f, 600f); VerticalLayoutGroup obj = ((Component)window).gameObject.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)obj).padding = new RectOffset(24, 24, 20, 20); ((HorizontalOrVerticalLayoutGroup)obj).spacing = 10f; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; titleText = CreateLabel("Title", window, "UNLOCK CHECKLIST", 34f, (FontStyles)1, 46f); content = CreateScrollArea(window, "ListArea", out listAreaElement); VerticalLayoutGroup obj2 = ((Component)content).gameObject.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)obj2).padding = new RectOffset(8, 8, 8, 8); ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 6f; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; statusText = CreateLabel("Status", window, HintLine(), 18f, (FontStyles)2, 28f); ((Graphic)statusText).color = DimTextColor; CreateButtonRow(window); RebuildRows(); } private static string HintLine() { bool value = Plugin.TagOnLeftClickWhenLocked.Value; bool value2 = Plugin.TagOnRightClick.Value; string text = ((value && value2) ? "left-click a locked entry, or right-click any entry" : (value ? "left-click a locked entry" : "right-click an entry")); return "In the character select loadout panel, " + text + " to add it here."; } private RectTransform CreateScrollArea(RectTransform parent, string name, out LayoutElement heightElement) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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) RectTransform val = CreateChildRect(name, (Transform)(object)parent); heightElement = AddFixedHeight(val, 200f); ScrollRect obj = ((Component)val).gameObject.AddComponent<ScrollRect>(); obj.horizontal = false; obj.vertical = true; obj.movementType = (MovementType)2; obj.scrollSensitivity = 30f; RectTransform val2 = CreatePanel("Viewport", (Transform)(object)val, PanelColor); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; ((Component)val2).gameObject.AddComponent<RectMask2D>(); obj.viewport = val2; RectTransform val3 = CreateChildRect("Content", (Transform)(object)val2); val3.anchorMin = new Vector2(0f, 1f); val3.anchorMax = new Vector2(1f, 1f); val3.pivot = new Vector2(0.5f, 1f); val3.sizeDelta = Vector2.zero; val3.anchoredPosition = Vector2.zero; obj.content = val3; ((Component)val3).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2; return val3; } private void CreateButtonRow(RectTransform parent) { //IL_004e: 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_0064: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown RectTransform obj = CreateChildRect("Buttons", (Transform)(object)parent); AddFixedHeight(obj, 52f); HorizontalLayoutGroup obj2 = ((Component)obj).gameObject.AddComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 12f; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = true; CreateActionButton(obj, "Clear completed", ButtonIdle, new UnityAction(OnClearCompleted)); Color buttonActive = ButtonActive; object obj3 = <>O.<0>__Close; if (obj3 == null) { UnityAction val = Close; <>O.<0>__Close = val; obj3 = (object)val; } CreateActionButton(obj, "Close", buttonActive, (UnityAction)obj3); } private void RebuildRows() { //IL_0122: Unknown result type (might be due to invalid IL or missing references) rows.Clear(); DestroyChildren(content); List<UnlockEntry> list = new List<UnlockEntry>(); List<UnlockEntry> list2 = new List<UnlockEntry>(); foreach (string tag in ChecklistStore.Tags) { UnlockEntry entry = UnlockIndex.GetEntry(tag); if (entry.unlocked) { list2.Add(entry); } else { list.Add(entry); } } foreach (UnlockEntry item in list) { CreateRow(item); } if (Plugin.ShowCompleted.Value) { foreach (UnlockEntry item2 in list2) { CreateRow(item2); } } if (((Transform)content).childCount == 0) { RectTransform obj = CreateChildRect("EmptyNote", (Transform)(object)content); AddFixedHeight(obj, 56f); ((Graphic)CreateLabelIn(obj, (ChecklistStore.Count == 0) ? "Nothing tagged yet." : "Everything you tagged is unlocked. Press Clear completed to empty the list.", 19f, (FontStyles)2)).color = DimTextColor; } if (Object.op_Implicit((Object)(object)titleText)) { ((TMP_Text)titleText).text = ((list2.Count > 0) ? ("UNLOCK CHECKLIST " + list.Count + " to go, " + list2.Count + " done") : ("UNLOCK CHECKLIST " + list.Count + " to go")); } ApplyLayout(); } private void CreateRow(UnlockEntry entry) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_022f: 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_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Expected O, but got Unknown //IL_0059: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00f7: Unknown result type (might be due to invalid IL or missing references) RectTransform val = CreatePanel("Row_" + entry.unlockableName, (Transform)(object)content, RowColor); AddFixedHeight(val, 76f); if (Object.op_Implicit((Object)(object)entry.icon)) { RectTransform obj = CreateChildRect("Icon", (Transform)(object)val); obj.anchorMin = new Vector2(0f, 0.5f); obj.anchorMax = new Vector2(0f, 0.5f); obj.pivot = new Vector2(0f, 0.5f); obj.sizeDelta = new Vector2(56f, 56f); obj.anchoredPosition = new Vector2(12f, 0f); Image obj2 = ((Component)obj).gameObject.AddComponent<Image>(); obj2.sprite = entry.icon; obj2.preserveAspect = true; ((Graphic)obj2).raycastTarget = false; ((Graphic)obj2).color = (Color)(entry.unlocked ? Color.white : new Color(1f, 1f, 1f, 0.6f)); } RectTransform obj3 = CreateChildRect("Title", (Transform)(object)val); obj3.anchorMin = new Vector2(0f, 0.5f); obj3.anchorMax = new Vector2(1f, 1f); obj3.offsetMin = new Vector2(80f, 0f); obj3.offsetMax = new Vector2(-190f, -8f); TextMeshProUGUI val2 = ConfigureText(obj3, entry.Title, 21f, (FontStyles)1); ((TMP_Text)val2).alignment = (TextAlignmentOptions)1025; ((TMP_Text)val2).enableAutoSizing = true; ((TMP_Text)val2).fontSizeMin = 15f; ((TMP_Text)val2).fontSizeMax = 21f; RectTransform obj4 = CreateChildRect("Requirement", (Transform)(object)val); obj4.anchorMin = new Vector2(0f, 0f); obj4.anchorMax = new Vector2(1f, 0.5f); obj4.offsetMin = new Vector2(80f, 8f); obj4.offsetMax = new Vector2(-190f, 0f); TextMeshProUGUI val3 = ConfigureText(obj4, entry.requirement, 17f, (FontStyles)0); ((TMP_Text)val3).alignment = (TextAlignmentOptions)257; ((Graphic)val3).color = DimTextColor; RectTransform val4 = CreatePanel("Badge", (Transform)(object)val, DoneColor); val4.anchorMin = new Vector2(1f, 0.5f); val4.anchorMax = new Vector2(1f, 0.5f); val4.pivot = new Vector2(1f, 0.5f); val4.sizeDelta = new Vector2(92f, 30f); val4.anchoredPosition = new Vector2(-62f, 0f); TextMeshProUGUI val5 = CreateLabelIn(val4, "DONE", 16f, (FontStyles)1); ((Graphic)val5).color = new Color(0.05f, 0.09f, 0.06f, 1f); RectTransform val6 = CreatePanel("Remove", (Transform)(object)val, ButtonIdle); val6.anchorMin = new Vector2(1f, 0.5f); val6.anchorMax = new Vector2(1f, 0.5f); val6.pivot = new Vector2(1f, 0.5f); val6.sizeDelta = new Vector2(40f, 40f); val6.anchoredPosition = new Vector2(-10f, 0f); Button obj5 = ((Component)val6).gameObject.AddComponent<Button>(); ((Selectable)obj5).targetGraphic = (Graphic)(object)((Component)val6).GetComponent<Image>(); CreateLabelIn(val6, "x", 22f, (FontStyles)1); string captured = entry.unlockableName; ((UnityEvent)obj5.onClick).AddListener((UnityAction)delegate { ChecklistStore.Remove(captured); }); RowEntry rowEntry = new RowEntry { unlockableName = entry.unlockableName, title = val2, requirement = val3, badge = ((Component)val4).GetComponent<Image>(), badgeLabel = val5, wasUnlocked = entry.unlocked }; rows.Add(rowEntry); ApplyRowState(rowEntry, entry.unlocked); } private static void ApplyRowState(RowEntry row, bool unlocked) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)row.badge)) { ((Component)row.badge).gameObject.SetActive(unlocked); } if (Object.op_Implicit((Object)(object)row.title)) { ((Graphic)row.title).color = (unlocked ? DimTextColor : TextColor); ((TMP_Text)row.title).fontStyle = (FontStyles)((!unlocked) ? 1 : 65); } } private void ApplyLayout() { //IL_008b: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Clamp((!Object.op_Implicit((Object)(object)content)) ? 1 : ((Transform)content).childCount, 1, 8); while (num > 1 && 196f + ListHeight(num) > 1000f) { num--; } float num2 = ListHeight(num); if (Object.op_Implicit((Object)(object)listAreaElement)) { listAreaElement.preferredHeight = num2; listAreaElement.minHeight = num2; } if (Object.op_Implicit((Object)(object)window)) { window.sizeDelta = new Vector2(1020f, 196f + num2); } } private static float ListHeight(int rowCount) { return 16f + (float)rowCount * 76f + (float)(rowCount - 1) * 6f; } private void OnClearCompleted() { int num = ChecklistStore.ClearCompleted(); SetStatus((num == 0) ? "Nothing on the list is unlocked yet." : ("Cleared " + num + " completed " + ((num == 1) ? "entry." : "entries."))); } private void SetStatus(string message) { if (Object.op_Implicit((Object)(object)statusText)) { ((TMP_Text)statusText).text = message; } } private void Update() { if (Input.GetKeyDown((KeyCode)27)) { Close(); } else if (!(Time.unscaledTime < nextStateCheck)) { nextStateCheck = Time.unscaledTime + 1f; RefreshUnlockState(); } } private void RefreshUnlockState() { bool flag = false; for (int i = 0; i < rows.Count; i++) { RowEntry rowEntry = rows[i]; bool flag2 = UnlockIndex.IsUnlocked(rowEntry.unlockableName); if (flag2 != rowEntry.wasUnlocked) { if (flag2 && !Plugin.ShowCompleted.Value) { flag = true; break; } rowEntry.wasUnlocked = flag2; rows[i] = rowEntry; ApplyRowState(rowEntry, flag2); } } if (flag) { RebuildRows(); } } private static void DestroyChildren(RectTransform parent) { if (Object.op_Implicit((Object)(object)parent)) { for (int num = ((Transform)parent).childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)((Transform)parent).GetChild(num)).gameObject); } } } private static RectTransform CreateChildRect(string name, Transform parent) { //IL_0014: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_0037: Expected O, but got Unknown RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform; ((Transform)val).SetParent(parent, false); val.sizeDelta = Vector2.zero; return val; } private static RectTransform CreatePanel(string name, Transform parent, Color color) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = CreateChildRect(name, parent); ((Graphic)((Component)obj).gameObject.AddComponent<Image>()).color = color; return obj; } private static void CreateStretched(string name, Transform parent, Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = CreatePanel(name, parent, color); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.offsetMin = Vector2.zero; obj.offsetMax = Vector2.zero; } private static LayoutElement AddFixedHeight(RectTransform rect, float height) { LayoutElement obj = ((Component)rect).gameObject.AddComponent<LayoutElement>(); obj.preferredHeight = height; obj.minHeight = height; return obj; } private static TextMeshProUGUI CreateLabel(string name, RectTransform parent, string text, float size, FontStyles style, float height) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) RectTransform rect = CreateChildRect(name, (Transform)(object)parent); AddFixedHeight(rect, height); return ConfigureText(rect, text, size, style); } private static TextMeshProUGUI CreateLabelIn(RectTransform parent, string text, float size, FontStyles style) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = CreateChildRect("Label", (Transform)(object)parent); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.offsetMin = new Vector2(6f, 2f); obj.offsetMax = new Vector2(-6f, -2f); return ConfigureText(obj, text, size, style); } private static TextMeshProUGUI ConfigureText(RectTransform rect, string text, float size, FontStyles style) { //IL_001a: 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) TextMeshProUGUI obj = ((Component)rect).gameObject.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).text = text; ((TMP_Text)obj).fontSize = size; ((TMP_Text)obj).fontStyle = style; ((Graphic)obj).color = TextColor; ((TMP_Text)obj).alignment = (TextAlignmentOptions)514; ((Graphic)obj).raycastTarget = false; ((TMP_Text)obj).enableWordWrapping = false; ((TMP_Text)obj).overflowMode = (TextOverflowModes)1; return obj; } private static void CreateActionButton(RectTransform parent, string text, Color color, UnityAction onClick) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) RectTransform val = CreatePanel("Button_" + text, (Transform)(object)parent, color); Button obj = ((Component)val).gameObject.AddComponent<Button>(); ((Selectable)obj).targetGraphic = (Graphic)(object)((Component)val).GetComponent<Image>(); ((UnityEvent)obj.onClick).AddListener(onClick); CreateLabelIn(val, text, 22f, (FontStyles)1); } } internal static class Commands { [ConCommand(/*Could not decode attribute arguments.*/)] private static void CCUI(ConCommandArgs args) { ChecklistUI.Toggle(); } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CCList(ConCommandArgs args) { if (ChecklistStore.Count == 0) { Print("Checklist is empty. Tag something in the character select, or use uc_tag <name>."); return; } StringBuilder stringBuilder = new StringBuilder($"{ChecklistStore.Count} tagged:\n"); foreach (string tag in ChecklistStore.Tags) { UnlockEntry entry = UnlockIndex.GetEntry(tag); stringBuilder.AppendLine(" [" + (entry.unlocked ? "x" : " ") + "] " + entry.Title); stringBuilder.AppendLine(" " + Strip(entry.requirement)); stringBuilder.AppendLine(" " + tag); } Print(stringBuilder.ToString()); } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CCTag(ConCommandArgs args) { string name; if (((ConCommandArgs)(ref args)).Count < 1) { Print("Usage: uc_tag <unlockable name or search> (see uc_find)"); } else if (ResolveOne(((ConCommandArgs)(ref args)).GetArgString(0), out name)) { UnlockEntry entry = UnlockIndex.GetEntry(name); Print(ChecklistStore.Add(name) ? ("Tagged " + entry.Title + ".") : (entry.Title + " is already on the checklist.")); } } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CCUntag(ConCommandArgs args) { if (((ConCommandArgs)(ref args)).Count < 1) { Print("Usage: uc_untag <unlockable name or search> (see uc_list)"); return; } string argString = ((ConCommandArgs)(ref args)).GetArgString(0); List<string> list = new List<string>(); foreach (string tag in ChecklistStore.Tags) { UnlockEntry entry = UnlockIndex.GetEntry(tag); if (Matches(tag, argString) || Matches(entry.Title, argString)) { list.Add(tag); } } if (list.Count == 0) { Print("Nothing on the checklist matches '" + argString + "'. Try uc_list."); return; } if (list.Count > 1) { PrintCandidates(argString, list); return; } UnlockEntry entry2 = UnlockIndex.GetEntry(list[0]); ChecklistStore.Remove(list[0]); Print("Untagged " + entry2.Title + "."); } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CCClear(ConCommandArgs args) { string text = ((((ConCommandArgs)(ref args)).Count >= 1) ? ((ConCommandArgs)(ref args)).GetArgString(0).Trim().ToLowerInvariant() : string.Empty); int num; int num2; if (!(text == "done")) { num = ((text == "completed") ? 1 : 0); if (num == 0) { num2 = ChecklistStore.Clear(); goto IL_004e; } } else { num = 1; } num2 = ChecklistStore.ClearCompleted(); goto IL_004e; IL_004e: int num3 = num2; Print((num != 0) ? string.Format("Cleared {0} completed entr{1}.", num3, (num3 == 1) ? "y" : "ies") : $"Cleared the whole checklist ({num3})."); } [ConCommand(/*Could not decode attribute arguments.*/)] private static void CCFind(ConCommandArgs args) { if (((ConCommandArgs)(ref args)).Count < 1) { Print("Usage: uc_find <search>"); return; } string argString = ((ConCommandArgs)(ref args)).GetArgString(0); List<string> list = UnlockIndex.Search(argString); if (list.Count == 0) { Print("No unlockable matches '" + argString + "'."); } else { PrintCandidates(argString, list); } } private static bool ResolveOne(string query, out string name) { name = null; List<string> list = UnlockIndex.Search(query); if (list.Count == 0) { Print("No unlockable matches '" + query + "'. Try uc_find."); return false; } if (list.Count > 1) { PrintCandidates(query, list); return false; } name = list[0]; return true; } private static void PrintCandidates(string query, List<string> matches) { StringBuilder stringBuilder = new StringBuilder($"{matches.Count} match(es) for '{query}':\n"); int num = 0; foreach (string match in matches) { if (num++ >= 30) { stringBuilder.AppendLine($" ... and {matches.Count - 30} more. Narrow the search."); break; } UnlockEntry entry = UnlockIndex.GetEntry(match); stringBuilder.AppendLine(string.Format(" [{0}] {1,-48} {2}", entry.unlocked ? "x" : " ", match, entry.Title)); } Print(stringBuilder.ToString()); } private static bool Matches(string haystack, string needle) { if (!string.IsNullOrEmpty(haystack)) { return haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static string Strip(string text) { if (string.IsNullOrEmpty(text)) { return text; } StringBuilder stringBuilder = new StringBuilder(text.Length); bool flag = false; foreach (char c in text) { switch (c) { case '<': flag = true; continue; case '>': flag = false; continue; } if (!flag) { stringBuilder.Append((c == '\n') ? ' ' : c); } } return stringBuilder.ToString().Trim(); } private static void Print(string message) { Debug.Log((object)("[UnlockChecklist] " + message)); } } internal static class LoadoutTagger { private static readonly FieldInfo RowsField = AccessTools.Field(typeof(LoadoutPanelController), "rows"); private static readonly Type RowType = AccessTools.Inner(typeof(LoadoutPanelController), "Row"); private static readonly Type RowDataType = AccessTools.Inner(typeof(LoadoutPanelController), "RowData"); private static readonly FieldInfo RowDataField = ((RowType == null) ? null : AccessTools.Field(RowType, "rowData")); private static readonly FieldInfo ButtonField = ((RowDataType == null) ? null : AccessTools.Field(RowDataType, "button")); private static readonly FieldInfo DefIndexField = ((RowDataType == null) ? null : AccessTools.Field(RowDataType, "defIndex")); private static bool loadoutTaggingDisabled; private static bool survivorTaggingDisabled; private static readonly HashSet<string> warned = new HashSet<string>(); [HarmonyPostfix] [HarmonyPatch(typeof(LoadoutPanelController), "Rebuild")] private static void DecorateLoadoutPanel(LoadoutPanelController __instance) { if (loadoutTaggingDisabled) { return; } try { if (RowsField == null || RowDataField == null || ButtonField == null || DefIndexField == null) { Disable(ref loadoutTaggingDisabled, "LoadoutPanelController no longer exposes the fields this reads; skills and skins cannot be tagged from the loadout panel. Survivor tagging and the uc_ commands still work.", null); } else { Decorate(__instance); } } catch (Exception exception) { Disable(ref loadoutTaggingDisabled, "Loadout panel tagging failed and has been switched off.", exception); } } [HarmonyPostfix] [HarmonyPatch(typeof(SurvivorIconController), "Rebuild")] private static void DecorateSurvivorIcon(SurvivorIconController __instance) { if (survivorTaggingDisabled) { return; } try { TagMarker.AttachToSurvivor(__instance); SurvivorDef survivorDef = __instance.survivorDef; if (Object.op_Implicit((Object)(object)survivorDef) && Object.op_Implicit((Object)(object)survivorDef.unlockableDef)) { AppendHint(__instance.tooltipProvider); } } catch (Exception exception) { Disable(ref survivorTaggingDisabled, "Survivor tagging failed and has been switched off.", exception); } } private static void Decorate(LoadoutPanelController panel) { //IL_003d: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Invalid comparison between Unknown and I4 //IL_0048: 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_00f5: Unknown result type (might be due to invalid IL or missing references) MPEventSystemLocator component = ((Component)panel).GetComponent<MPEventSystemLocator>(); MPEventSystem obj = (Object.op_Implicit((Object)(object)component) ? component.eventSystem : null); object obj2; if (obj == null) { obj2 = null; } else { LocalUser localUser = obj.localUser; obj2 = ((localUser != null) ? localUser.currentNetworkUser : null); } NetworkUser val = (NetworkUser)obj2; BodyIndex val2 = (BodyIndex)((!Object.op_Implicit((Object)(object)val)) ? (-1) : ((int)val.bodyIndexPreference)); if ((int)val2 == -1) { return; } CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(val2); if (!Object.op_Implicit((Object)(object)bodyPrefabBodyComponent)) { return; } GenericSkill[] components = ((Component)bodyPrefabBodyComponent).GetComponents<GenericSkill>(); List<int> list = new List<int>(); for (int i = 0; i < components.Length; i++) { if (Object.op_Implicit((Object)(object)components[i]) && !components[i].hideInLoadoutSelect) { list.Add(i); } } SkinDef[] bodySkinDefs = SkinCatalog.GetBodySkinDefs(val2); if (!(RowsField.GetValue(panel) is IList list2)) { return; } if (list2.Count != list.Count + 1) { WarnOnce($"Loadout panel has {list2.Count} row(s) where {list.Count + 1} were expected " + "for " + BodyCatalog.GetBodyName(val2) + "; skipping tag markers for it rather than risking a wrong mapping. Tag it with uc_tag instead."); return; } for (int j = 0; j < list2.Count; j++) { bool flag = j == list.Count; SkillFamily family = (flag ? null : components[list[j]].skillFamily); DecorateRow(list2[j], family, flag ? bodySkinDefs : null); } } private static void WarnOnce(string message) { if (warned.Add(message)) { Plugin.Log.LogWarning((object)message); } } private static void DecorateRow(object row, SkillFamily family, SkinDef[] skins) { if (row == null || !(RowDataField.GetValue(row) is IList list)) { return; } for (int i = 0; i < list.Count; i++) { object obj = list[i]; if (obj == null) { continue; } object? value = ButtonField.GetValue(obj); MPButton val = (MPButton)((value is MPButton) ? value : null); int num = (int)DefIndexField.GetValue(obj); if (Object.op_Implicit((Object)(object)val) && num >= 0) { UnlockableDef val2 = ((skins != null) ? GetSkinUnlockable(skins, num) : GetVariantUnlockable(family, num)); if (Object.op_Implicit((Object)(object)val2)) { TagMarker.Attach(((Component)val).gameObject, val2.cachedName); AppendHint(((Component)val).GetComponent<TooltipProvider>()); } } } } private static UnlockableDef GetSkinUnlockable(SkinDef[] skins, int index) { if (index >= skins.Length || !Object.op_Implicit((Object)(object)skins[index])) { return null; } return skins[index].unlockableDef; } private static UnlockableDef GetVariantUnlockable(SkillFamily family, int index) { if (family?.variants == null || index >= family.variants.Length) { return null; } return family.variants[index].unlockableDef; } private static void AppendHint(TooltipProvider provider) { if (Plugin.AppendTooltipHint.Value && Object.op_Implicit((Object)(object)provider) && ((Behaviour)provider).enabled && !string.IsNullOrEmpty(provider.overrideBodyText)) { string text = Hint(); if (text != null) { provider.overrideBodyText = provider.overrideBodyText + "\n\n" + text; } } } private static string Hint() { bool value = Plugin.TagOnLeftClickWhenLocked.Value; bool value2 = Plugin.TagOnRightClick.Value; if (value && value2) { return "<style=cStack>Left or right click to add this to your unlock checklist.</style>"; } if (value) { return "<style=cStack>Click to add this to your unlock checklist.</style>"; } if (value2) { return "<style=cStack>Right click to add this to your unlock checklist.</style>"; } return null; } private static void Disable(ref bool flag, string message, Exception exception) { flag = true; Plugin.Log.LogError((object)((exception == null) ? message : (message + " " + exception))); } } [BepInPlugin("com.bdub.UnlockChecklist", "UnlockChecklist", "0.1.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.bdub.UnlockChecklist"; public const string ModName = "UnlockChecklist"; public const string ModVersion = "0.1.0"; internal static ManualLogSource Log; internal static Plugin Instance; internal static ConfigEntry<KeyboardShortcut> ToggleKey; internal static ConfigEntry<bool> TagOnLeftClickWhenLocked; internal static ConfigEntry<bool> TagOnRightClick; internal static ConfigEntry<bool> ShowCompleted; internal static ConfigEntry<bool> AppendTooltipHint; internal static ConfigEntry<bool> MarkTaggedInMenu; private Harmony harmony; private void Awake() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; BindConfig(); ChecklistStore.Load(); harmony = new Harmony("com.bdub.UnlockChecklist"); harmony.PatchAll(typeof(LoadoutTagger)); Log.LogInfo((object)string.Format("{0} {1} loaded with {2} tag(s).", "UnlockChecklist", "0.1.0", ChecklistStore.Count)); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } ChecklistUI.Close(); } private void BindConfig() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)107, Array.Empty<KeyCode>()), "Opens and closes the checklist. Works in a run and on the character select screen."); TagOnLeftClickWhenLocked = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "TagOnLeftClickWhenLocked", true, "Left-clicking a LOCKED entry in the character select tags it. Vanilla ignores that click entirely (locked buttons set disablePointerClick), so nothing is being overridden."); TagOnRightClick = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "TagOnRightClick", true, "Right-clicking any entry in the character select toggles its tag, locked or not. Vanilla binds nothing to right click here."); ShowCompleted = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowCompleted", true, "Keep tags you have since unlocked in the list, marked DONE. Off hides them, though they stay in the file until you clear them."); MarkTaggedInMenu = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "MarkTaggedInMenu", true, "Draw the orange corner pip and tint on tagged entries in the character select."); AppendTooltipHint = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "AppendTooltipHint", true, "Add a 'click to add to checklist' line to the tooltip of locked entries. Only touches tooltips the game has already filled in, and is rewritten from scratch on every rebuild."); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = ToggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && !IsTypingSomewhere()) { ChecklistUI.Toggle(); } } private static bool IsTypingSomewhere() { if (ConsoleWindow.IsShown()) { return true; } GameObject val = (Object.op_Implicit((Object)(object)EventSystem.current) ? EventSystem.current.currentSelectedGameObject : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } TMP_InputField component = val.GetComponent<TMP_InputField>(); if (Object.op_Implicit((Object)(object)component) && component.isFocused) { return true; } InputField component2 = val.GetComponent<InputField>(); if (Object.op_Implicit((Object)(object)component2)) { return component2.isFocused; } return false; } } internal class TagMarker : MonoBehaviour, IPointerClickHandler, IEventSystemHandler, IPointerDownHandler { private static readonly Color TaggedColor = new Color(0.95f, 0.62f, 0.18f, 1f); private static readonly Color DoneColor = new Color(0.38f, 0.8f, 0.42f, 1f); private string staticKey; private SurvivorIconController survivorSource; private Image tint; private Image pip; private string lastKey; private bool lastVisible; private bool lastDone; public string Key { get { if (!Object.op_Implicit((Object)(object)survivorSource)) { return staticKey; } SurvivorDef survivorDef = survivorSource.survivorDef; if (!Object.op_Implicit((Object)(object)survivorDef) || !Object.op_Implicit((Object)(object)survivorDef.unlockableDef)) { return null; } return survivorDef.unlockableDef.cachedName; } } public static void Attach(GameObject target, string unlockableName) { if (Object.op_Implicit((Object)(object)target) && !string.IsNullOrEmpty(unlockableName)) { TagMarker obj = target.GetComponent<TagMarker>() ?? target.AddComponent<TagMarker>(); obj.staticKey = unlockableName; obj.survivorSource = null; obj.Refresh(); } } public static void AttachToSurvivor(SurvivorIconController controller) { if (Object.op_Implicit((Object)(object)controller)) { TagMarker obj = ((Component)controller).GetComponent<TagMarker>() ?? ((Component)controller).gameObject.AddComponent<TagMarker>(); obj.staticKey = null; obj.survivorSource = controller; obj.Refresh(); } } public void OnPointerDown(PointerEventData eventData) { } public void OnPointerClick(PointerEventData eventData) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) string key = Key; if (string.IsNullOrEmpty(key)) { return; } if ((int)eventData.button == 1) { if (!Plugin.TagOnRightClick.Value) { return; } } else if ((int)eventData.button != 0 || !Plugin.TagOnLeftClickWhenLocked.Value || UnlockIndex.IsUnlocked(key)) { return; } UnlockEntry entry = UnlockIndex.GetEntry(key); bool flag = ChecklistStore.Toggle(key); Plugin.Log.LogInfo((object)((flag ? "Tagged " : "Untagged ") + entry.Title + " [" + key + "]")); Refresh(); } private void LateUpdate() { Refresh(); } private void Refresh() { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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) string key = Key; bool flag = Plugin.MarkTaggedInMenu.Value && ChecklistStore.IsTagged(key); bool flag2 = flag && UnlockIndex.IsUnlocked(key); if (!(key == lastKey) || flag != lastVisible || flag2 != lastDone) { lastKey = key; lastVisible = flag; lastDone = flag2; if (flag && !Object.op_Implicit((Object)(object)pip)) { Build(); } if (Object.op_Implicit((Object)(object)pip)) { Color val = (flag2 ? DoneColor : TaggedColor); ((Graphic)pip).color = val; ((Graphic)tint).color = new Color(val.r, val.g, val.b, 0.18f); ((Component)pip).gameObject.SetActive(flag); ((Component)tint).gameObject.SetActive(flag); } } } private void Build() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_003b: Unknown result type (might be due to invalid IL or missing references) tint = CreateOverlay("ChecklistTint", Vector2.zero, Vector2.one); pip = CreateOverlay("ChecklistPip", new Vector2(0.64f, 0.64f), new Vector2(0.96f, 0.96f)); } private Image CreateOverlay(string name, Vector2 anchorMin, Vector2 anchorMax) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0054: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent(((Component)this).transform, false); val2.anchorMin = anchorMin; val2.anchorMax = anchorMax; val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; val.AddComponent<LayoutElement>().ignoreLayout = true; Image obj = val.AddComponent<Image>(); ((Graphic)obj).raycastTarget = false; return obj; } private void OnDestroy() { tint = null; pip = null; } } internal enum UnlockKind { Unresolved, Survivor, Skill, Skin } internal struct UnlockEntry { public string unlockableName; public UnlockKind kind; public string owner; public string label; public string slotLabel; public string requirement; public Sprite icon; public bool unlocked; public string Title { get { string text = (string.IsNullOrEmpty(owner) ? label : (owner + " - " + label)); if (!string.IsNullOrEmpty(slotLabel)) { return text + " (" + slotLabel + ")"; } return text; } } } internal static class UnlockIndex { private struct Descriptor { public UnlockKind kind; public string owner; public string label; public string slotLabel; public Sprite icon; } private static Dictionary<string, Descriptor> map; private static Dictionary<string, Descriptor> Map => map ?? (map = Build()); public static void Invalidate() { map = null; } public static UnlockEntry GetEntry(string unlockableName) { UnlockEntry result = new UnlockEntry { unlockableName = unlockableName, kind = UnlockKind.Unresolved, label = unlockableName, unlocked = IsUnlocked(unlockableName) }; if (Map.TryGetValue(unlockableName, out var value)) { result.kind = value.kind; result.owner = value.owner; result.label = value.label; result.slotLabel = value.slotLabel; result.icon = value.icon; } AchievementDef achievement = GetAchievement(unlockableName); if (achievement != null) { result.requirement = Resolve(achievement.descriptionToken, null); if (result.kind == UnlockKind.Unresolved) { result.label = Resolve(achievement.nameToken, unlockableName); } if (!Object.op_Implicit((Object)(object)result.icon)) { result.icon = achievement.GetAchievedIcon(); } } if (string.IsNullOrEmpty(result.requirement)) { UnlockableDef unlockableDef = GetUnlockableDef(unlockableName); result.requirement = (Object.op_Implicit((Object)(object)unlockableDef) ? unlockableDef.getHowToUnlockString() : null); } if (string.IsNullOrEmpty(result.requirement) || result.requirement == "???") { result.requirement = ((result.kind == UnlockKind.Unresolved) ? "Not installed in this modpack, or it has no unlock condition." : "No unlock condition is recorded for this."); } return result; } public static bool IsUnlocked(string unlockableName) { if (string.IsNullOrEmpty(unlockableName)) { return true; } UnlockableDef unlockableDef = GetUnlockableDef(unlockableName); if (!Object.op_Implicit((Object)(object)unlockableDef)) { return false; } foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList) { if (((readOnlyLocalUsers != null) ? readOnlyLocalUsers.userProfile : null) != null && readOnlyLocalUsers.userProfile.HasUnlockable(unlockableDef)) { return true; } } return false; } public static bool IsKnown(string unlockableName) { if (!string.IsNullOrEmpty(unlockableName)) { return Map.ContainsKey(unlockableName); } return false; } public static List<string> Search(string query) { List<string> list = new List<string>(); if (string.IsNullOrEmpty(query)) { return list; } string text = query.Trim(); if (Map.ContainsKey(text)) { list.Add(text); return list; } foreach (KeyValuePair<string, Descriptor> item in Map) { Descriptor value = item.Value; if (Contains(item.Key, text) || Contains(value.label, text) || Contains(value.owner + " " + value.label, text)) { list.Add(item.Key); } } return list; } private static bool Contains(string haystack, string needle) { if (!string.IsNullOrEmpty(haystack)) { return haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } public static UnlockableDef GetUnlockableDef(string unlockableName) { if (string.IsNullOrEmpty(unlockableName)) { return null; } try { return UnlockableCatalog.GetUnlockableDef(unlockableName); } catch (Exception) { return null; } } private static AchievementDef GetAchievement(string unlockableName) { try { return AchievementManager.GetAchievementDefFromUnlockable(unlockableName); } catch (Exception) { return null; } } private static Dictionary<string, Descriptor> Build() { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, Descriptor> dictionary = new Dictionary<string, Descriptor>(StringComparer.Ordinal); foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs) { if (!Object.op_Implicit((Object)(object)orderedSurvivorDef) || !Object.op_Implicit((Object)(object)orderedSurvivorDef.bodyPrefab)) { continue; } CharacterBody component = orderedSurvivorDef.bodyPrefab.GetComponent<CharacterBody>(); if (Object.op_Implicit((Object)(object)component)) { string text = Resolve(orderedSurvivorDef.displayNameToken, orderedSurvivorDef.cachedName); if (Object.op_Implicit((Object)(object)orderedSurvivorDef.unlockableDef)) { Add(dictionary, orderedSurvivorDef.unlockableDef.cachedName, new Descriptor { kind = UnlockKind.Survivor, owner = string.Empty, label = text, slotLabel = string.Empty, icon = null }); } AddSkills(dictionary, component, text); AddSkins(dictionary, component.bodyIndex, text); } } Plugin.Log.LogInfo((object)("Indexed " + dictionary.Count + " unlockable(s) across " + SurvivorCatalog.survivorCount + " survivor(s).")); return dictionary; } private static void AddSkills(Dictionary<string, Descriptor> result, CharacterBody prefabBody, string survivorName) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) SkillLocator component = ((Component)prefabBody).GetComponent<SkillLocator>(); GenericSkill[] components = ((Component)prefabBody).GetComponents<GenericSkill>(); foreach (GenericSkill val in components) { SkillFamily val2 = (Object.op_Implicit((Object)(object)val) ? val.skillFamily : null); if ((Object)(object)val2 == (Object)null || val2.variants == null) { continue; } string slotLabel = GetSlotLabel(component, val); Variant[] variants = val2.variants; foreach (Variant val3 in variants) { if (Object.op_Implicit((Object)(object)val3.unlockableDef) && Object.op_Implicit((Object)(object)val3.skillDef)) { Add(result, val3.unlockableDef.cachedName, new Descriptor { kind = UnlockKind.Skill, owner = survivorName, label = Resolve(val3.skillDef.skillNameToken, val3.skillDef.skillName), slotLabel = slotLabel, icon = val3.skillDef.icon }); } } } } private static void AddSkins(Dictionary<string, Descriptor> result, BodyIndex bodyIndex, string survivorName) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) if ((int)bodyIndex == -1) { return; } SkinDef[] bodySkinDefs = SkinCatalog.GetBodySkinDefs(bodyIndex); if (bodySkinDefs == null) { return; } SkinDef[] array = bodySkinDefs; foreach (SkinDef val in array) { if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.unlockableDef)) { Add(result, val.unlockableDef.cachedName, new Descriptor { kind = UnlockKind.Skin, owner = survivorName, label = Resolve(val.nameToken, ((Object)val).name), slotLabel = "Skin", icon = val.icon }); } } } private static string GetSlotLabel(SkillLocator locator, GenericSkill slot) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected I4, but got Unknown if (!string.IsNullOrWhiteSpace(slot.loadoutTitleToken)) { return Resolve(slot.loadoutTitleToken, slot.loadoutTitleToken); } SkillSlot val = (SkillSlot)((!Object.op_Implicit((Object)(object)locator)) ? (-1) : ((int)locator.FindSkillSlot(slot))); return Resolve((int)val switch { 0 => "LOADOUT_SKILL_PRIMARY", 1 => "LOADOUT_SKILL_SECONDARY", 2 => "LOADOUT_SKILL_UTILITY", 3 => "LOADOUT_SKILL_SPECIAL", _ => "LOADOUT_SKILL_MISC", }, string.Empty); } private static void Add(Dictionary<string, Descriptor> result, string name, Descriptor descriptor) { if (!string.IsNullOrEmpty(name) && !result.ContainsKey(name)) { result[name] = descriptor; } } private static string Resolve(string token, string fallback) { if (string.IsNullOrEmpty(token)) { return fallback; } string text = Language.GetString(token); if (!string.IsNullOrEmpty(text) && !(text == token)) { return text; } return fallback; } } }