Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of ProductSum Mono v1.2.0
ProductSum-Mono.dll
Decompiled 2 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using HarmonyLib; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using ProductSum; using ScheduleOne; using ScheduleOne.Economy; using ScheduleOne.ItemFramework; using ScheduleOne.PlayerScripts; using ScheduleOne.Product; using ScheduleOne.Quests; using TMPro; using UnityEngine; using UnityEngine.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(global::ProductSum.ProductSum), "ProductSum", "1.2", "k073l", null)] [assembly: MelonColor(1, 255, 215, 0)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ProductSum_Mono")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ProductSum_Mono")] [assembly: AssemblyTitle("ProductSum_Mono")] [assembly: NeutralResourcesLanguage("en-US")] [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 ProductSum { public static class BuildInfo { public const string Name = "ProductSum"; public const string Description = "sums your products duh"; public const string Author = "k073l"; public const string Company = null; public const string Version = "1.2"; public const string DownloadLink = null; } public class ProductSum : MelonMod { [CompilerGenerated] private sealed class <CreateProductUI>d__20 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ProductSum <>4__this; private GameObject <hudParent>5__1; private RectTransform <rectTransform>5__2; private GameObject <bgGO>5__3; private Image <bg>5__4; private RectTransform <bgRect>5__5; private GameObject <textChildGO>5__6; private TextMeshProUGUI <existingText>5__7; private RectTransform <textRect>5__8; private Exception <ex>5__9; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CreateProductUI>d__20(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <hudParent>5__1 = null; <rectTransform>5__2 = null; <bgGO>5__3 = null; <bg>5__4 = null; <bgRect>5__5 = null; <textChildGO>5__6 = null; <existingText>5__7 = null; <textRect>5__8 = null; <ex>5__9 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_010e: 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_0144: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Expected O, but got Unknown //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0226: 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_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Expected O, but got Unknown //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)Player.Local != (Object)null && (Object)(object)((Component)Player.Local).gameObject != (Object)null && !<>4__this.uiCreated) { try { <hudParent>5__1 = GameObject.Find("UI/HUD/"); if ((Object)(object)<hudParent>5__1 == (Object)null) { MelonLogger.Error("Could not find HUD parent!"); return false; } <>4__this.uiContainer = new GameObject("ProductSumContainer"); <>4__this.uiContainer.transform.SetParent(<hudParent>5__1.transform, false); <rectTransform>5__2 = <>4__this.uiContainer.AddComponent<RectTransform>(); <rectTransform>5__2.anchorMin = new Vector2(0f, 1f); <rectTransform>5__2.anchorMax = new Vector2(0f, 1f); <rectTransform>5__2.pivot = new Vector2(0f, 1f); <rectTransform>5__2.anchoredPosition = new Vector2(10f, -40f); <rectTransform>5__2.sizeDelta = new Vector2(200f, 100f); <bgGO>5__3 = new GameObject("Background"); <bgGO>5__3.transform.SetParent(<>4__this.uiContainer.transform, false); <bg>5__4 = <bgGO>5__3.AddComponent<Image>(); ((Graphic)<bg>5__4).color = new Color(0f, 0f, 0f, 0.5f); <bgRect>5__5 = ((Component)<bg>5__4).GetComponent<RectTransform>(); <bgRect>5__5.anchorMin = Vector2.zero; <bgRect>5__5.anchorMax = Vector2.one; <bgRect>5__5.offsetMin = Vector2.zero; <bgRect>5__5.offsetMax = Vector2.zero; <textChildGO>5__6 = new GameObject("Text"); <textChildGO>5__6.transform.SetParent(<>4__this.uiContainer.transform, false); <>4__this.tmpText = <textChildGO>5__6.AddComponent<TextMeshProUGUI>(); ((TMP_Text)<>4__this.tmpText).alignment = (TextAlignmentOptions)257; ((TMP_Text)<>4__this.tmpText).fontSize = 15f; ((Graphic)<>4__this.tmpText).color = Color.white; ((TMP_Text)<>4__this.tmpText).text = ""; <existingText>5__7 = <hudParent>5__1.GetComponentInChildren<TextMeshProUGUI>(); if ((Object)(object)<existingText>5__7 != (Object)null && (Object)(object)((TMP_Text)<existingText>5__7).font != (Object)null) { ((TMP_Text)<>4__this.tmpText).font = ((TMP_Text)<existingText>5__7).font; } <textRect>5__8 = ((Component)<>4__this.tmpText).GetComponent<RectTransform>(); <textRect>5__8.anchorMin = Vector2.zero; <textRect>5__8.anchorMax = Vector2.one; <textRect>5__8.offsetMin = new Vector2(5f, 5f); <textRect>5__8.offsetMax = new Vector2(-5f, -5f); <>4__this.uiContainer.SetActive(false); <>4__this.uiCreated = true; MelonLogger.Msg("ProductSum UI created successfully!"); <hudParent>5__1 = null; <rectTransform>5__2 = null; <bgGO>5__3 = null; <bg>5__4 = null; <bgRect>5__5 = null; <textChildGO>5__6 = null; <existingText>5__7 = null; <textRect>5__8 = null; } catch (Exception ex) { <ex>5__9 = ex; MelonLogger.Error("Error creating UI: " + <ex>5__9.Message + "\n" + <ex>5__9.StackTrace); } } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WaitForPlayer>d__18 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ProductSum <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForPlayer>d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((Object)(object)Player.Local == (Object)null || (Object)(object)((Component)Player.Local).gameObject == (Object)null) { <>2__current = null; <>1__state = 1; return true; } if (!hasPlayerSpawned) { hasPlayerSpawned = true; MelonCoroutines.Start(<>4__this.CreateProductUI()); } else if (<>4__this.uiCreated && (Object)(object)<>4__this.uiContainer != (Object)null) { <>4__this.uiContainer.SetActive(true); <>4__this.UpdateProductUI(); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static MelonPreferences_Category Category; private static MelonPreferences_Entry<bool> AlwaysOn; private static MelonPreferences_Entry<string> Keybind; private static MelonPreferences_Entry<int> Timeout; private static MelonPreferences_Entry<bool> SplitByTimeSlot; private static MelonPreferences_Entry<bool> ShowPackagingDetails; private GameObject uiContainer; private TextMeshProUGUI tmpText; private static bool hasPlayerSpawned; private bool uiCreated = false; private bool timerActive = false; private float timerStartTime = 0f; private static MethodInfo shouldShowJournalEntryMethod; private static Instance MelonLogger { get; set; } public override void OnInitializeMelon() { MelonLogger = ((MelonBase)this).LoggerInstance; MelonLogger.Msg("ProductSum initialized!"); Category = MelonPreferences.CreateCategory("ProductSum", "ProductSum Settings"); AlwaysOn = Category.CreateEntry<bool>("AlwaysOn", true, "When enabled, the product summary is always visible (when available)", (string)null, false, false, (ValueValidator)null, (string)null); SplitByTimeSlot = Category.CreateEntry<bool>("SplitByTimeSlot", true, "When enabled, the product summary is split by time slot", (string)null, false, false, (ValueValidator)null, (string)null); Keybind = Category.CreateEntry<string>("Keybind", "P", "Key to temporarily show the product summary (when not in Always On mode)", (string)null, false, false, (ValueValidator)null, (string)null); Timeout = Category.CreateEntry<int>("Timeout", 5, "How many seconds the product summary remains visible after pressing the keybind", (string)null, false, false, (ValueValidator)null, (string)null); ShowPackagingDetails = Category.CreateEntry<bool>("ShowPackagingDetails", false, "When enabled, the product summary shows packaging details", (string)null, false, false, (ValueValidator)null, (string)null); shouldShowJournalEntryMethod = AccessTools.Method(typeof(Contract), "ShouldShowJournalEntry", (Type[])null, (Type[])null); if (shouldShowJournalEntryMethod == null) { MelonLogger.Error("Failed to find method: Contract.ShouldShowJournalEntry()"); } } [IteratorStateMachine(typeof(<WaitForPlayer>d__18))] private IEnumerator WaitForPlayer() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForPlayer>d__18(0) { <>4__this = this }; } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (sceneName == "Main") { MelonLogger.Msg("Main scene loaded, waiting for player..."); MelonCoroutines.Start(WaitForPlayer()); return; } hasPlayerSpawned = false; uiCreated = false; if ((Object)(object)uiContainer != (Object)null) { uiContainer.SetActive(false); } Object.Destroy((Object)(object)uiContainer); uiContainer = null; } [IteratorStateMachine(typeof(<CreateProductUI>d__20))] private IEnumerator CreateProductUI() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CreateProductUI>d__20(0) { <>4__this = this }; } public override void OnUpdate() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!uiCreated || (Object)(object)tmpText == (Object)null) { return; } if (!AlwaysOn.Value && Input.GetKeyDown(ParseKeybind(Keybind.Value))) { MelonLogger.Msg("Timer started"); timerActive = true; timerStartTime = Time.time; UpdateProductUI(); } if (timerActive && Time.time - timerStartTime >= (float)Timeout.Value) { timerActive = false; if (!AlwaysOn.Value) { uiContainer.SetActive(false); } } if (AlwaysOn.Value || timerActive || uiContainer.activeSelf) { UpdateProductUI(); } } private void UpdateProductUI() { //IL_012a: 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_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0143: 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_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) try { Dictionary<EDealWindow, AbbreviatedDealInfo> dictionary = new Dictionary<EDealWindow, AbbreviatedDealInfo>(); bool flag = false; int num = 0; List<Contract> contracts = Contract.Contracts; if (contracts != null && contracts.Count > 0) { foreach (Contract item2 in contracts) { bool flag2 = false; if (shouldShowJournalEntryMethod != null) { try { flag2 = (bool)shouldShowJournalEntryMethod.Invoke(item2, null); } catch (Exception ex) { MelonLogger.Error("Reflection error: " + ex.Message); continue; } } if (!flag2) { continue; } num++; flag = true; ProductList productList = item2.ProductList; QuestWindowConfig deliveryWindow = item2.DeliveryWindow; if (productList?.entries == null) { continue; } foreach (Entry entry in productList.entries) { ItemDefinition item = Registry.GetItem(entry.ProductID); if (!((Object)(object)item == (Object)null)) { string name = item.Name; int quantity = entry.Quantity; EDealWindow window = DealWindowInfo.GetWindow(deliveryWindow.WindowStartTime); if (!dictionary.ContainsKey(window)) { dictionary[window] = new AbbreviatedDealInfo(window); } dictionary[window].AddProduct(name, quantity); } } } if (flag && num > 1) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Summary:"); stringBuilder.AppendLine("---------------"); bool value = ShowPackagingDetails.Value; if (SplitByTimeSlot.Value) { foreach (AbbreviatedDealInfo value2 in dictionary.Values) { stringBuilder.AppendLine(value2.GetFormattedSummary(value)); stringBuilder.AppendLine(); } } else { AbbreviatedDealInfo abbreviatedDealInfo = new AbbreviatedDealInfo((EDealWindow)0); foreach (AbbreviatedDealInfo value3 in dictionary.Values) { abbreviatedDealInfo.MergeFrom(value3); } foreach (KeyValuePair<string, Packing> product in abbreviatedDealInfo.Products) { if (value) { stringBuilder.Append("<i>" + product.Key + "</i>: "); List<string> list = new List<string>(); foreach (KeyValuePair<string, int> item3 in product.Value.Items) { list.Add($"<b>{item3.Value}</b>x {item3.Key}"); } stringBuilder.AppendLine(string.Join(", ", list)); } else { int totalQuantity = product.Value.GetTotalQuantity(); stringBuilder.AppendLine($"<b>{totalQuantity}</b>x <i>{product.Key}</i>"); } } } ((TMP_Text)tmpText).text = stringBuilder.ToString(); Canvas.ForceUpdateCanvases(); float num2 = ((TMP_Text)tmpText).preferredHeight + 20f; RectTransform component = uiContainer.GetComponent<RectTransform>(); component.sizeDelta = new Vector2(component.sizeDelta.x, num2); bool flag3 = AlwaysOn.Value || timerActive; if (flag3 && !uiContainer.activeSelf) { uiContainer.SetActive(true); } else if (!flag3 && uiContainer.activeSelf) { uiContainer.SetActive(false); } } else if (uiContainer.activeSelf) { uiContainer.SetActive(false); timerActive = false; } } else if (uiContainer.activeSelf && !AlwaysOn.Value) { uiContainer.SetActive(false); timerActive = false; } } catch (Exception ex2) { MelonLogger.Error("Error updating product list: " + ex2.Message); } } private KeyCode ParseKeybind(string keybind) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (Enum.TryParse<KeyCode>(keybind, out KeyCode result)) { return result; } return (KeyCode)112; } } public class Packing { public static readonly SortedDictionary<string, int> PackagingCapacities = new SortedDictionary<string, int> { { "Baggie", 1 }, { "Jar", 5 }, { "Brick", 20 } }; public string Name { get; set; } public Dictionary<string, int> Items { get; private set; } public Packing(string name, int quantity) { Name = name; Items = DistributeQuantityToPackaging(quantity); } public Packing(string name, Dictionary<string, int> items) { Name = name; Items = new Dictionary<string, int>(items); } private static Dictionary<string, int> DistributeQuantityToPackaging(int quantity) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); int num = quantity; foreach (KeyValuePair<string, int> item in PackagingCapacities.OrderByDescending((KeyValuePair<string, int> p) => p.Value)) { string key = item.Key; int value = item.Value; if (num >= value) { int value2 = num / value; dictionary[key] = value2; num %= value; } } if (num > 0 && PackagingCapacities.Count > 0) { string key2 = PackagingCapacities.OrderBy((KeyValuePair<string, int> p) => p.Value).First().Key; if (dictionary.ContainsKey(key2)) { dictionary[key2]++; } else { dictionary[key2] = 1; } } return dictionary; } public void MergeWith(Packing other) { if (Name != other.Name) { throw new ArgumentException("Cannot merge packings of different products"); } foreach (KeyValuePair<string, int> item in other.Items) { if (Items.ContainsKey(item.Key)) { Items[item.Key] += item.Value; } else { Items[item.Key] = item.Value; } } } public Dictionary<string, int> Flatten() { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (KeyValuePair<string, int> item in Items) { string key = item.Key; int value = item.Value; if (PackagingCapacities.ContainsKey(key)) { dictionary[Name] = (dictionary.ContainsKey(Name) ? dictionary[Name] : 0) + value * PackagingCapacities[key]; } } return dictionary; } public int GetTotalQuantity() { int num = 0; foreach (KeyValuePair<string, int> item in Items) { if (PackagingCapacities.ContainsKey(item.Key)) { num += item.Value * PackagingCapacities[item.Key]; } } return num; } } public class AbbreviatedDealInfo { public EDealWindow TimeSlot { get; set; } public Dictionary<string, Packing> Products { get; set; } public AbbreviatedDealInfo(EDealWindow timeSlot) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) TimeSlot = timeSlot; Products = new Dictionary<string, Packing>(); } public void AddProduct(string productName, int quantity) { Packing packing = new Packing(productName, quantity); if (Products.ContainsKey(productName)) { Products[productName].MergeWith(packing); } else { Products[productName] = packing; } } public void MergeFrom(AbbreviatedDealInfo other) { foreach (KeyValuePair<string, Packing> product in other.Products) { if (Products.ContainsKey(product.Key)) { Products[product.Key].MergeWith(product.Value); } else { Products[product.Key] = new Packing(product.Key, new Dictionary<string, int>(product.Value.Items)); } } } public Dictionary<string, int> FlattenProducts() { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (KeyValuePair<string, Packing> product in Products) { string key = product.Key; int totalQuantity = product.Value.GetTotalQuantity(); dictionary[key] = totalQuantity; } return dictionary; } public string GetFormattedSummary(bool showPackaging) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); string name = Enum.GetName(typeof(EDealWindow), TimeSlot); stringBuilder.AppendLine("<u>" + name + "</u>"); foreach (KeyValuePair<string, Packing> product in Products) { string key = product.Key; if (showPackaging) { stringBuilder.Append("<i>" + key + "</i>: "); List<string> list = new List<string>(); foreach (KeyValuePair<string, int> item in product.Value.Items) { list.Add($"<b>{item.Value}</b>x {item.Key}"); } stringBuilder.AppendLine(string.Join(", ", list)); } else { int totalQuantity = product.Value.GetTotalQuantity(); stringBuilder.AppendLine($"<b>{totalQuantity}</b>x <i>{key}</i>"); } } return stringBuilder.ToString(); } } }