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 v1.0.1
Upgradeable Mix Station Mod.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.Json; using System.Text.RegularExpressions; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Money; using Il2CppScheduleOne.ObjectScripts; using Il2CppScheduleOne.UI.Stations; using Il2CppTMPro; using MelonLoader; using MelonLoader.Utils; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using UpgradeableMixStationMod; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(MixStationUpgradeMod), "Dom's Upgradeable Mix Station Mod", "1.0.0", "Dom", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: MelonAdditionalDependencies(new string[] { "Unity.TextMeshPro" })] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Upgradeable Mix Station Mod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+499bca348101c88159c30d972122753e161c57e1")] [assembly: AssemblyProduct("Upgradeable Mix Station Mod")] [assembly: AssemblyTitle("Upgradeable Mix Station Mod")] [assembly: AssemblyVersion("1.0.0.0")] namespace UpgradeableMixStationMod; public static class BuildInfo { public const string Name = "Dom's Upgradeable Mix Station Mod"; public const string Description = "Adds upgrades to the Mixing Station Mk2"; public const string Author = "Dom"; public const string Version = "1.0.0"; } public class StationUpgradeData { public int Level = 1; public int Cost = 500; public bool Enhanced = false; public Text LevelText; public GameObject UpgradePanel; } public class GlobalUpgradeState { public int Level { get; set; } = 1; public bool Enhanced { get; set; } = false; } public class MixStationUpgradeMod : MelonMod { public static Dictionary<MixingStationCanvas, StationUpgradeData> stationData = new Dictionary<MixingStationCanvas, StationUpgradeData>(); private static readonly string SavePath = Path.Combine(MelonEnvironment.UserDataDirectory, "MixStationUpgradeSave.json"); private static GlobalUpgradeState globalState = new GlobalUpgradeState(); public override void OnInitializeMelon() { LoadUpgradeData(); MelonLogger.Msg("Dom's Upgradeable Mix Station Mod loaded."); } public static void SaveUpgradeData() { try { string contents = JsonSerializer.Serialize(globalState, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(SavePath, contents); MelonLogger.Msg("[Save] Upgrade data saved."); } catch (Exception value) { MelonLogger.Error($"[Save] Failed to save upgrade data: {value}"); } } public static void LoadUpgradeData() { try { if (File.Exists(SavePath)) { string json = File.ReadAllText(SavePath); globalState = JsonSerializer.Deserialize<GlobalUpgradeState>(json) ?? new GlobalUpgradeState(); MelonLogger.Msg($"[Load] Loaded upgrade level {globalState.Level}, enhanced: {globalState.Enhanced}"); } else { MelonLogger.Msg("[Load] No saved data found. Using defaults."); } } catch (Exception value) { MelonLogger.Error($"[Load] Failed to load upgrade data: {value}"); } } public static void Upgrade(MixingStationCanvas stationCanvas) { if (!stationData.TryGetValue(stationCanvas, out var value)) { return; } float cashBalance = NetworkSingleton<MoneyManager>.Instance.cashBalance; if (cashBalance < (float)value.Cost) { MelonLogger.Msg("[Upgrade] Not enough money."); return; } NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance((float)(-value.Cost), true, true); value.Level++; globalState.Level = value.Level; SaveUpgradeData(); if (value.Level == 5) { value.Cost = 30000; UpdateUIToEnhance(value, stationCanvas); } else { value.Cost *= 2; UpdateLevelText(value); } MelonLogger.Msg($"[Upgrade] Upgraded to level {value.Level}"); } public static void Enhance(MixingStationCanvas stationCanvas, bool fromLoad = false) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (!stationData.TryGetValue(stationCanvas, out var value)) { return; } if (value.Enhanced && !fromLoad) { MelonLogger.Msg("[Enhance] Already enhanced."); return; } value.Enhanced = true; globalState.Enhanced = true; Button componentInChildren = value.UpgradePanel.GetComponentInChildren<Button>(); Text componentInChildren2 = ((Component)componentInChildren).GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.text = "Max Level"; ((Selectable)componentInChildren).interactable = false; Image component = ((Component)componentInChildren).GetComponent<Image>(); if ((Object)(object)component != (Object)null) { ((Graphic)component).color = new Color(0.75f, 0.75f, 0.75f, 0.5f); } } if ((Object)(object)value.LevelText != (Object)null) { value.LevelText.text = "Mixing Table: Enhanced"; } if (fromLoad) { SaveUpgradeData(); MelonLogger.Msg("[Enhance] Enhancement complete (loaded state)."); } else { MelonLogger.Msg("[Enhance] Enhancement complete."); } } public static void CreateLevelUI(MixingStationCanvas stationCanvas) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Expected O, but got Unknown //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Expected O, but got Unknown //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) if (stationData.ContainsKey(stationCanvas)) { return; } StationUpgradeData stationUpgradeData = new StationUpgradeData { Level = globalState.Level, Enhanced = globalState.Enhanced, Cost = ((globalState.Level >= 5) ? 30000 : (500 * (int)Mathf.Pow(2f, (float)(globalState.Level - 1)))) }; Transform transform = ((Component)stationCanvas).transform; GameObject val = (stationUpgradeData.UpgradePanel = new GameObject("UpgradePanel")); val.transform.SetParent(transform, false); RectTransform val2 = val.AddComponent<RectTransform>(); val2.sizeDelta = new Vector2(260f, 130f); ((Transform)val2).localPosition = new Vector3(-400f, 0f, 0f); ((Graphic)val.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.6f); ((Shadow)val.AddComponent<Outline>()).effectColor = Color.white; GameObject val3 = new GameObject("LevelText"); val3.transform.SetParent(val.transform, false); Text val4 = val3.AddComponent<Text>(); val4.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); val4.fontSize = 18; val4.alignment = (TextAnchor)4; stationUpgradeData.LevelText = val4; UpdateLevelText(stationUpgradeData); RectTransform component = val3.GetComponent<RectTransform>(); component.anchoredPosition = new Vector2(0f, 30f); component.sizeDelta = new Vector2(240f, 50f); GameObject val5 = new GameObject("UpgradeButton"); val5.transform.SetParent(val.transform, false); Button val6 = val5.AddComponent<Button>(); Image val7 = val5.AddComponent<Image>(); ((Graphic)val7).color = new Color(0.85f, 0.85f, 0.85f); RectTransform component2 = val5.GetComponent<RectTransform>(); component2.anchoredPosition = new Vector2(0f, -25f); component2.sizeDelta = new Vector2(180f, 45f); GameObject val8 = new GameObject("ButtonText"); val8.transform.SetParent(val5.transform, false); Text val9 = val8.AddComponent<Text>(); val9.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); val9.fontSize = 18; val9.alignment = (TextAnchor)4; RectTransform component3 = val8.GetComponent<RectTransform>(); component3.anchoredPosition = Vector2.zero; component3.sizeDelta = component2.sizeDelta; if (stationUpgradeData.Level == 5 && !stationUpgradeData.Enhanced) { val9.text = "Enhance"; ((UnityEvent)val6.onClick).AddListener(UnityAction.op_Implicit((Action)delegate { Enhance(stationCanvas); })); } else if (stationUpgradeData.Enhanced) { val9.text = "Max Level"; ((Selectable)val6).interactable = false; ((Graphic)val7).color = new Color(0.75f, 0.75f, 0.75f, 0.5f); } else { val9.text = "Upgrade"; ((UnityEvent)val6.onClick).AddListener(UnityAction.op_Implicit((Action)delegate { Upgrade(stationCanvas); })); } stationData[stationCanvas] = stationUpgradeData; } private static void UpdateLevelText(StationUpgradeData data) { if ((Object)(object)data.LevelText != (Object)null) { data.LevelText.text = $"Mixing Table Level: {data.Level}\nNext Upgrade: ${data.Cost}"; } } private static void UpdateUIToEnhance(StationUpgradeData data, MixingStationCanvas stationCanvas) { UpdateLevelText(data); Button componentInChildren = data.UpgradePanel.GetComponentInChildren<Button>(); Text componentInChildren2 = ((Component)componentInChildren).GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.text = "Enhance"; ((UnityEventBase)componentInChildren.onClick).RemoveAllListeners(); ((UnityEvent)componentInChildren.onClick).AddListener(UnityAction.op_Implicit((Action)delegate { Enhance(stationCanvas); })); } } } [HarmonyPatch(typeof(MixingStationCanvas), "Start")] public class MixingStationCanvas_Start_Patch { public static void Postfix(MixingStationCanvas __instance) { MixStationUpgradeMod.CreateLevelUI(__instance); } } [HarmonyPatch(typeof(MixingStationMk2), "MixingStart")] public class MixingStationMk2_MixingStart_Patch { public static void Postfix(MixingStationMk2 __instance) { MixingStationCanvas[] array = Il2CppArrayBase<MixingStationCanvas>.op_Implicit(Object.FindObjectsOfType<MixingStationCanvas>()); StationUpgradeData stationUpgradeData = null; MixingStationCanvas[] array2 = array; foreach (MixingStationCanvas val in array2) { if ((Object)(object)val.MixingStation == (Object)(object)__instance && MixStationUpgradeMod.stationData.TryGetValue(val, out var value)) { stationUpgradeData = value; break; } } if (stationUpgradeData == null) { MelonLogger.Warning("[MixingStart Patch] No upgrade data found. Using default timing."); return; } int result = 0; TextMeshProUGUI quantityLabel = __instance.QuantityLabel; string text = ((quantityLabel != null) ? ((TMP_Text)quantityLabel).text : null); if (!string.IsNullOrEmpty(text)) { string value2 = Regex.Match(text, "\\d+").Value; int.TryParse(value2, out result); } if (result <= 0) { MelonLogger.Warning("[MixingStart Patch] Invalid quantity. Aborting."); return; } int num = Mathf.Clamp(stationUpgradeData.Level, 1, 5); float num2 = 3f - (float)(num - 1) * 0.5f; float num3 = (stationUpgradeData.Enhanced ? 1f : ((float)result * num2)); TextMeshProUGUI progressLabel = __instance.ProgressLabel; if ((Object)(object)progressLabel != (Object)null) { ((TMP_Text)progressLabel).text = $"{num3:0.#}s remaining"; } MelonCoroutines.Start(FinishEarly(__instance, num3)); MelonLogger.Msg($"[MixingStart Patch] Mix of {result} will finish in {num3}s (Level {num})"); } private static IEnumerator FinishEarly(MixingStationMk2 station, float totalTime) { float elapsed = 0f; TextMeshProUGUI progressLabel = station.ProgressLabel; while (elapsed < totalTime) { float remaining = Mathf.Max(0f, totalTime - elapsed); string display = $"{remaining:0.#}s remaining"; if ((Object)(object)progressLabel != (Object)null) { ((TMP_Text)progressLabel).text = display; } elapsed += Time.deltaTime; yield return null; } ((MixingStation)station).MixingDone(); if ((Object)(object)progressLabel != (Object)null) { ((TMP_Text)progressLabel).text = "Mixing Complete!"; } MelonLogger.Msg("[MixingStart Patch] MixingDone() called early."); } }