Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of Upgradeable Mix Station Mod v2.0.1
Mods/UpgradeableMixStationMod.dll
Decompiled a month agousing System; using System.Collections; 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 HarmonyLib; using MelonLoader; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using ScheduleOne; using ScheduleOne.Core.Items.Framework; using ScheduleOne.DevUtilities; using ScheduleOne.Dialogue; using ScheduleOne.Economy; using ScheduleOne.Effects; using ScheduleOne.EntityFramework; using ScheduleOne.GameTime; using ScheduleOne.ItemFramework; using ScheduleOne.Map; using ScheduleOne.Money; using ScheduleOne.NPCs; using ScheduleOne.ObjectScripts; using ScheduleOne.Persistence; using ScheduleOne.PlayerScripts; using ScheduleOne.Product; using ScheduleOne.Storage; using ScheduleOne.UI.Shop; using ScheduleOne.UI.Stations; using TMPro; using UnityEngine; using UnityEngine.AI; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; using UpgradeableMixStationMod; using UpgradeableMixStationMod.Data; using UpgradeableMixStationMod.Items; using UpgradeableMixStationMod.Shop; using UpgradeableMixStationMod.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Mod), "UpgradeableMixStationMod", "2.0.0", "Dom", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("UpgradeableMixStationMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("UpgradeableMixStationMod")] [assembly: AssemblyTitle("UpgradeableMixStationMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace MyMod.Helpers { public static class MelonLoggerExtensions { public static void Debug(this Instance logger, string message, bool stacktrace = true) { MelonDebug.Msg(stacktrace ? ("[" + GetCallerInfo() + "] " + message) : message); } private static string GetCallerInfo() { StackTrace stackTrace = new StackTrace(); for (int i = 2; i < stackTrace.FrameCount; i++) { StackFrame frame = stackTrace.GetFrame(i); MethodBase method = frame.GetMethod(); if (!(method?.DeclaringType == null)) { return method.DeclaringType.FullName + "." + method.Name; } } return "unknown"; } } } namespace UpgradeableMixStationMod { public class Mod : MelonMod { private bool _injected; public static Mod Instance { get; private set; } public static UpgradeManager Upgrades { get; private set; } public override void OnInitializeMelon() { Instance = this; Upgrades = new UpgradeManager(); ((MelonBase)this).LoggerInstance.Msg("UpgradeableMixStationMod loaded."); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (sceneName == "Main" || sceneName == "Tutorial") { _injected = false; HookSaveSystem(); } } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { if (_injected || (sceneName != "Main" && sceneName != "Tutorial")) { return; } try { UpgradeParts.Register(); MelonCoroutines.Start(DelayedVendorSpawn()); MelonCoroutines.Start(InitSpawnerDelayed()); _injected = true; } catch (Exception arg) { ((MelonBase)this).LoggerInstance.Error($"Injection failed: {arg}"); } } private IEnumerator InitSpawnerDelayed() { yield return (object)new WaitForSeconds(4f); PartSpawner.Initialize(); } public override void OnUpdate() { } private void HookSaveSystem() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown try { LoadManager instance = Singleton<LoadManager>.Instance; if ((Object)(object)instance != (Object)null) { instance.onLoadComplete.AddListener(new UnityAction(OnGameLoaded)); } SaveManager instance2 = Singleton<SaveManager>.Instance; if ((Object)(object)instance2 != (Object)null) { instance2.onSaveStart.AddListener(new UnityAction(OnGameSaving)); } } catch { ((MelonBase)this).LoggerInstance.Warning("Could not hook save system yet."); } } private void OnGameLoaded() { LoadManager instance = Singleton<LoadManager>.Instance; string text = ((instance != null) ? instance.LoadedGameFolderPath : null); if (!string.IsNullOrEmpty(text)) { Upgrades.Load(text); } } private void OnGameSaving() { LoadManager instance = Singleton<LoadManager>.Instance; string text = ((instance != null) ? instance.LoadedGameFolderPath : null); if (!string.IsNullOrEmpty(text)) { Upgrades.Save(text); } } public override void OnApplicationQuit() { try { LoadManager instance = Singleton<LoadManager>.Instance; string text = ((instance != null) ? instance.LoadedGameFolderPath : null); if (!string.IsNullOrEmpty(text)) { Upgrades?.Save(text); } } catch { } } private IEnumerator DelayedVendorSpawn() { while (NPCManager.NPCRegistry.Count == 0) { yield return (object)new WaitForSeconds(1f); } yield return (object)new WaitForSeconds(2f); yield return PartsVendor.SpawnVendor(); } } } namespace UpgradeableMixStationMod.UI { public class PanelDragger : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler { public RectTransform Target; private Vector2 _dragOffset; public void OnBeginDrag(PointerEventData eventData) { //IL_0012: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) Transform parent = ((Transform)Target).parent; Vector2 val = default(Vector2); RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)(object)((parent is RectTransform) ? parent : null), eventData.position, eventData.pressEventCamera, ref val); _dragOffset = Vector2.op_Implicit(((Transform)Target).localPosition) - val; } public void OnDrag(PointerEventData eventData) { //IL_0012: 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_002d: 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_0037: Unknown result type (might be due to invalid IL or missing references) Transform parent = ((Transform)Target).parent; Vector2 val = default(Vector2); RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)(object)((parent is RectTransform) ? parent : null), eventData.position, eventData.pressEventCamera, ref val); ((Transform)Target).localPosition = Vector2.op_Implicit(val + _dragOffset); } public void OnEndDrag(PointerEventData eventData) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) UpgradePanel.SavePosition(Target.anchoredPosition); } } public static class UpgradePanel { private static GameObject _panelRoot; private static RectTransform _panelRect; private static TextMeshProUGUI _speedCurrentLabel; private static TextMeshProUGUI _speedNextLabel; private static TextMeshProUGUI _speedReqLabel; private static Button _speedButton; private static TextMeshProUGUI _speedButtonText; private static TextMeshProUGUI _qualityCurrentLabel; private static TextMeshProUGUI _qualityNextLabel; private static TextMeshProUGUI _qualityReqLabel; private static Button _qualityButton; private static TextMeshProUGUI _qualityButtonText; private static TextMeshProUGUI _statusLabel; private static MixingStationMk2 _currentStation; private static TMP_FontAsset _cachedFont; private static Sprite _roundedSprite; private static string PositionPath => Path.Combine(MelonEnvironment.UserDataDirectory, "UpgradeableMixStationMod_UIPos.txt"); public static void Show(MixingStationCanvas canvas, MixingStationMk2 station) { _currentStation = station; if ((Object)(object)_cachedFont == (Object)null) { TextMeshProUGUI instructionLabel = canvas.InstructionLabel; _cachedFont = ((instructionLabel != null) ? ((TMP_Text)instructionLabel).font : null); } if ((Object)(object)_roundedSprite == (Object)null) { _roundedSprite = CreateRoundedSprite(12, 64); } if ((Object)(object)_panelRoot == (Object)null) { BuildPanel(((Component)canvas.Canvas).transform); } if ((Object)(object)_panelRoot.transform.parent != (Object)(object)((Component)canvas.Canvas).transform) { _panelRoot.transform.SetParent(((Component)canvas.Canvas).transform, false); } _panelRoot.SetActive(true); RefreshUI(); } public static void Hide() { if ((Object)(object)_panelRoot != (Object)null) { _panelRoot.SetActive(false); } _currentStation = null; } public static void SavePosition(Vector2 pos) { //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) try { File.WriteAllText(PositionPath, $"{pos.x},{pos.y}"); } catch { } } private static Vector2 LoadPosition() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) try { if (!File.Exists(PositionPath)) { return new Vector2(-20f, -10f); } string[] array = File.ReadAllText(PositionPath).Split(','); return new Vector2(float.Parse(array[0]), float.Parse(array[1])); } catch { return new Vector2(-20f, -10f); } } private static void BuildPanel(Transform canvasParent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0040: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) _panelRoot = new GameObject("MixUpgradePanel"); _panelRoot.transform.SetParent(canvasParent, false); _panelRect = _panelRoot.AddComponent<RectTransform>(); _panelRect.anchorMin = new Vector2(1f, 1f); _panelRect.anchorMax = new Vector2(1f, 1f); _panelRect.pivot = new Vector2(1f, 1f); _panelRect.anchoredPosition = LoadPosition(); _panelRect.sizeDelta = new Vector2(280f, 0f); Image val = _panelRoot.AddComponent<Image>(); val.sprite = _roundedSprite; val.type = (Type)1; ((Graphic)val).color = new Color(0.08f, 0.08f, 0.12f, 0.92f); PanelDragger panelDragger = _panelRoot.AddComponent<PanelDragger>(); panelDragger.Target = _panelRect; VerticalLayoutGroup val2 = _panelRoot.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)val2).padding = new RectOffset(16, 16, 16, 16); ((HorizontalOrVerticalLayoutGroup)val2).spacing = 8f; ((LayoutGroup)val2).childAlignment = (TextAnchor)1; ((HorizontalOrVerticalLayoutGroup)val2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)val2).childForceExpandHeight = false; ContentSizeFitter val3 = _panelRoot.AddComponent<ContentSizeFitter>(); val3.verticalFit = (FitMode)2; TextMeshProUGUI label = CreateLabel(_panelRoot.transform, "UPGRADES", 18f, (FontStyles)1); SetPreferredHeight(label, 28f); CreateDivider(_panelRoot.transform); CreateLabel(_panelRoot.transform, "SPEED", 14f, (FontStyles)1, (Color?)new Color(0.4f, 0.8f, 1f)); _speedCurrentLabel = CreateLabel(_panelRoot.transform, "", 12f, (FontStyles)0); _speedNextLabel = CreateLabel(_panelRoot.transform, "", 11f, (FontStyles)2, (Color?)new Color(0.7f, 0.7f, 0.7f)); _speedReqLabel = CreateLabel(_panelRoot.transform, "", 10f, (FontStyles)0); ((TMP_Text)_speedReqLabel).richText = true; _speedButton = CreateRoundedButton(_panelRoot.transform, "Upgrade", OnSpeedClicked, out _speedButtonText); CreateDivider(_panelRoot.transform); CreateLabel(_panelRoot.transform, "QUALITY FLOOR", 14f, (FontStyles)1, (Color?)new Color(1f, 0.8f, 0.3f)); _qualityCurrentLabel = CreateLabel(_panelRoot.transform, "", 12f, (FontStyles)0); _qualityNextLabel = CreateLabel(_panelRoot.transform, "", 11f, (FontStyles)2, (Color?)new Color(0.7f, 0.7f, 0.7f)); _qualityReqLabel = CreateLabel(_panelRoot.transform, "", 10f, (FontStyles)0); ((TMP_Text)_qualityReqLabel).richText = true; _qualityButton = CreateRoundedButton(_panelRoot.transform, "Upgrade", OnQualityClicked, out _qualityButtonText); CreateDivider(_panelRoot.transform); _statusLabel = CreateLabel(_panelRoot.transform, "", 11f, (FontStyles)2, (Color?)new Color(0.9f, 0.5f, 0.5f)); SetPreferredHeight(_statusLabel, 20f); } private static void RefreshUI() { if (!((Object)(object)_currentStation == (Object)null)) { StationUpgradeData data = Mod.Upgrades.GetData(((BuildableItem)_currentStation).GUID); ((TMP_Text)_speedCurrentLabel).text = "Current: " + data.CurrentSpeedName; if (data.CanUpgradeSpeed) { UpgradeTier nextSpeedTier = data.NextSpeedTier; ((TMP_Text)_speedNextLabel).text = "Next: " + nextSpeedTier.Name + " — " + nextSpeedTier.Description; ((TMP_Text)_speedReqLabel).text = BuildRequirementsText(nextSpeedTier); ((Component)_speedReqLabel).gameObject.SetActive(true); ((TMP_Text)_speedButtonText).text = "Upgrade (" + MoneyManager.FormatAmount(nextSpeedTier.Cost, false, false) + ")"; ((Component)_speedButton).gameObject.SetActive(true); ((Selectable)_speedButton).interactable = Mod.Upgrades.HasRequiredItems(nextSpeedTier); } else { ((TMP_Text)_speedNextLabel).text = "MAX LEVEL"; ((Component)_speedReqLabel).gameObject.SetActive(false); ((Component)_speedButton).gameObject.SetActive(false); } ((TMP_Text)_qualityCurrentLabel).text = "Current: " + data.CurrentQualityName; if (data.CanUpgradeQuality) { UpgradeTier nextQualityTier = data.NextQualityTier; ((TMP_Text)_qualityNextLabel).text = "Next: " + nextQualityTier.Name + " — " + nextQualityTier.Description; ((TMP_Text)_qualityReqLabel).text = BuildRequirementsText(nextQualityTier); ((Component)_qualityReqLabel).gameObject.SetActive(true); ((TMP_Text)_qualityButtonText).text = "Upgrade (" + MoneyManager.FormatAmount(nextQualityTier.Cost, false, false) + ")"; ((Component)_qualityButton).gameObject.SetActive(true); ((Selectable)_qualityButton).interactable = Mod.Upgrades.HasRequiredItems(nextQualityTier); } else { ((TMP_Text)_qualityNextLabel).text = "MAX LEVEL"; ((Component)_qualityReqLabel).gameObject.SetActive(false); ((Component)_qualityButton).gameObject.SetActive(false); } ((TMP_Text)_statusLabel).text = ""; } } private static string BuildRequirementsText(UpgradeTier tier) { if (tier.Items == null || tier.Items.Count == 0) { return ""; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Requires: "); for (int i = 0; i < tier.Items.Count; i++) { ItemRequirement itemRequirement = tier.Items[i]; int playerItemCount = Mod.Upgrades.GetPlayerItemCount(itemRequirement.ItemID); string text = ((playerItemCount >= itemRequirement.Amount) ? "#66FF66" : "#FF6666"); if (i > 0) { stringBuilder.Append(", "); } stringBuilder.Append($"<color={text}>{itemRequirement.Amount}x {itemRequirement.DisplayName} ({playerItemCount})</color>"); } return stringBuilder.ToString(); } private static void OnSpeedClicked() { //IL_007d: 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) if (!((Object)(object)_currentStation == (Object)null)) { if (Mod.Upgrades.TryUpgradeSpeed(((BuildableItem)_currentStation).GUID, out var failReason)) { ((Graphic)_statusLabel).color = new Color(0.4f, 1f, 0.4f); ((TMP_Text)_statusLabel).text = "Speed upgraded!"; RefreshUI(); } else { ((Graphic)_statusLabel).color = new Color(1f, 0.4f, 0.4f); ((TMP_Text)_statusLabel).text = failReason; } } } private static void OnQualityClicked() { //IL_007d: 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) if (!((Object)(object)_currentStation == (Object)null)) { if (Mod.Upgrades.TryUpgradeQuality(((BuildableItem)_currentStation).GUID, out var failReason)) { ((Graphic)_statusLabel).color = new Color(0.4f, 1f, 0.4f); ((TMP_Text)_statusLabel).text = "Quality floor upgraded!"; RefreshUI(); } else { ((Graphic)_statusLabel).color = new Color(1f, 0.4f, 0.4f); ((TMP_Text)_statusLabel).text = failReason; } } } private static Sprite CreateRoundedSprite(int radius, int size) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false); Color32[] array = (Color32[])(object)new Color32[size * size]; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num = 0f; float num2 = 0f; if (j < radius) { num = radius - j; } else if (j > size - 1 - radius) { num = j - (size - 1 - radius); } if (i < radius) { num2 = radius - i; } else if (i > size - 1 - radius) { num2 = i - (size - 1 - radius); } float num3 = Mathf.Sqrt(num * num + num2 * num2); byte b = (byte)((num3 <= (float)(radius - 1)) ? 255u : ((uint)((num3 <= (float)radius) ? ((byte)(255f * ((float)radius - num3))) : 0))); array[i * size + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b); } } val.SetPixels32(array); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)radius, (float)radius, (float)radius, (float)radius)); } private static TextMeshProUGUI CreateLabel(Transform parent, string text, float fontSize, FontStyles style = 0, Color? color = null) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0032: 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_0046: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Label"); val.transform.SetParent(parent, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val2).text = text; ((TMP_Text)val2).fontSize = fontSize; ((TMP_Text)val2).fontStyle = style; ((Graphic)val2).color = (Color)(((??)color) ?? Color.white); ((TMP_Text)val2).alignment = (TextAlignmentOptions)513; ((TMP_Text)val2).enableWordWrapping = true; ((TMP_Text)val2).overflowMode = (TextOverflowModes)3; if ((Object)(object)_cachedFont != (Object)null) { ((TMP_Text)val2).font = _cachedFont; } LayoutElement val3 = val.AddComponent<LayoutElement>(); val3.preferredHeight = fontSize + 6f; return val2; } private static void SetPreferredHeight(TextMeshProUGUI label, float height) { LayoutElement component = ((Component)label).GetComponent<LayoutElement>(); if ((Object)(object)component != (Object)null) { component.preferredHeight = height; } } private static Button CreateRoundedButton(Transform parent, string text, Action onClick, out TextMeshProUGUI buttonLabel) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Button"); val.transform.SetParent(parent, false); val.AddComponent<LayoutElement>().preferredHeight = 34f; Image val2 = val.AddComponent<Image>(); val2.sprite = _roundedSprite; val2.type = (Type)1; ((Graphic)val2).color = new Color(0.2f, 0.5f, 0.3f, 1f); Button val3 = val.AddComponent<Button>(); ColorBlock colors = ((Selectable)val3).colors; ((ColorBlock)(ref colors)).normalColor = new Color(0.2f, 0.5f, 0.3f); ((ColorBlock)(ref colors)).highlightedColor = new Color(0.25f, 0.65f, 0.35f); ((ColorBlock)(ref colors)).pressedColor = new Color(0.15f, 0.4f, 0.2f); ((ColorBlock)(ref colors)).disabledColor = new Color(0.2f, 0.2f, 0.2f); ((Selectable)val3).colors = colors; ((UnityEvent)val3.onClick).AddListener((UnityAction)delegate { onClick?.Invoke(); }); GameObject val4 = new GameObject("Text"); val4.transform.SetParent(val.transform, false); RectTransform val5 = val4.AddComponent<RectTransform>(); val5.anchorMin = Vector2.zero; val5.anchorMax = Vector2.one; val5.sizeDelta = Vector2.zero; val5.offsetMin = new Vector2(8f, 2f); val5.offsetMax = new Vector2(-8f, -2f); buttonLabel = val4.AddComponent<TextMeshProUGUI>(); ((TMP_Text)buttonLabel).text = text; ((TMP_Text)buttonLabel).fontSize = 13f; ((TMP_Text)buttonLabel).fontStyle = (FontStyles)1; ((Graphic)buttonLabel).color = Color.white; ((TMP_Text)buttonLabel).alignment = (TextAlignmentOptions)514; if ((Object)(object)_cachedFont != (Object)null) { ((TMP_Text)buttonLabel).font = _cachedFont; } return val3; } private static void CreateDivider(Transform parent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Divider"); val.transform.SetParent(parent, false); LayoutElement val2 = val.AddComponent<LayoutElement>(); val2.preferredHeight = 1f; val2.flexibleHeight = 0f; ((Graphic)val.AddComponent<Image>()).color = new Color(1f, 1f, 1f, 0.15f); } } } namespace UpgradeableMixStationMod.Shop { public static class PartsVendor { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Predicate<ShopInterface> <>9__11_0; public static Action <>9__14_3; public static UnityAction <>9__14_0; public static UnityAction <>9__14_1; public static UnityAction <>9__14_2; internal bool <SpawnVendor>b__11_0(ShopInterface s) { return s.ShopCode == "gas_mart_central"; } internal void <SetupDialogue>b__14_0() { SetSkipBehaviourEnd(); MelonCoroutines.Start(EndDialogueThen(delegate { OpenShop(); })); } internal void <SetupDialogue>b__14_3() { OpenShop(); } internal void <SetupDialogue>b__14_1() { <>c__DisplayClass14_0 CS$<>8__locals0 = new <>c__DisplayClass14_0(); SetSkipBehaviourEnd(); CS$<>8__locals0.response = GetHintResponse(); MelonCoroutines.Start(EndDialogueThen(delegate { ShowHintBubble(CS$<>8__locals0.response); })); } internal void <SetupDialogue>b__14_2() { SetSkipBehaviourEnd(); MelonCoroutines.Start(EndDialogueThen(null)); } } [CompilerGenerated] private sealed class <>c__DisplayClass14_0 { public string response; internal void <SetupDialogue>b__4() { ShowHintBubble(response); } } private static ShopInterface _shop; private static Canvas _shopCanvas; private static RectTransform _shopContainer; private static NPC _vendorNPC; private static Vector3 _spawnPos; private static Quaternion _spawnRot; private static bool _spawned; public static Vector3 VendorPosition = new Vector3(67.77f, 0f, 28.74f); public static Quaternion VendorRotation = Quaternion.Euler(0f, 90f, 0f); public static bool IsShopOpen => (Object)(object)_shopContainer != (Object)null && ((Component)_shopContainer).gameObject.activeInHierarchy; public static IEnumerator SpawnVendor() { if (_spawned) { yield break; } yield return (object)new WaitForSeconds(3f); ShopInterface sourceShop = ShopInterface.AllShops.Find((ShopInterface s) => s.ShopCode == "gas_mart_central"); if ((Object)(object)sourceShop == (Object)null) { MelonLogger.Warning("[Shop] Could not find source shop to clone."); yield break; } GameObject shopGO = Object.Instantiate<GameObject>(((Component)sourceShop).gameObject); ((Object)shopGO).name = "UpgradePartsShop"; _shop = shopGO.GetComponent<ShopInterface>(); _shop.ShopName = "Mix Tech Parts"; _shop.ShopCode = "mix_tech_parts"; _shopCanvas = shopGO.GetComponentInChildren<Canvas>(true); _shopContainer = _shop.Container; if ((Object)(object)_shop.StoreNameLabel != (Object)null) { ((TMP_Text)_shop.StoreNameLabel).text = "Mix Tech Parts"; } FieldInfo screenField = typeof(ShopInterface).GetField("shopScreen", BindingFlags.Instance | BindingFlags.NonPublic); if (screenField != null) { Component screen = shopGO.GetComponentInChildren(screenField.FieldType, true); if ((Object)(object)screen != (Object)null) { screenField.SetValue(_shop, screen); } } Cart cart = shopGO.GetComponentInChildren<Cart>(true); if ((Object)(object)cart != (Object)null) { cart.Shop = _shop; } RectTransform listingContainer = _shop.ListingContainer; if ((Object)(object)listingContainer != (Object)null) { for (int i = ((Transform)listingContainer).childCount - 1; i >= 0; i--) { Object.Destroy((Object)(object)((Component)((Transform)listingContainer).GetChild(i)).gameObject); } } (typeof(ShopInterface).GetField("listingUI", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(_shop) as List<ListingUI>)?.Clear(); _shop.Listings.Clear(); yield return null; if ((Object)(object)UpgradeParts.MixingGear != (Object)null) { AddListing(_shop, UpgradeParts.MixingGear, 150f); } if ((Object)(object)UpgradeParts.PrecisionComponent != (Object)null) { AddListing(_shop, UpgradeParts.PrecisionComponent, 400f); } SpawnTable(); MelonCoroutines.Start(AddVendorMapPOI()); MelonCoroutines.Start(SpawnNPC()); try { TryRegisterDayPass(); } catch { } _spawned = true; } private static void TryRegisterDayPass() { try { TimeManager instance = NetworkSingleton<TimeManager>.Instance; if ((Object)(object)instance != (Object)null) { instance.onDayPass = (Action)Delegate.Combine(instance.onDayPass, new Action(OnDayPass)); } } catch (Exception ex) { MelonLogger.Warning("[Shop] Could not register TimeManager onDayPass: " + ex.Message); } } private static IEnumerator SpawnNPC() { _spawnPos = new Vector3(67.01f, 0.11f, 28.78f); _spawnRot = Quaternion.Euler(0f, 90f, 0f); NPC sourceNPC = null; foreach (NPC npc in NPCManager.NPCRegistry) { if ((Object)(object)npc == (Object)null || (Object)(object)npc.DialogueHandler == (Object)null || (Object)(object)((Component)npc).GetComponentInChildren<DialogueController>() == (Object)null) { continue; } sourceNPC = npc; break; } if ((Object)(object)sourceNPC == (Object)null) { MelonLogger.Error("[Shop] Checked NPCs, none suitable. Vendor NPC not spawned."); yield break; } GameObject npcGO = Object.Instantiate<GameObject>(((Component)sourceNPC).gameObject); ((Object)npcGO).name = "Nick"; _vendorNPC = npcGO.GetComponent<NPC>(); _vendorNPC.FirstName = "Nick"; _vendorNPC.hasLastName = false; _vendorNPC.LastName = ""; _vendorNPC.ID = "tech_dealer_nick"; _vendorNPC.BakedGUID = Guid.NewGuid().ToString(); _vendorNPC.CanBeSummoned = false; NavMeshAgent agent = npcGO.GetComponent<NavMeshAgent>(); if ((Object)(object)agent != (Object)null) { ((Behaviour)agent).enabled = false; } if ((Object)(object)_vendorNPC.Health != (Object)null) { _vendorNPC.Health.Invincible = true; } _vendorNPC.OverrideParent = true; _vendorNPC.OverriddenParent = null; MonoBehaviour[] componentsInChildren = npcGO.GetComponentsInChildren<MonoBehaviour>(); foreach (MonoBehaviour comp in componentsInChildren) { string typeName = ((object)comp).GetType().Name; if ((typeName.Contains("Schedule") || typeName.Contains("Behaviour") || typeName.Contains("Behavior")) && (Object)(object)comp != (Object)(object)_vendorNPC && !typeName.Contains("Dialogue")) { ((Behaviour)comp).enabled = false; } } SetupDialogue(npcGO); yield return null; yield return null; npcGO.transform.position = _spawnPos; npcGO.transform.rotation = _spawnRot; npcGO.SetActive(true); _vendorNPC.SetVisible(true, false); Renderer[] componentsInChildren2 = npcGO.GetComponentsInChildren<Renderer>(true); foreach (Renderer rend in componentsInChildren2) { if (rend is MeshRenderer && (Object)(object)((Component)rend).GetComponent<MeshFilter>() != (Object)null) { Mesh sharedMesh = ((Component)rend).GetComponent<MeshFilter>().sharedMesh; string meshName = ((sharedMesh != null) ? ((Object)sharedMesh).name : null) ?? ""; if (meshName.Contains("Capsule") || meshName.Contains("Sphere") || meshName.Contains("Cube") || meshName.Contains("Cylinder")) { rend.enabled = false; continue; } } rend.enabled = true; } if ((Object)(object)_vendorNPC.Movement != (Object)null) { _vendorNPC.Movement.Stop(); _vendorNPC.Movement.SetAgentEnabled(false); } yield return null; npcGO.transform.position = _spawnPos; npcGO.transform.rotation = _spawnRot; MelonCoroutines.Start(KeepInPlace()); } private static void SetupDialogue(GameObject npcGO) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_00e4: 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_00ef: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Expected O, but got Unknown DialogueController val = npcGO.GetComponent<DialogueController>() ?? npcGO.GetComponentInChildren<DialogueController>(); if ((Object)(object)val == (Object)null) { MelonLogger.Error("[Shop] No DialogueController found on cloned NPC — dialogue will not work."); return; } val.Choices.Clear(); val.GreetingOverrides.Clear(); val.UseDialogueBehaviour = false; DialogueHandler val2 = npcGO.GetComponent<DialogueHandler>() ?? npcGO.GetComponentInChildren<DialogueHandler>(); if ((Object)(object)val2 != (Object)null) { val2.DialogueEvents = (DialogueEvent[])(object)new DialogueEvent[0]; } GreetingOverride val3 = new GreetingOverride(); val3.Greeting = "What do you need?"; val3.ShouldShow = true; val3.PlayVO = false; val.AddGreetingOverride(val3); DialogueChoice val4 = new DialogueChoice(); val4.Enabled = true; val4.ChoiceText = "I want to buy something."; val4.ShowWorldspaceDialogue = true; val4.onChoosen = new UnityEvent(); UnityEvent onChoosen = val4.onChoosen; object obj = <>c.<>9__14_0; if (obj == null) { UnityAction val5 = delegate { SetSkipBehaviourEnd(); MelonCoroutines.Start(EndDialogueThen(delegate { OpenShop(); })); }; <>c.<>9__14_0 = val5; obj = (object)val5; } onChoosen.AddListener((UnityAction)obj); val.AddDialogueChoice(val4, 10); DialogueChoice val6 = new DialogueChoice(); val6.Enabled = true; val6.ChoiceText = "Where can I find a Prototype Core?"; val6.ShowWorldspaceDialogue = true; val6.onChoosen = new UnityEvent(); UnityEvent onChoosen2 = val6.onChoosen; object obj2 = <>c.<>9__14_1; if (obj2 == null) { UnityAction val7 = delegate { SetSkipBehaviourEnd(); string response = GetHintResponse(); MelonCoroutines.Start(EndDialogueThen(delegate { ShowHintBubble(response); })); }; <>c.<>9__14_1 = val7; obj2 = (object)val7; } onChoosen2.AddListener((UnityAction)obj2); val.AddDialogueChoice(val6, 5); DialogueChoice val8 = new DialogueChoice(); val8.Enabled = true; val8.ChoiceText = "Nothing."; val8.ShowWorldspaceDialogue = true; val8.onChoosen = new UnityEvent(); UnityEvent onChoosen3 = val8.onChoosen; object obj3 = <>c.<>9__14_2; if (obj3 == null) { UnityAction val9 = delegate { SetSkipBehaviourEnd(); MelonCoroutines.Start(EndDialogueThen(null)); }; <>c.<>9__14_2 = val9; obj3 = (object)val9; } onChoosen3.AddListener((UnityAction)obj3); val.AddDialogueChoice(val8, 1); } private static IEnumerator EndDialogueThen(Action callback) { yield return null; yield return null; callback?.Invoke(); } private static void SetSkipBehaviourEnd() { try { DialogueHandler val = _vendorNPC?.DialogueHandler; if (!((Object)(object)val == (Object)null)) { FieldInfo field = typeof(DialogueHandler).GetField("skipNextDialogueBehaviourEnd", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { field.SetValue(val, true); } } } catch { } } private static void ShowHintBubble(string text) { try { NPC vendorNPC = _vendorNPC; if (vendorNPC != null) { DialogueHandler dialogueHandler = vendorNPC.DialogueHandler; if (dialogueHandler != null) { dialogueHandler.ShowWorldspaceDialogue(text, 6f); } } } catch { } } private static string GetHintResponse() { if (PartSpawner.TrackedDrops.Count == 0) { return "No Prototype Cores out there today. Check back tomorrow."; } if (PartSpawner.HasGivenHintToday) { return "I already told you what I know today. Come back tomorrow."; } DeadDrop hintDrop = PartSpawner.GetHintDrop(); if ((Object)(object)hintDrop == (Object)null) { return "I don't have any leads right now."; } string text = ((!string.IsNullOrEmpty(hintDrop.DeadDropName)) ? hintDrop.DeadDropName : "an unknown location"); PartSpawner.MarkHintGiven(); return "I heard there's a Prototype Core at the dead drop near \"" + text + "\". That's all I know for today."; } private static IEnumerator KeepInPlace() { while ((Object)(object)_vendorNPC != (Object)null) { if ((Object)(object)_vendorNPC.Movement != (Object)null && _vendorNPC.Movement.IsMoving) { _vendorNPC.Movement.Stop(); _vendorNPC.Movement.SetAgentEnabled(false); } if (Vector3.Distance(((Component)_vendorNPC).transform.position, _spawnPos) > 0.3f) { ((Component)_vendorNPC).transform.position = _spawnPos; ((Component)_vendorNPC).transform.rotation = _spawnRot; } yield return (object)new WaitForSeconds(0.5f); } } private static void OnDayPass() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_vendorNPC == (Object)null) { return; } try { if ((Object)(object)_vendorNPC.Health != (Object)null && (_vendorNPC.Health.IsDead || _vendorNPC.Health.IsKnockedOut)) { Object.Destroy((Object)(object)((Component)_vendorNPC).gameObject); MelonCoroutines.Start(SpawnNPC()); return; } ((Component)_vendorNPC).gameObject.SetActive(true); _vendorNPC.SetVisible(true, false); ((Component)_vendorNPC).transform.position = _spawnPos; ((Component)_vendorNPC).transform.rotation = _spawnRot; if ((Object)(object)_vendorNPC.Movement != (Object)null) { _vendorNPC.Movement.Stop(); _vendorNPC.Movement.SetAgentEnabled(false); } } catch (Exception ex) { MelonLogger.Warning("[Shop] Respawn failed: " + ex.Message); } } private static void OpenShop() { if (!((Object)(object)_shop == (Object)null)) { _shop.SetIsOpen(true); if ((Object)(object)_shopCanvas != (Object)null) { ((Behaviour)_shopCanvas).enabled = true; } if ((Object)(object)_shopContainer != (Object)null) { ((Component)_shopContainer).gameObject.SetActive(true); } MelonCoroutines.Start(WatchForShopClose()); } } private static void ForceCloseShop() { if (!((Object)(object)_shop == (Object)null)) { _shop.SetIsOpen(false); if ((Object)(object)_shopCanvas != (Object)null) { ((Behaviour)_shopCanvas).enabled = false; } if ((Object)(object)_shopContainer != (Object)null) { ((Component)_shopContainer).gameObject.SetActive(false); } ClearWorldspaceDialogue(); } } private static void ClearWorldspaceDialogue() { try { NPC vendorNPC = _vendorNPC; if (vendorNPC != null) { DialogueHandler dialogueHandler = vendorNPC.DialogueHandler; if (dialogueHandler != null) { dialogueHandler.ShowWorldspaceDialogue(" ", 0f); } } } catch { } } private static IEnumerator WatchForShopClose() { yield return (object)new WaitForSeconds(0.3f); while ((Object)(object)_shop != (Object)null && _shop.IsOpen) { PlayerMovement player = PlayerSingleton<PlayerMovement>.Instance; if ((Object)(object)player != (Object)null && Vector3.Distance(((Component)player).transform.position, VendorPosition) > 8f) { ForceCloseShop(); yield break; } yield return null; } if ((Object)(object)_shopCanvas != (Object)null) { ((Behaviour)_shopCanvas).enabled = false; } if ((Object)(object)_shopContainer != (Object)null) { ((Component)_shopContainer).gameObject.SetActive(false); } ClearWorldspaceDialogue(); } private static void SpawnTable() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0012: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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) //IL_0101: Expected O, but got Unknown //IL_0119: 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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Expected O, but got Unknown //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Expected O, but got Unknown GameObject val = new GameObject("VendorTable"); val.transform.position = VendorPosition; val.transform.rotation = VendorRotation; Shader val2 = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"); GameObject val3 = GameObject.CreatePrimitive((PrimitiveType)3); val3.transform.SetParent(val.transform, false); val3.transform.localPosition = new Vector3(0f, 0.75f, 0f); val3.transform.localScale = new Vector3(1.4f, 0.08f, 0.7f); val3.GetComponent<Renderer>().material = new Material(val2) { color = new Color(0.15f, 0.2f, 0.25f) }; val3.layer = LayerMask.NameToLayer("Default"); Material material = new Material(val2) { color = new Color(0.1f, 0.12f, 0.15f) }; Vector3[] array = (Vector3[])(object)new Vector3[4] { new Vector3(0.6f, 0.37f, 0.28f), new Vector3(-0.6f, 0.37f, 0.28f), new Vector3(0.6f, 0.37f, -0.28f), new Vector3(-0.6f, 0.37f, -0.28f) }; foreach (Vector3 localPosition in array) { GameObject val4 = GameObject.CreatePrimitive((PrimitiveType)3); val4.transform.SetParent(val.transform, false); val4.transform.localPosition = localPosition; val4.transform.localScale = new Vector3(0.06f, 0.7f, 0.06f); val4.GetComponent<Renderer>().material = material; val4.layer = LayerMask.NameToLayer("Default"); } GameObject val5 = GameObject.CreatePrimitive((PrimitiveType)2); val5.transform.SetParent(val.transform, false); val5.transform.localPosition = new Vector3(-0.3f, 0.85f, 0f); val5.transform.localScale = new Vector3(0.2f, 0.04f, 0.2f); val5.GetComponent<Renderer>().material = new Material(val2) { color = new Color(0.5f, 0.7f, 0.9f) }; Object.Destroy((Object)(object)val5.GetComponent<Collider>()); GameObject val6 = GameObject.CreatePrimitive((PrimitiveType)3); val6.transform.SetParent(val.transform, false); val6.transform.localPosition = new Vector3(0.3f, 0.84f, 0f); val6.transform.localScale = new Vector3(0.15f, 0.1f, 0.15f); val6.GetComponent<Renderer>().material = new Material(val2) { color = new Color(0.9f, 0.6f, 0.2f) }; Object.Destroy((Object)(object)val6.GetComponent<Collider>()); } private static void AddListing(ShopInterface shop, PropertyItemDefinition def, float price) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_003c: 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_004b: Expected O, but got Unknown if (!((Object)(object)def == (Object)null) && !((Object)(object)shop == (Object)null)) { ShopListing val = new ShopListing { name = ((BaseItemDefinition)def).Name, Item = (StorableItemDefinition)(object)def, LimitedStock = false, DefaultStock = -1, CanBeDelivered = false }; typeof(ShopListing).GetField("OverridePrice", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(val, true); typeof(ShopListing).GetField("OverriddenPrice", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(val, price); shop.Listings.Add(val); val.Initialize(shop); typeof(ShopInterface).GetMethod("CreateListingUI", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(shop, new object[1] { val }); } } public static Texture2D LoadCustomTexture(string fileName) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown try { string text = Path.Combine(MelonEnvironment.MelonBaseDirectory, "Mods", "UpgradeableMixStationMod", "Icons", fileName); if (!File.Exists(text)) { MelonLogger.Warning("[Shop] Map icon not found at: " + text); return null; } byte[] array = File.ReadAllBytes(text); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ((Texture)val).filterMode = (FilterMode)1; ImageConversion.LoadImage(val, array); return val; } catch (Exception ex) { MelonLogger.Error("[Shop] Failed to load map icon: " + ex.Message); return null; } } private static IEnumerator AddVendorMapPOI() { yield return (object)new WaitForSeconds(1f); POI existingPOI = Object.FindObjectOfType<POI>(); if ((Object)(object)existingPOI == (Object)null) { MelonLogger.Warning("[Shop] Could not find an existing POI to clone for the map marker."); yield break; } GameObject poiAnchor = new GameObject("MixTechPartsPOI_Anchor"); poiAnchor.transform.position = VendorPosition; GameObject poiGO = Object.Instantiate<GameObject>(((Component)existingPOI).gameObject, poiAnchor.transform); ((Object)poiGO).name = "MixTechPartsPOI"; poiGO.transform.localPosition = new Vector3(0f, 2f, 0f); POI poi = poiGO.GetComponent<POI>(); poi.SetMainText("Mix Tech Parts"); poi.onUICreated.AddListener((UnityAction)delegate { MelonCoroutines.Start(SetPOIIcon(poi)); }); ((Behaviour)poi).enabled = true; poiGO.SetActive(true); } private static IEnumerator SetPOIIcon(POI poi) { yield return null; if ((Object)(object)poi.IconContainer == (Object)null) { MelonLogger.Warning("[Shop] POI IconContainer is null, cannot set custom icon."); yield break; } for (int i = ((Transform)poi.IconContainer).childCount - 1; i >= 0; i--) { Object.Destroy((Object)(object)((Component)((Transform)poi.IconContainer).GetChild(i)).gameObject); } yield return null; Texture2D tex = LoadCustomTexture("Supplier.png"); if (!((Object)(object)tex == (Object)null)) { GameObject iconGO = new GameObject("MixTechIcon"); iconGO.transform.SetParent((Transform)(object)poi.IconContainer, false); RectTransform rect = iconGO.AddComponent<RectTransform>(); rect.sizeDelta = new Vector2(25f, 25f); Image img = iconGO.AddComponent<Image>(); img.sprite = Sprite.Create(tex, new Rect(0f, 0f, (float)((Texture)tex).width, (float)((Texture)tex).height), new Vector2(0.5f, 0.5f)); ((Graphic)img).color = Color.white; img.preserveAspect = true; } } } } namespace UpgradeableMixStationMod.Patches { [HarmonyPatch(typeof(UIScreenManager), "get_IsBackTriggeredThisFrame")] public static class BlockPauseMenuForCustomShopPatch { public static void Postfix(ref bool __result) { if (PartsVendor.IsShopOpen) { __result = true; } } } [HarmonyPatch(typeof(MixingStationCanvas), "Open")] public static class CanvasOpenPatch { [HarmonyPostfix] public static void Postfix(MixingStationCanvas __instance, MixingStation station) { MixingStationMk2 val = (MixingStationMk2)(object)((station is MixingStationMk2) ? station : null); if (val != null) { UpgradePanel.Show(__instance, val); } } } [HarmonyPatch(typeof(MixingStationCanvas), "Close")] public static class CanvasClosePatch { [HarmonyPostfix] public static void Postfix() { UpgradePanel.Hide(); } } [HarmonyPatch(typeof(UIScreenManager), "Update")] public static class CleanupGhostScreensPatch { public static void Prefix(UIScreenManager __instance) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!__instance.IsAnyScreenActive()) { return; } UIScreen topScreen = __instance.TopScreen; if ((Object)(object)topScreen == (Object)null || !((Component)topScreen).gameObject.activeInHierarchy) { Stack<UIScreenInfo> value = Traverse.Create((object)__instance).Field("screenStack").GetValue<Stack<UIScreenInfo>>(); if (value != null && value.Count > 0) { value.Pop(); } } } } [HarmonyPatch(typeof(ListingUI), "Initialize")] public static class CustomShop_ListingUI_Patch { public static void Postfix(ListingUI __instance) { ListingUI obj = __instance; obj.onDropdownClicked = (Action)Delegate.Combine(obj.onDropdownClicked, (Action)delegate { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) Canvas shopCanvas = ((Component)__instance).GetComponentInParent<Canvas>(); if ((Object)(object)shopCanvas == (Object)null) { MelonLogger.Error("[Shop] Could not find parent Canvas!"); } else { ShopAmountSelector val = ((Component)shopCanvas).GetComponentInChildren<ShopAmountSelector>(true); if ((Object)(object)val == (Object)null) { ShopAmountSelector val2 = Object.FindObjectOfType<ShopAmountSelector>(true); if ((Object)(object)val2 != (Object)null) { val = Object.Instantiate<ShopAmountSelector>(val2, ((Component)shopCanvas).transform); ((Component)val).gameObject.SetActive(true); RectTransform component = ((Component)val).GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { ((Transform)component).localScale = Vector3.one; } } } if ((Object)(object)val != (Object)null) { if ((Object)(object)__instance.DropdownAnchor != (Object)null) { ((Component)val).transform.position = ((Transform)__instance.DropdownAnchor).position; RectTransform component2 = ((Component)val).GetComponent<RectTransform>(); if ((Object)(object)component2 != (Object)null) { Vector2 anchoredPosition = component2.anchoredPosition; Rect rect = component2.rect; component2.anchoredPosition = anchoredPosition + new Vector2(0f, 0f - ((Rect)(ref rect)).height); } } ((Component)val).transform.SetAsLastSibling(); val.Open(); ((UnityEventBase)val.onSubmitted).RemoveAllListeners(); val.onSubmitted.AddListener((UnityAction<int>)delegate(int amount) { try { Cart componentInChildren = ((Component)shopCanvas).GetComponentInChildren<Cart>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.AddItem(__instance.Listing, amount); } else { MelonLogger.Error("[Shop] FAILED: Could not find the Cart component in this shop's UI!"); } } catch (Exception ex) { MelonLogger.Error("[Shop] Error adding to cart: " + ex.Message); } }); } else { MelonLogger.Error("[Shop] FAILED: Could not find the base game's ShopAmountSelector to clone!"); } } }); } } [HarmonyPatch(typeof(MixingStationCanvas), "StartMixOperation")] public static class QualityPatch { [HarmonyPrefix] public static void Prefix(MixingStationCanvas __instance, MixOperation mixOperation) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) MixingStation mixingStation = __instance.MixingStation; MixingStationMk2 val = (MixingStationMk2)(object)((mixingStation is MixingStationMk2) ? mixingStation : null); if (val == null) { return; } StationUpgradeData data = Mod.Upgrades.GetData(((BuildableItem)val).GUID); if (data.QualityLevel > 0) { int qualityFloorValue = data.QualityFloorValue; if ((int)mixOperation.ProductQuality < qualityFloorValue) { mixOperation.ProductQuality = (EQuality)qualityFloorValue; } } } } [HarmonyPatch(typeof(ShopAmountSelector), "Open")] public static class ShopAmountSelectorOpenPatch { [HarmonyPostfix] public static void Postfix(ShopAmountSelector __instance) { MelonCoroutines.Start(ActivateNextFrame(__instance)); } private static IEnumerator ActivateNextFrame(ShopAmountSelector selector) { yield return null; if ((Object)(object)selector != (Object)null && selector.IsOpen && (Object)(object)selector.InputField != (Object)null) { selector.InputField.ActivateInputField(); } } } [HarmonyPatch(typeof(MixingStation), "GetMixTimeForCurrentOperation")] public static class SpeedPatch { [HarmonyPostfix] public static void Postfix(MixingStation __instance, ref int __result) { if (!(__instance is MixingStationMk2)) { return; } StationUpgradeData data = Mod.Upgrades.GetData(((BuildableItem)__instance).GUID); if (data.SpeedLevel > 0) { if (data.IsInstantSpeed) { __result = 1; } else { __result = Mathf.Max(1, Mathf.RoundToInt((float)__result * data.SpeedMultiplier)); } } } } } namespace UpgradeableMixStationMod.Items { public static class PartSpawner { private const int SpawnsPerDay = 3; private static readonly List<DeadDrop> _trackedDrops = new List<DeadDrop>(); private static bool _hooked; private static int _lastHintDay = -1; private static int _lastSpawnDay = -1; public static IReadOnlyList<DeadDrop> TrackedDrops => _trackedDrops; public static bool HasGivenHintToday => _lastHintDay == GetCurrentDay(); public static void MarkHintGiven() { _lastHintDay = GetCurrentDay(); } public static DeadDrop GetHintDrop() { if (_trackedDrops.Count == 0) { return null; } int index = GetCurrentDay() % _trackedDrops.Count; return _trackedDrops[index]; } private static int GetCurrentDay() { try { return NetworkSingleton<TimeManager>.Instance.ElapsedDays; } catch { return 0; } } public static void Initialize() { if (_hooked) { return; } try { TimeManager instance = NetworkSingleton<TimeManager>.Instance; if ((Object)(object)instance != (Object)null) { instance.onDayPass = (Action)Delegate.Combine(instance.onDayPass, new Action(OnNewDay)); instance.onSleepEnd = (Action)Delegate.Combine(instance.onSleepEnd, new Action(OnNewDay)); _hooked = true; OnNewDay(); } } catch (Exception arg) { Melon<Mod>.Logger.Error($"PartSpawner init failed: {arg}"); } } private static void OnNewDay() { int currentDay = GetCurrentDay(); if (currentDay != _lastSpawnDay) { _lastSpawnDay = currentDay; CleanupOldCores(); DistributeCores(); } } private static void CleanupOldCores() { foreach (DeadDrop trackedDrop in _trackedDrops) { if ((Object)(object)trackedDrop == (Object)null || (Object)(object)trackedDrop.Storage == (Object)null) { continue; } try { List<ItemSlot> itemSlots = ((StorageEntity)trackedDrop.Storage).ItemSlots; if (itemSlots == null) { continue; } foreach (ItemSlot item in itemSlots) { if (((item != null) ? item.ItemInstance : null) != null && ((BaseItemInstance)item.ItemInstance).ID.ToLower() == "prototypecore") { item.ClearStoredInstance(false); } } } catch (Exception ex) { Melon<Mod>.Logger.Warning("Cleanup failed for drop: " + ex.Message); } } _trackedDrops.Clear(); } private static void DistributeCores() { if ((Object)(object)UpgradeParts.PrototypeCore == (Object)null) { Melon<Mod>.Logger.Warning("PrototypeCore definition not registered yet."); return; } List<DeadDrop> list = DeadDrop.DeadDrops.Where((DeadDrop d) => (Object)(object)d != (Object)null && (Object)(object)d.Storage != (Object)null && ((StorageEntity)d.Storage).ItemCount == 0).ToList(); if (list.Count == 0) { return; } for (int num = list.Count - 1; num > 0; num--) { int index = Random.Range(0, num + 1); DeadDrop value = list[num]; list[num] = list[index]; list[index] = value; } int num2 = 0; int num3 = Mathf.Min(3, list.Count); for (int i = 0; i < num3; i++) { DeadDrop val = list[i]; try { List<ItemSlot> itemSlots = ((StorageEntity)val.Storage).ItemSlots; if (itemSlots != null) { ItemSlot val2 = ((IEnumerable<ItemSlot>)itemSlots).FirstOrDefault((Func<ItemSlot, bool>)((ItemSlot s) => s.ItemInstance == null)); if (val2 != null) { ItemInstance defaultInstance = ((ItemDefinition)UpgradeParts.PrototypeCore).GetDefaultInstance(1); val2.SetStoredItem(defaultInstance, false); _trackedDrops.Add(val); num2++; } } } catch (Exception ex) { Melon<Mod>.Logger.Warning("Failed to place core in dead drop: " + ex.Message); } } } } public static class UpgradeParts { private static bool _registered; private static readonly string IconFolder = Path.Combine(Directory.GetCurrentDirectory(), "Mods", "UpgradeableMixStationMod", "Icons"); public static PropertyItemDefinition MixingGear { get; private set; } public static PropertyItemDefinition PrecisionComponent { get; private set; } public static PropertyItemDefinition PrototypeCore { get; private set; } public static void Register() { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if (_registered) { return; } Registry instance = Singleton<Registry>.Instance; if ((Object)(object)instance == (Object)null) { Melon<Mod>.Logger.Error("Registry not found."); return; } PropertyItemDefinition item = Registry.GetItem<PropertyItemDefinition>("iodine"); if ((Object)(object)item == (Object)null) { Melon<Mod>.Logger.Error("Could not find iodine template."); return; } MixingGear = CreatePart(item, instance, "mixinggear", "Mixing Gear", "MixingGear.png", new Color(0.5f, 0.7f, 0.9f)); PrecisionComponent = CreatePart(item, instance, "precisioncomponent", "Precision Component", "PrecisionComponent.png", new Color(0.9f, 0.6f, 0.2f)); PrototypeCore = CreatePart(item, instance, "prototypecore", "Prototype Core", "PrototypeCore.png", new Color(0.8f, 0.2f, 1f)); _registered = true; } private static PropertyItemDefinition CreatePart(PropertyItemDefinition template, Registry registry, string id, string name, string iconFile, Color fallbackColor) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) PropertyItemDefinition val = Object.Instantiate<PropertyItemDefinition>(template); ((Object)val).name = id; ((BaseItemDefinition)val).Name = name; ((BaseItemDefinition)val).ID = id; val.Properties = new List<Effect>(); Sprite val2 = LoadIcon(iconFile); ((BaseItemDefinition)val).Icon = val2 ?? GenerateFallbackIcon(fallbackColor); registry.AddToRegistry((ItemDefinition)(object)val); return val; } private static Sprite LoadIcon(string fileName) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) try { string text = Path.Combine(IconFolder, fileName); if (!File.Exists(text)) { Melon<Mod>.Logger.Warning("Icon not found: " + text + " — using fallback color."); return null; } byte[] array = File.ReadAllBytes(text); Texture2D val = new Texture2D(2, 2); ImageConversion.LoadImage(val, array); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } catch (Exception ex) { Melon<Mod>.Logger.Warning("Icon load failed: " + ex.Message); return null; } } private static Sprite GenerateFallbackIcon(Color color) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00de: 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_00ee: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[4096]; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num = Mathf.Abs((float)j - 31.5f); float num2 = Mathf.Abs((float)i - 31.5f); float num3 = Mathf.Sqrt(Mathf.Max(0f, num - 24f) * Mathf.Max(0f, num - 24f) + Mathf.Max(0f, num2 - 24f) * Mathf.Max(0f, num2 - 24f)); float num4 = ((num3 <= 7f) ? 1f : 0f); float num5 = 0.85f + 0.15f * ((float)i / 64f); array[i * 64 + j] = new Color(color.r * num5, color.g * num5, color.b * num5, num4); } } val.SetPixels(array); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f)); } } } namespace UpgradeableMixStationMod.Data { [Serializable] public class ItemRequirement { public string ItemID; public int Amount; public string DisplayName; public ItemRequirement(string itemId, int amount, string displayName) { ItemID = itemId; Amount = amount; DisplayName = displayName; } } [Serializable] public class UpgradeTier { public string Name; public float Cost; public float Value; public string Description; public List<ItemRequirement> Items; public UpgradeTier(string name, float cost, float value, string description, List<ItemRequirement> items = null) { Name = name; Cost = cost; Value = value; Description = description; Items = items ?? new List<ItemRequirement>(); } } public static class UpgradeConfig { public const string MixingGearID = "mixinggear"; public const string PrecisionComponentID = "precisioncomponent"; public const string PrototypeCoreID = "prototypecore"; public static readonly List<UpgradeTier> SpeedTiers = new List<UpgradeTier> { new UpgradeTier("Quick Mix", 3000f, 0.8f, "80% of original time", new List<ItemRequirement> { new ItemRequirement("mixinggear", 2, "Mixing Gear") }), new UpgradeTier("Rapid Mix", 6000f, 0.6f, "60% of original time", new List<ItemRequirement> { new ItemRequirement("mixinggear", 3, "Mixing Gear"), new ItemRequirement("precisioncomponent", 1, "Precision Component") }), new UpgradeTier("Swift Mix", 8000f, 0.4f, "40% of original time", new List<ItemRequirement> { new ItemRequirement("mixinggear", 4, "Mixing Gear"), new ItemRequirement("precisioncomponent", 2, "Precision Component") }), new UpgradeTier("Blitz Mix", 10000f, 0.2f, "20% of original time", new List<ItemRequirement> { new ItemRequirement("precisioncomponent", 3, "Precision Component"), new ItemRequirement("prototypecore", 1, "Prototype Core") }), new UpgradeTier("Instant Mix", 20000f, 0f, "Completes in 1 minute", new List<ItemRequirement> { new ItemRequirement("precisioncomponent", 5, "Precision Component"), new ItemRequirement("prototypecore", 3, "Prototype Core") }) }; public static readonly List<UpgradeTier> QualityTiers = new List<UpgradeTier> { new UpgradeTier("Standard Floor", 5000f, 2f, "Minimum quality: Standard", new List<ItemRequirement> { new ItemRequirement("mixinggear", 3, "Mixing Gear"), new ItemRequirement("precisioncomponent", 1, "Precision Component") }), new UpgradeTier("Premium Floor", 12000f, 3f, "Minimum quality: Premium", new List<ItemRequirement> { new ItemRequirement("precisioncomponent", 4, "Precision Component"), new ItemRequirement("prototypecore", 1, "Prototype Core") }), new UpgradeTier("Heavenly Floor", 20000f, 4f, "Minimum quality: Heavenly", new List<ItemRequirement> { new ItemRequirement("precisioncomponent", 5, "Precision Component"), new ItemRequirement("prototypecore", 3, "Prototype Core") }) }; } [Serializable] public class StationUpgradeData { public int SpeedLevel; public int QualityLevel; public bool CanUpgradeSpeed => SpeedLevel < UpgradeConfig.SpeedTiers.Count; public bool IsInstantSpeed => SpeedLevel > 0 && UpgradeConfig.SpeedTiers[SpeedLevel - 1].Value == 0f; public float SpeedMultiplier => (SpeedLevel > 0) ? UpgradeConfig.SpeedTiers[SpeedLevel - 1].Value : 1f; public UpgradeTier NextSpeedTier => CanUpgradeSpeed ? UpgradeConfig.SpeedTiers[SpeedLevel] : null; public string CurrentSpeedName => (SpeedLevel > 0) ? UpgradeConfig.SpeedTiers[SpeedLevel - 1].Name : "None"; public bool CanUpgradeQuality => QualityLevel < UpgradeConfig.QualityTiers.Count; public int QualityFloorValue => (QualityLevel > 0) ? ((int)UpgradeConfig.QualityTiers[QualityLevel - 1].Value) : 0; public UpgradeTier NextQualityTier => CanUpgradeQuality ? UpgradeConfig.QualityTiers[QualityLevel] : null; public string CurrentQualityName => (QualityLevel > 0) ? UpgradeConfig.QualityTiers[QualityLevel - 1].Name : "None"; public StationUpgradeData() { SpeedLevel = 0; QualityLevel = 0; } } [Serializable] public class SaveFile { public Dictionary<string, StationUpgradeData> Stations = new Dictionary<string, StationUpgradeData>(); } public class UpgradeManager { private const string FileName = "UpgradeableMixStationMod.json"; private Dictionary<string, StationUpgradeData> _data = new Dictionary<string, StationUpgradeData>(); public StationUpgradeData GetData(Guid stationGuid) { string key = stationGuid.ToString(); if (!_data.TryGetValue(key, out var value)) { value = new StationUpgradeData(); _data[key] = value; } return value; } public bool HasRequiredItems(UpgradeTier tier) { PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance; if ((Object)(object)instance == (Object)null) { return false; } foreach (ItemRequirement item in tier.Items) { if (instance.GetAmountOfItem(item.ItemID) < item.Amount) { return false; } } return true; } public int GetPlayerItemCount(string itemID) { PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance; if ((Object)(object)instance == (Object)null) { return 0; } return (int)instance.GetAmountOfItem(itemID); } public bool TryUpgradeSpeed(Guid stationGuid, out string failReason) { StationUpgradeData data = GetData(stationGuid); if (!data.CanUpgradeSpeed) { failReason = "Already at max level."; return false; } UpgradeTier nextSpeedTier = data.NextSpeedTier; if (!HasRequiredItems(nextSpeedTier)) { failReason = "Missing required parts."; return false; } if (!TryDeductCash(nextSpeedTier.Cost, out failReason)) { return false; } ConsumeItems(nextSpeedTier); data.SpeedLevel++; SaveNow(); return true; } public bool TryUpgradeQuality(Guid stationGuid, out string failReason) { StationUpgradeData data = GetData(stationGuid); if (!data.CanUpgradeQuality) { failReason = "Already at max level."; return false; } UpgradeTier nextQualityTier = data.NextQualityTier; if (!HasRequiredItems(nextQualityTier)) { failReason = "Missing required parts."; return false; } if (!TryDeductCash(nextQualityTier.Cost, out failReason)) { return false; } ConsumeItems(nextQualityTier); data.QualityLevel++; SaveNow(); return true; } private void ConsumeItems(UpgradeTier tier) { PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance; if ((Object)(object)instance == (Object)null) { return; } foreach (ItemRequirement item in tier.Items) { for (int i = 0; i < item.Amount; i++) { instance.RemoveAmountOfItem(item.ItemID, 1u); } } } private bool TryDeductCash(float cost, out string failReason) { failReason = ""; try { MoneyManager instance = NetworkSingleton<MoneyManager>.Instance; if ((Object)(object)instance == (Object)null) { failReason = "Money system unavailable."; return false; } if (instance.cashBalance < cost) { failReason = "Not enough cash. Need " + MoneyManager.FormatAmount(cost, false, false) + "."; return false; } instance.ChangeCashBalance(0f - cost, true, false); return true; } catch (Exception arg) { failReason = "Error accessing money system."; Melon<Mod>.Logger.Error($"TryDeductCash failed: {arg}"); return false; } } private void SaveNow() { try { LoadManager instance = Singleton<LoadManager>.Instance; string text = ((instance != null) ? instance.LoadedGameFolderPath : null); if (!string.IsNullOrEmpty(text)) { Save(text); } } catch { } } public void Save(string saveFolderPath) { try { SaveFile saveFile = new SaveFile(); foreach (KeyValuePair<string, StationUpgradeData> datum in _data) { if (datum.Value.SpeedLevel > 0 || datum.Value.QualityLevel > 0) { saveFile.Stations[datum.Key] = datum.Value; } } string path = Path.Combine(saveFolderPath, "UpgradeableMixStationMod.json"); File.WriteAllText(path, JsonConvert.SerializeObject((object)saveFile, (Formatting)1)); } catch (Exception arg) { Melon<Mod>.Logger.Error($"Failed to save: {arg}"); } } public void Load(string saveFolderPath) { try { string path = Path.Combine(saveFolderPath, "UpgradeableMixStationMod.json"); if (!File.Exists(path)) { _data.Clear(); } else { _data = JsonConvert.DeserializeObject<SaveFile>(File.ReadAllText(path))?.Stations ?? new Dictionary<string, StationUpgradeData>(); } } catch (Exception arg) { Melon<Mod>.Logger.Error($"Failed to load: {arg}"); _data.Clear(); } } } }