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 SaleStarReminder v1.0.0
plugins/SaleStarReminder/SaleStarReminder.dll
Decompiled 2 hours agousing 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.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.UI; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("RoR2")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SaleStarReminder")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+f8a53eb52f28146eeca5f0161efe17cda8f77167")] [assembly: AssemblyProduct("SaleStarReminder")] [assembly: AssemblyTitle("SaleStarReminder")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 SaleStarReminder { internal sealed class ChestScanner { private const string CategorySeparator = " - "; private const string ChestWord = "Chest"; private const string SmallChestToken = "CHEST1_NAME"; private const string SmallChestName = "Small Chest"; private int scannedInstanceCount = -1; private int scannedCandidateCount = -1; private bool scannedHasKey; private bool scannedRemoteOp; private PurchaseInteraction best; public bool AnyUsable => scannedCandidateCount > 0; public PurchaseInteraction Best => best; public void Refresh(Inventory inventory, CharacterBody body) { bool flag = HasRustedKey(inventory); bool flag2 = IsRemoteOp(body); List<PurchaseInteraction> instancesList = InstanceTracker.GetInstancesList<PurchaseInteraction>(); int num = 0; foreach (PurchaseInteraction item in instancesList) { if (IsCandidate(item, flag, flag2)) { num++; } } bool flag3 = num == 0 || (Object.op_Implicit((Object)(object)best) && IsCandidate(best, flag, flag2)); if (!(instancesList.Count == scannedInstanceCount && num == scannedCandidateCount && flag == scannedHasKey && flag2 == scannedRemoteOp && flag3)) { scannedInstanceCount = instancesList.Count; scannedCandidateCount = num; scannedHasKey = flag; scannedRemoteOp = flag2; best = FindBest(instancesList, flag, flag2, null); } } public PurchaseInteraction GetBestExcluding(PurchaseInteraction exclude) { if ((Object)(object)best != (Object)(object)exclude) { return best; } return FindBest(InstanceTracker.GetInstancesList<PurchaseInteraction>(), scannedHasKey, scannedRemoteOp, exclude); } public static string GetDisplayName(PurchaseInteraction chest) { string text = Language.GetString(chest.displayNameToken); if (Language.currentLanguageName != "en") { return text; } if (chest.displayNameToken == "CHEST1_NAME") { return "Small Chest"; } int num = text.IndexOf(" - ", StringComparison.Ordinal); if (num < 0) { return text; } string text2 = text.Substring(0, num); if (!text2.EndsWith("Chest", StringComparison.Ordinal)) { return text; } string text3 = text.Substring(num + " - ".Length).Trim(); return text2.Substring(0, text2.Length - "Chest".Length) + text3 + " Chest"; } public static void DumpAll(Inventory inventory, CharacterBody body) { //IL_00dd: Unknown result type (might be due to invalid IL or missing references) bool flag = HasRustedKey(inventory); bool flag2 = IsRemoteOp(body); List<PurchaseInteraction> instancesList = InstanceTracker.GetInstancesList<PurchaseInteraction>(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"{instancesList.Count} purchasable objects, Rusted Key held: {flag}," + $" remote operation: {flag2}"); foreach (PurchaseInteraction item in instancesList) { if (Object.op_Implicit((Object)(object)item)) { stringBuilder.AppendLine(" " + ((Object)((Component)item).gameObject).name + ": token=" + item.displayNameToken + $" compatible={item.saleStarCompatible} available={item.available}" + $" cost={item.cost} costType={item.costType} tier={ChestTiers.Get(item)}" + $" allowRemoteOp={item.allowRemoteOpInteraction}" + $" candidate={IsCandidate(item, flag, flag2)}"); } } SaleStarReminderPlugin.Log.LogInfo((object)stringBuilder.ToString()); } private static bool IsCandidate(PurchaseInteraction chest, bool hasKey, bool remoteOp) { if (Object.op_Implicit((Object)(object)chest) && chest.saleStarCompatible && chest.available && (hasKey || chest.displayNameToken != "LOCKBOX_NAME")) { if (remoteOp) { return chest.allowRemoteOpInteraction; } return true; } return false; } private static bool IsRemoteOp(CharacterBody body) { if (Object.op_Implicit((Object)(object)body)) { return body.isRemoteOp; } return false; } private static bool HasRustedKey(Inventory inventory) { if (Object.op_Implicit((Object)(object)inventory)) { return inventory.GetItemCountEffective(Items.TreasureCache) > 0; } return false; } private static PurchaseInteraction FindBest(List<PurchaseInteraction> all, bool hasKey, bool remoteOp, PurchaseInteraction exclude) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) PurchaseInteraction val = null; ChestTier chestTier = ChestTier.Unknown; foreach (PurchaseInteraction item in all) { if (!((Object)(object)item == (Object)(object)exclude) && IsCandidate(item, hasKey, remoteOp)) { ChestTier chestTier2 = ChestTiers.Get(item); if (!Object.op_Implicit((Object)(object)val) || chestTier2 > chestTier || (chestTier2 == chestTier && item.costType == val.costType && item.cost > val.cost)) { val = item; chestTier = chestTier2; } } } return val; } } internal enum ChestTier { Unknown, Lesser, Small, Adaptive, Large, Legendary } internal static class ChestTiers { public const string RustyLockboxToken = "LOCKBOX_NAME"; private static readonly Dictionary<string, ChestTier> ByToken = new Dictionary<string, ChestTier> { { "EQUIPMENTBARREL_NAME", ChestTier.Lesser }, { "HOLLOWCHEST_NAME", ChestTier.Lesser }, { "CHEST1_NAME", ChestTier.Small }, { "CHEST1_STEALTHED_NAME", ChestTier.Small }, { "CATEGORYCHEST_DAMAGE_NAME", ChestTier.Small }, { "CATEGORYCHEST_HEALING_NAME", ChestTier.Small }, { "CATEGORYCHEST_UTILITY_NAME", ChestTier.Small }, { "CASINOCHEST_NAME", ChestTier.Adaptive }, { "CHEST2_NAME", ChestTier.Large }, { "CATEGORYCHEST2_DAMAGE_NAME", ChestTier.Large }, { "CATEGORYCHEST2_HEALING_NAME", ChestTier.Large }, { "CATEGORYCHEST2_UTILITY_NAME", ChestTier.Large }, { "LOCKBOX_NAME", ChestTier.Large }, { "GOLDCHEST_NAME", ChestTier.Legendary } }; public static ChestTier Get(PurchaseInteraction chest) { string displayNameToken = chest.displayNameToken; if (displayNameToken == null || !ByToken.TryGetValue(displayNameToken, out var value)) { return ChestTier.Unknown; } return value; } public static bool IsMockable(ChestTier tier) { if (tier != ChestTier.Lesser) { return tier == ChestTier.Small; } return true; } } internal static class EnglishArticle { private static readonly string[] ConsonantSoundPrefixes = new string[12] { "uni", "use", "usu", "uti", "ure", "uri", "uro", "ubiq", "eu", "ewe", "one", "once" }; private static readonly string[] VowelSoundPrefixes = new string[5] { "hour", "honest", "honor", "honour", "heir" }; public static string For(string phrase) { string text = phrase.TrimStart().ToLowerInvariant(); if (text.Length == 0) { return "a"; } if (StartsWithAny(text, ConsonantSoundPrefixes)) { return "a"; } if (StartsWithAny(text, VowelSoundPrefixes)) { return "an"; } if ("aeiou".IndexOf(text[0]) < 0) { return "a"; } return "an"; } private static bool StartsWithAny(string word, string[] prefixes) { foreach (string value in prefixes) { if (word.StartsWith(value, StringComparison.Ordinal)) { return true; } } return false; } } internal static class MockLines { [Serializable] internal sealed class LinesFile { public LineSet smallChest; public LineSet betterChest; } [Serializable] internal sealed class LineSet { public string[] clean; public string[] vulgar; } public const string FileName = "MockLines.json"; private static string[] smallChest = Array.Empty<string>(); private static string[] smallChestVulgar = Array.Empty<string>(); private static string[] betterChest = Array.Empty<string>(); private static string[] betterChestVulgar = Array.Empty<string>(); public static void Load(string directory) { string text = Path.Combine(directory, "MockLines.json"); if (!File.Exists(text)) { SaleStarReminderPlugin.Log.LogWarning((object)(text + " is missing, so the mocking message is off.")); return; } LinesFile linesFile; try { linesFile = JsonUtility.FromJson<LinesFile>(File.ReadAllText(text)); } catch (Exception ex) { SaleStarReminderPlugin.Log.LogError((object)("Couldn't read " + text + ", so the mocking message is off: " + ex.Message)); return; } if (linesFile == null) { SaleStarReminderPlugin.Log.LogWarning((object)(text + " is empty, so the mocking message is off.")); return; } smallChest = Clean(linesFile.smallChest?.clean); smallChestVulgar = Clean(linesFile.smallChest?.vulgar); betterChest = Clean(linesFile.betterChest?.clean); betterChestVulgar = Clean(linesFile.betterChest?.vulgar); if (SaleStarReminderPlugin.Settings.DebugLogging.Value) { SaleStarReminderPlugin.Log.LogInfo((object)($"Loaded mocking lines from {text}: {smallChest.Length} + " + $"{smallChestVulgar.Length} vulgar headlines, {betterChest.Length} + {betterChestVulgar.Length}" + " vulgar better-chest lines.")); } } public static string PickSmallChest(bool includeVulgar) { return Pick(smallChest, smallChestVulgar, includeVulgar); } public static string PickBetterChest(bool includeVulgar, string chestName) { return Pick(betterChest, betterChestVulgar, includeVulgar)?.Replace("{0}", chestName); } private static string Pick(string[] clean, string[] vulgar, bool includeVulgar) { int num = (includeVulgar ? vulgar.Length : 0); int num2 = clean.Length + num; if (num2 == 0) { return null; } int num3 = Random.Range(0, num2); if (num3 >= clean.Length) { return vulgar[num3 - clean.Length]; } return clean[num3]; } private static string[] Clean(string[] lines) { if (lines != null) { return lines.Where((string line) => !string.IsNullOrWhiteSpace(line)).ToArray(); } return Array.Empty<string>(); } } internal sealed class PluginConfig { public readonly ConfigEntry<bool> ShowReminder; public readonly ConfigEntry<float> ReminderFontSize; public readonly ConfigEntry<float> SubheaderFontSize; public readonly ConfigEntry<float> ReminderOffsetY; public readonly ConfigEntry<float> NearChestScale; public readonly ConfigEntry<bool> PulseNearChest; public readonly ConfigEntry<bool> ShowMostValuableChest; public readonly ConfigEntry<bool> MockSmallChest; public readonly ConfigEntry<bool> MockIncludeVulgar; public readonly ConfigEntry<float> MockDurationSeconds; public readonly ConfigEntry<bool> DebugLogging; public readonly ConfigEntry<bool> DebugAlwaysShow; public readonly ConfigEntry<KeyboardShortcut> DumpChestsKey; public PluginConfig(ConfigFile config) { //IL_0180: Unknown result type (might be due to invalid IL or missing references) ShowReminder = config.Bind<bool>("Reminder", "ShowReminder", true, "Show large red text at the top of the screen while you hold an unused Sale Star and the stage has a chest it works on."); ReminderFontSize = config.Bind<float>("Reminder", "ReminderFontSize", 80f, "Font size of the main alert, in UI points."); SubheaderFontSize = config.Bind<float>("Reminder", "SubheaderFontSize", 20f, "Font size of the smaller line under the main alert, in UI points."); ReminderOffsetY = config.Bind<float>("Reminder", "ReminderOffsetY", 8f, "Gap between the bottom of the item box at the top of the screen and the reminder text, in UI pixels."); NearChestScale = config.Bind<float>("Reminder", "NearChestScale", 1.3f, "How much bigger the main alert gets while the game circles a chest your Sale Star works on (when you look at it up close), if that chest is worse than a Large chest or better still on the stage. 1 turns this off."); PulseNearChest = config.Bind<bool>("Reminder", "PulseNearChest", true, "Fade the main alert in and out, twice per second, at the same times it grows (see NearChestScale). Turn this off if any pulsing or flashing bothers you."); ShowMostValuableChest = config.Bind<bool>("MostValuableChest", "ShowMostValuableChest", false, "Under the reminder, name the most valuable unopened chest on the stage that the Sale Star works on. This includes chests you haven't found yet."); MockSmallChest = config.Bind<bool>("Mock", "MockSmallChest", false, "Make fun of you for a few seconds after you spend a Sale Star on a small chest, an Equipment Barrel or a Concept Reliquary while a Large Chest, Rusty Lockbox or Legendary Chest was still available. With ShowMostValuableChest on, also names that chest. The lines come from MockLines.json next to the mod's DLL."); MockIncludeVulgar = config.Bind<bool>("Mock", "MockIncludeVulgar", false, "Also pick from the vulgar lines when making fun of you."); MockDurationSeconds = config.Bind<float>("Mock", "MockDurationSeconds", 6f, "How long the mocking message stays on screen, in seconds."); DebugLogging = config.Bind<bool>("Debug", "DebugLogging", false, "Log each Sale Star use the mod detects, and enable the chest dump key."); DebugAlwaysShow = config.Bind<bool>("Debug", "DebugAlwaysShow", false, "Show the reminder even without a Sale Star or a usable chest, for testing."); DumpChestsKey = config.Bind<KeyboardShortcut>("Debug", "DumpChestsKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "With DebugLogging on, press to log every purchasable object in the current stage and how the mod ranks it."); } } internal sealed class ReminderBanner : MonoBehaviour { private const float FadeDuration = 0.2f; private const float SideMargin = 40f; private const float EmphasisFadeDuration = 0.15f; private const float PulseFrequency = 2f; private const float PulseMinAlpha = 0.35f; private const string ReminderHeadline = "UNUSED SALE STAR"; private static readonly Color HeadlineColor = new Color(1f, 0.17f, 0.17f); private static readonly Color SubheaderColor = new Color(1f, 0.92f, 0.92f); private RectTransform rectTransform; private ItemInventoryDisplay itemDisplay; private readonly Vector3[] corners = (Vector3[])(object)new Vector3[4]; private CanvasGroup canvasGroup; private TextMeshProUGUI headline; private TextMeshProUGUI subheader; private bool visible; private bool emphasized; private float emphasis; private float pulseTime; private float shownHeadlineSize = -1f; private float shownSubheaderSize = -1f; public static ReminderBanner Create(HUD hud) { //IL_0024: 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) //IL_003a: 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_0046: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) Transform transform = hud.mainContainer.transform; GameObject val = new GameObject("SaleStarReminderBanner", new Type[1] { typeof(RectTransform) }) { layer = ((Component)transform).gameObject.layer }; RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent(transform, false); val2.anchorMin = new Vector2(0f, 1f); val2.anchorMax = new Vector2(1f, 1f); val2.pivot = new Vector2(0.5f, 1f); val2.sizeDelta = new Vector2(-80f, 0f); val.AddComponent<LayoutElement>().ignoreLayout = true; VerticalLayoutGroup obj = val.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)obj).childAlignment = (TextAnchor)1; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; ContentSizeFitter obj2 = val.AddComponent<ContentSizeFitter>(); obj2.horizontalFit = (FitMode)0; obj2.verticalFit = (FitMode)2; CanvasGroup val3 = val.AddComponent<CanvasGroup>(); val3.alpha = 0f; val3.interactable = false; val3.blocksRaycasts = false; ReminderBanner reminderBanner = val.AddComponent<ReminderBanner>(); reminderBanner.rectTransform = val2; reminderBanner.itemDisplay = hud.itemInventoryDisplay; reminderBanner.canvasGroup = val3; reminderBanner.headline = CreateText(val2, "Headline", HeadlineColor); reminderBanner.subheader = CreateText(val2, "Subheader", SubheaderColor); ((Component)reminderBanner.subheader).gameObject.SetActive(false); return reminderBanner; } private static TextMeshProUGUI CreateText(RectTransform parent, string name, Color color) { //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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }) { layer = ((Component)parent).gameObject.layer }; val.transform.SetParent((Transform)(object)parent, false); HGTextMeshProUGUI obj = val.AddComponent<HGTextMeshProUGUI>(); ((TMP_Text)obj).richText = true; ((TMP_Text)obj).enableWordWrapping = true; ((TMP_Text)obj).alignment = (TextAlignmentOptions)258; ((Graphic)obj).color = color; ((Graphic)obj).raycastTarget = false; return (TextMeshProUGUI)(object)obj; } public void ShowReminder(string subline, bool nearChest) { Show("UNUSED SALE STAR", subline); emphasized = nearChest; } public void ShowMock(string line, string subline) { Show(line, subline); emphasized = false; } public void Hide() { visible = false; emphasized = false; } private void Show(string line, string subline) { visible = true; if (((TMP_Text)headline).text != line) { ((TMP_Text)headline).text = line; } bool flag = !string.IsNullOrEmpty(subline); if (((Component)subheader).gameObject.activeSelf != flag) { ((Component)subheader).gameObject.SetActive(flag); } if (flag && ((TMP_Text)subheader).text != subline) { ((TMP_Text)subheader).text = subline; } } private void LateUpdate() { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) PluginConfig settings = SaleStarReminderPlugin.Settings; emphasis = Mathf.MoveTowards(emphasis, emphasized ? 1f : 0f, Time.unscaledDeltaTime / 0.15f); float num = settings.ReminderFontSize.Value * Mathf.Lerp(1f, settings.NearChestScale.Value, emphasis); if (num != shownHeadlineSize) { shownHeadlineSize = num; ((TMP_Text)headline).fontSize = num; } UpdatePulse(settings.PulseNearChest.Value); float value = settings.SubheaderFontSize.Value; if (value != shownSubheaderSize) { shownSubheaderSize = value; ((TMP_Text)subheader).fontSize = value; } float num2 = (visible ? 1f : 0f); if (visible || canvasGroup.alpha > 0f) { rectTransform.anchoredPosition = new Vector2(0f, GetItemDisplayBottom() - settings.ReminderOffsetY.Value); } canvasGroup.alpha = Mathf.MoveTowards(canvasGroup.alpha, num2, Time.unscaledDeltaTime / 0.2f); } private void UpdatePulse(bool enabled) { float num = 1f; if (enabled && emphasis > 0f) { pulseTime += Time.unscaledDeltaTime; float num2 = 0.5f - 0.5f * Mathf.Cos(MathF.PI * 4f * pulseTime); num = Mathf.Lerp(1f, 0.35f, num2 * emphasis); } else { pulseTime = 0f; } if (((TMP_Text)headline).alpha != num) { ((TMP_Text)headline).alpha = num; } } private float GetItemDisplayBottom() { //IL_0032: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)itemDisplay)) { Transform parent = ((Transform)rectTransform).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (val != null) { ((RectTransform)((Component)itemDisplay).transform).GetWorldCorners(corners); float y = ((Transform)val).InverseTransformPoint(corners[0]).y; Rect rect = val.rect; return y - ((Rect)(ref rect)).yMax; } } return 0f; } } internal static class RiskOfOptionsCompat { public const string GUID = "com.rune580.riskofoptions"; private const string IconResource = "SaleStarReminder.icon.png"; public static bool Enabled => Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"); [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void Register(PluginConfig settings) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0034: 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_0044: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_00ab: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00b6: 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_00c6: 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_00ec: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_00f7: 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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Expected O, but got Unknown //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Expected O, but got Unknown //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Expected O, but got Unknown //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Expected O, but got Unknown //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Expected O, but got Unknown ModSettingsManager.SetModDescription("Reminds you in large red text while you hold an unused Sale Star."); Sprite val = LoadIcon(); if (Object.op_Implicit((Object)(object)val)) { ModSettingsManager.SetModIcon(val); } ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(settings.ShowReminder)); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(settings.ReminderFontSize, new StepSliderConfig { min = 20f, max = 160f, increment = 1f, FormatString = "{0:0}" })); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(settings.SubheaderFontSize, new StepSliderConfig { min = 10f, max = 80f, increment = 1f, FormatString = "{0:0}" })); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(settings.ReminderOffsetY, new StepSliderConfig { min = -50f, max = 300f, increment = 1f, FormatString = "{0:0}px" })); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(settings.NearChestScale, new StepSliderConfig { min = 1f, max = 2f, increment = 0.05f, FormatString = "{0:0.00}x" })); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(settings.PulseNearChest)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(settings.ShowMostValuableChest)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(settings.MockSmallChest)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(settings.MockIncludeVulgar)); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(settings.MockDurationSeconds, new StepSliderConfig { min = 1f, max = 15f, increment = 0.5f, FormatString = "{0:0.0}s" })); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(settings.DebugLogging)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(settings.DebugAlwaysShow)); } private static Sprite LoadIcon() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) using Stream stream = typeof(RiskOfOptionsCompat).Assembly.GetManifestResourceStream("SaleStarReminder.icon.png"); if (stream == null) { return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, memoryStream.ToArray())) { return null; } return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } } internal sealed class SaleStarReminderController : MonoBehaviour { private const float UsedChestGrace = 1.5f; private readonly ChestScanner scanner = new ChestScanner(); private HUD hud; private ReminderBanner banner; private CharacterBody driverBody; private InteractionDriver driver; private GameObject aimedObject; private PurchaseInteraction aimedChest; private PurchaseInteraction lastAimedChest; private float lastAimedTime = float.NegativeInfinity; private Inventory trackedInventory; private int lastStars; private int lastConsumed; private float mockUntil = float.NegativeInfinity; private string mockLine; private string mockSubline; private PurchaseInteraction describedBest; private string bestSubline; private void Awake() { hud = ((Component)this).GetComponent<HUD>(); } private void Update() { if (!Object.op_Implicit((Object)(object)banner)) { if (!Object.op_Implicit((Object)(object)hud.mainContainer)) { return; } banner = ReminderBanner.Create(hud); } PluginConfig settings = SaleStarReminderPlugin.Settings; LocalUser localUserViewer = hud.localUserViewer; CharacterMaster val = ((localUserViewer != null) ? localUserViewer.cachedMaster : null); Inventory val2 = (Object.op_Implicit((Object)(object)val) ? val.inventory : null); CharacterBody val3 = ((localUserViewer != null) ? localUserViewer.cachedBody : null); scanner.Refresh(val2, val3); TrackAimedChest(val3); DetectStarUse(val2, settings); if (Time.time < mockUntil) { banner.ShowMock(mockLine, mockSubline); return; } bool flag = Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val2) && val2.GetItemCountEffective(Items.LowerPricedChests) > 0; if (settings.ShowReminder.Value && ((flag && scanner.AnyUsable) || settings.DebugAlwaysShow.Value)) { banner.ShowReminder(settings.ShowMostValuableChest.Value ? DescribeBest(scanner.Best) : null, flag && IsAboutToWasteStar()); } else { banner.Hide(); } } private bool IsAboutToWasteStar() { if (!IsGameCirclingChest() || !Object.op_Implicit((Object)(object)aimedChest)) { return false; } PurchaseInteraction best = scanner.Best; if (!Object.op_Implicit((Object)(object)best)) { return false; } ChestTier chestTier = ChestTiers.Get(best); if (chestTier >= ChestTier.Large) { return ChestTiers.Get(aimedChest) < chestTier; } return false; } private bool IsGameCirclingChest() { if (Object.op_Implicit((Object)(object)driver)) { return Object.op_Implicit((Object)(object)driver.saleStarEffect); } return false; } private string DescribeBest(PurchaseInteraction best) { if ((Object)(object)best != (Object)(object)describedBest) { describedBest = best; bestSubline = (Object.op_Implicit((Object)(object)best) ? DescribeChestOnStage(ChestScanner.GetDisplayName(best)) : null); } return bestSubline; } private static string DescribeChestOnStage(string name) { return "There is " + EnglishArticle.For(name) + " " + name + " on this stage"; } private void TrackAimedChest(CharacterBody body) { if ((Object)(object)body != (Object)(object)driverBody) { driverBody = body; driver = (Object.op_Implicit((Object)(object)body) ? ((Component)body).GetComponent<InteractionDriver>() : null); } GameObject val = (Object.op_Implicit((Object)(object)driver) ? driver.currentInteractable : null); if ((Object)(object)val != (Object)(object)aimedObject) { aimedObject = val; PurchaseInteraction val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<PurchaseInteraction>() : null); aimedChest = ((Object.op_Implicit((Object)(object)val2) && val2.saleStarCompatible) ? val2 : null); } if (Object.op_Implicit((Object)(object)aimedChest)) { lastAimedChest = aimedChest; lastAimedTime = Time.time; } } private void DetectStarUse(Inventory inventory, PluginConfig settings) { int num = (Object.op_Implicit((Object)(object)inventory) ? inventory.GetItemCountTotal(Items.LowerPricedChests) : 0); int num2 = (Object.op_Implicit((Object)(object)inventory) ? inventory.GetItemCountTotal(Items.LowerPricedChestsConsumed) : 0); bool num3 = (Object)(object)inventory == (Object)(object)trackedInventory && Object.op_Implicit((Object)(object)inventory) && num < lastStars && num2 > lastConsumed; trackedInventory = inventory; lastStars = num; lastConsumed = num2; if (num3) { OnStarUsed(settings); } } private void OnStarUsed(PluginConfig settings) { PurchaseInteraction val = ((Object.op_Implicit((Object)(object)lastAimedChest) && Time.time - lastAimedTime <= 1.5f) ? lastAimedChest : null); if (!Object.op_Implicit((Object)(object)val)) { if (settings.DebugLogging.Value) { SaleStarReminderPlugin.Log.LogInfo((object)"Sale Star spent, but no recently aimed-at chest to blame."); } return; } ChestTier chestTier = ChestTiers.Get(val); PurchaseInteraction bestExcluding = scanner.GetBestExcluding(val); ChestTier chestTier2 = (Object.op_Implicit((Object)(object)bestExcluding) ? ChestTiers.Get(bestExcluding) : ChestTier.Unknown); if (settings.DebugLogging.Value) { SaleStarReminderPlugin.Log.LogInfo((object)($"Sale Star spent on {((Object)((Component)val).gameObject).name} ({val.displayNameToken}, tier {chestTier}); best other" + string.Format(" chest: {0} (tier {1}).", Object.op_Implicit((Object)(object)bestExcluding) ? bestExcluding.displayNameToken : "none", chestTier2))); } if (settings.MockSmallChest.Value && ChestTiers.IsMockable(chestTier) && chestTier2 >= ChestTier.Large) { bool value = settings.MockIncludeVulgar.Value; string text = MockLines.PickSmallChest(value); if (text != null) { string text2 = (settings.ShowMostValuableChest.Value ? MockLines.PickBetterChest(value, ChestScanner.GetDisplayName(bestExcluding)) : null); mockLine = text; mockSubline = text2; mockUntil = Time.time + settings.MockDurationSeconds.Value; } } } } [BepInPlugin("sevenstack.SaleStarReminder", "SaleStarReminder", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SaleStarReminderPlugin : BaseUnityPlugin { public const string PluginGUID = "sevenstack.SaleStarReminder"; public const string PluginName = "SaleStarReminder"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; internal static PluginConfig Settings; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; Settings = new PluginConfig(((BaseUnityPlugin)this).Config); MockLines.Load(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location)); if (RiskOfOptionsCompat.Enabled) { RiskOfOptionsCompat.Register(Settings); } HUD.onHudTargetChangedGlobal += OnHudTargetChanged; } private void OnDestroy() { HUD.onHudTargetChangedGlobal -= OnHudTargetChanged; } private void Update() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (Settings.DebugLogging.Value) { KeyboardShortcut value = Settings.DumpChestsKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); CharacterMaster val = ((firstLocalUser != null) ? firstLocalUser.cachedMaster : null); ChestScanner.DumpAll(Object.op_Implicit((Object)(object)val) ? val.inventory : null, (firstLocalUser != null) ? firstLocalUser.cachedBody : null); } } } private static void OnHudTargetChanged(HUD hud) { if (Object.op_Implicit((Object)(object)hud) && !Object.op_Implicit((Object)(object)((Component)hud).GetComponent<SaleStarReminderController>())) { ((Component)hud).gameObject.AddComponent<SaleStarReminderController>(); } } } internal static class PluginVersionInfo { public const string Version = "1.0.0"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }