Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of AutoRestockIL2CPP v1.1.1
Mods/AutoRestockIL2CPP.dll
Decompiled 2 weeks 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.Threading; using AutoRestock; using HarmonyLib; using Il2CppFishNet; using Il2CppFishNet.Object; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.EntityFramework; using Il2CppScheduleOne.GameTime; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.Management; using Il2CppScheduleOne.Messaging; using Il2CppScheduleOne.Money; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.NPCs.Behaviour; using Il2CppScheduleOne.ObjectScripts; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.PlayerTasks; using Il2CppScheduleOne.Property; using Il2CppScheduleOne.StationFramework; using Il2CppScheduleOne.Storage; using Il2CppScheduleOne.UI; using Il2CppScheduleOne.UI.Items; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(AutoRestockMod), "AutoRestock", "1.1.1", "lasersquid", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("AutoRestockIL2CPP")] [assembly: AssemblyConfiguration("IL2CPP")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: AssemblyInformationalVersion("1.1.1+f66bf71d4af9219ae7d76e96b0a8fcce524d01ea")] [assembly: AssemblyProduct("AutoRestockIL2CPP")] [assembly: AssemblyTitle("AutoRestockIL2CPP")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.1.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 AutoRestock { public class AutoRestockMod : MelonMod { public MelonPreferences_Category melonPrefs; public Harmony harmony = new Harmony("com.lasersquid.autorestock"); public override void OnInitializeMelon() { CreateMelonPreferences(); Utils.Initialize(this); ((MelonBase)this).LoggerInstance.Msg("Mod initialized."); } private void CreateMelonPreferences() { melonPrefs = MelonPreferences.CreateCategory("AutoRestock"); melonPrefs.SetFilePath("UserData/AutoRestock.cfg", true, false); melonPrefs.CreateEntry<float>("itemDiscount", 0f, "Restock discount", "Discount applied to restock price (0.2 = 20% off)", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("payWithCash", true, "Pay for restock with cash", "True to pay with cash, false to pay with bank account", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<int>("restockAmount", 0, "Amount to restock", "Amount to restock when a restock is triggered (enter 0 for item stacklimit)", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("enableCauldrons", true, "Enable auto-restock on cauldrons", "Enable auto-restock on cauldrons", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("enableMixingStations", true, "Enable auto-restock on mixing stations", "Enable auto-restock on mixing stations", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("enableChemistryStations", true, "Enable auto-restock on chemistry stations", "Enable auto-restock on chemistry stations", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("enablePackagingStations", true, "Enable auto-restock on packaging stations", "Enable auto-restock on packaging stations", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("enableSpawnStations", true, "Enable auto-restock on mushroom spawn stations", "Enable auto-restock on mushroom spawn stations", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("enableStorage", true, "Enable auto-restock on storage (shelves and safes)", "Enable auto-restock on storage (shelves and safes)", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("playerRestockStations", true, "Enable auto-restock on stations after player-initiated actions (start cauldron, etc)", "Enable auto-restock on stations after player-initiated actions (start cauldron, etc)", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("verboseLogs", false, "Print to the log for each auto-restock transaction", "Print to the log for each auto-restock transaction", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("debugLogs", false, "Print debug logs", "Print debug logs", false, false, (ValueValidator)null, (string)null); melonPrefs.SaveToFile(false); } } public static class Utils { public class UnityObjectComparer : IEqualityComparer<Object> { public bool Equals(Object a, Object b) { return a.GetInstanceID() == b.GetInstanceID(); } public int GetHashCode(Object item) { return item.GetInstanceID(); } } private static AutoRestockMod Mod; private static Assembly S1Assembly; public static void Initialize(AutoRestockMod mod) { Mod = mod; S1Assembly = AppDomain.CurrentDomain.GetAssemblies().First((Assembly a) => a.GetName().Name == "Assembly-CSharp"); } public static void PrintException(Exception e) { Warn("Exception: " + e.GetType().Name + " - " + e.Message); Warn("Source: " + e.Source); Warn(e.StackTrace ?? ""); if (e.InnerException != null) { Warn("Inner exception: " + e.InnerException.GetType().Name + " - " + e.InnerException.Message); Warn("Source: " + e.InnerException.Source); Warn(e.InnerException.StackTrace ?? ""); if (e.InnerException.InnerException != null) { Warn("Inner inner exception: " + e.InnerException.InnerException.GetType().Name + " - " + e.InnerException.InnerException.Message); Warn("Source: " + e.InnerException.InnerException.Source); Warn(e.InnerException.InnerException.StackTrace ?? ""); } } } public static void Log(string message) { ((MelonBase)Mod).LoggerInstance.Msg(message); } public static void Warn(string message) { ((MelonBase)Mod).LoggerInstance.Warning(message); } public static void Debug(string message) { if (Manager.isInitialized && Manager.melonPrefs.GetEntry<bool>("debugLogs").Value) { ((MelonBase)Mod).LoggerInstance.Msg("DEBUG: " + message); } } public static void VerboseLog(string message) { if (Manager.isInitialized && Manager.melonPrefs.GetEntry<bool>("verboseLogs").Value) { ((MelonBase)Mod).LoggerInstance.Msg(message); } } public static Treturn GetField<Ttarget, Treturn>(string fieldName, object target) where Treturn : class { return (Treturn)GetField<Ttarget>(fieldName, target); } public static object GetField<Ttarget>(string fieldName, object target) { return AccessTools.Property(typeof(Ttarget), fieldName).GetValue(target); } public static void SetField<Ttarget>(string fieldName, object target, object value) { AccessTools.Property(typeof(Ttarget), fieldName).SetValue(target, value); } public static Treturn GetProperty<Ttarget, Treturn>(string fieldName, object target) where Treturn : class { return (Treturn)GetProperty<Ttarget>(fieldName, target); } public static object GetProperty<Ttarget>(string fieldName, object target) { return AccessTools.Property(typeof(Ttarget), fieldName).GetValue(target); } public static void SetProperty<Ttarget>(string fieldName, object target, object value) { AccessTools.Property(typeof(Ttarget), fieldName).SetValue(target, value); } public static Treturn CallMethod<Ttarget, Treturn>(string methodName, object target) where Treturn : class { return (Treturn)CallMethod<Ttarget>(methodName, target, Array.Empty<object>()); } public static Treturn CallMethod<Ttarget, Treturn>(string methodName, object target, object[] args) where Treturn : class { return (Treturn)CallMethod<Ttarget>(methodName, target, args); } public static Treturn CallMethod<Ttarget, Treturn>(string methodName, Type[] argTypes, object target, object[] args) where Treturn : class { return (Treturn)CallMethod<Ttarget>(methodName, argTypes, target, args); } public static object CallMethod<Ttarget>(string methodName, object target) { return AccessTools.Method(typeof(Ttarget), methodName, (Type[])null, (Type[])null).Invoke(target, Array.Empty<object>()); } public static object CallMethod<Ttarget>(string methodName, object target, object[] args) { return AccessTools.Method(typeof(Ttarget), methodName, (Type[])null, (Type[])null).Invoke(target, args); } public static object CallMethod<Ttarget>(string methodName, Type[] argTypes, object target, object[] args) { return AccessTools.Method(typeof(Ttarget), methodName, argTypes, (Type[])null).Invoke(target, args); } public static T CastTo<T>(Il2CppObjectBase o) where T : Il2CppObjectBase { if (typeof(T).IsAssignableFrom(GetType(o))) { return (T)Activator.CreateInstance(typeof(T), o.Pointer); } return default(T); } public static bool Is<T>(Il2CppObjectBase o) { return typeof(T).IsAssignableFrom(GetType(o)); } public static T ToInterface<T>(Il2CppObjectBase o) where T : Il2CppObjectBase { return (T)Activator.CreateInstance(typeof(T), o.Pointer); } public static Type GetType(Il2CppObjectBase o) { string fullName = Il2CppType.TypeFromPointer(o.ObjectClass, "<unknown type>").FullName; return S1Assembly.GetType("Il2Cpp" + fullName); } public static UnityAction ToUnityAction(Action action) { return DelegateSupport.ConvertDelegate<UnityAction>((Delegate)action); } public static UnityAction<T> ToUnityAction<T>(Action<T> action) { return DelegateSupport.ConvertDelegate<UnityAction<T>>((Delegate)action); } public static Predicate<T> ToPredicate<T>(Func<T, bool> func) { return DelegateSupport.ConvertDelegate<Predicate<T>>((Delegate)func); } public static List<ItemDefinition> GetItemDefsContaining(List<string> terms) { List<ItemDefinition> allItems = Singleton<Registry>.Instance.GetAllItems(); return allItems.FindAll(ToPredicate((ItemDefinition def) => terms.Any((string term) => def.ID.Contains(term)))); } public static bool IsQualityIngredient(string itemID) { List<string> source = new List<string>(1) { "pseudo" }; return source.Any((string id) => itemID.Contains(id)); } public static StorableItemInstance GetItemInstance(string itemID, EQuality quality = 2) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (IsQualityIngredient(itemID)) { return (StorableItemInstance)(object)GetQualityItemInstance(itemID, quality); } return Utils.CastTo<StorableItemInstance>((Il2CppObjectBase)(object)Registry.GetItem(itemID).GetDefaultInstance(1)); } public static QualityItemInstance GetQualityItemInstance(string itemID, EQuality quality) { //IL_0054: 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) Dictionary<EQuality, string> dictionary = new Dictionary<EQuality, string> { { (EQuality)4, "heavenly" }, { (EQuality)3, "highquality" }, { (EQuality)2, "" }, { (EQuality)1, "lowquality" }, { (EQuality)0, "trash" } }; if (IsQualityIngredient(itemID)) { string text = dictionary[quality] + itemID; QualityItemInstance val = Utils.CastTo<QualityItemInstance>((Il2CppObjectBase)(object)Registry.GetItem(text).GetDefaultInstance(1)); val.Quality = quality; return val; } Warn("itemid " + itemID + " is not a quality ingredient?"); return null; } public static bool IsStorageRack(ITransitEntity transitEntity) { if (transitEntity != null && Is<PlaceableStorageEntity>((Il2CppObjectBase)(object)transitEntity)) { PlaceableStorageEntity placeable = Utils.CastTo<PlaceableStorageEntity>((Il2CppObjectBase)(object)transitEntity); return IsStorageRack(placeable); } return false; } public static bool IsStorageRack(IItemSlotOwner slotOwner) { if (slotOwner != null && Is<StorageEntity>((Il2CppObjectBase)(object)slotOwner)) { StorageEntity entity = Utils.CastTo<StorageEntity>((Il2CppObjectBase)(object)slotOwner); return IsStorageRack(entity); } return false; } public static bool IsStorageRack(StorageEntity entity) { if ((Object)(object)entity != (Object)null) { PlaceableStorageEntity component = ((Component)entity).GetComponent<PlaceableStorageEntity>(); if ((Object)(object)component != (Object)null) { return IsStorageRack(component); } Warn("StorageEntity " + ((Object)entity).name + " did not have PlaceableStorageEntity component"); return false; } return false; } public static bool IsStorageRack(PlaceableStorageEntity placeable) { List<string> source = new List<string>(5) { "safe", "smallstoragerack", "mediumstoragerack", "largestoragerack", "wallmountedshelf" }; if ((Object)(object)placeable != (Object)null) { string placeableID = ((BuildableItem)placeable).ItemInstance.ID; return source.Any((string id) => placeableID.Contains(id)); } return false; } public static bool IsStation(ITransitEntity transitEntity) { if (transitEntity != null && Is<GridItem>((Il2CppObjectBase)(object)transitEntity)) { GridItem gridItem = Utils.CastTo<GridItem>((Il2CppObjectBase)(object)transitEntity); return IsStation(gridItem); } return false; } public static bool IsStation(IItemSlotOwner slotOwner) { if (slotOwner != null && Is<GridItem>((Il2CppObjectBase)(object)slotOwner)) { GridItem gridItem = Utils.CastTo<GridItem>((Il2CppObjectBase)(object)slotOwner); return IsStation(gridItem); } return false; } public static bool IsStation(GridItem gridItem) { List<Type> list = new List<Type>(7); list.Add(typeof(PackagingStation)); list.Add(typeof(Cauldron)); list.Add(typeof(ChemistryStation)); list.Add(typeof(MixingStation)); list.Add(typeof(MushroomSpawnStation)); list.Add(typeof(LabOven)); list.Add(typeof(DryingRack)); List<Type> source = list; if ((Object)(object)gridItem != (Object)null) { Type ownerType = GetType((Il2CppObjectBase)(object)gridItem); return source.Any((Type t) => t.IsAssignableFrom(ownerType)); } return false; } } public static class Manager { public class Transaction { public string itemID; public int quantity; public float discount; public float unitPrice; public float totalCost; public string property; public bool useCash; public SlotIdentifier slotID; public Transaction(string itemID, int quantity, float discount, float unitPrice, float totalCost, bool useCash, SlotIdentifier slotID) { this.itemID = itemID; this.quantity = quantity; this.discount = discount; this.unitPrice = unitPrice; this.totalCost = totalCost; this.useCash = useCash; this.slotID = slotID; } } public class SlotIdentifier { public List<float> gridLocation; public string type; public int slotIndex; public string property; public SlotIdentifier(string property, Vector2 gridLocation, int slotIndex, string type) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) this.property = property; this.gridLocation = new List<float>(new <>z__ReadOnlyArray<float>(new float[2] { gridLocation.x, gridLocation.y })); this.slotIndex = slotIndex; this.type = type; } [JsonConstructor] public SlotIdentifier(string property, List<float> gridLocation, int slotIndex, string type) { this.property = property; this.gridLocation = gridLocation; this.slotIndex = slotIndex; this.type = type; } } public static ItemSlot playerClickedSlot; public static List<ItemSlot> playerStationOperationSlots; public static MelonPreferences_Category melonPrefs; private static TimeManager timeManager; private static MoneyManager moneyManager; private static SaveManager saveManager; private static NPC oscar; private static string ledgerString; private static string transactionString; private static List<Transaction> ledger; private static Dictionary<Transaction, object> coroutines; private static EDay ledgerDay; private static Mutex exclusiveLock; public static bool isInitialized; public static SlotIdentifier SerializeSlot(ItemSlot slot) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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) GridItem val; string type; if (Utils.IsStation(slot.SlotOwner)) { val = Utils.CastTo<GridItem>((Il2CppObjectBase)(object)slot.SlotOwner); type = ((Object)val).name; } else { if (!Utils.IsStorageRack(slot.SlotOwner)) { Utils.Warn($"Couldn't serialize itemslot--not station or storage rack? ({Utils.GetType((Il2CppObjectBase)(object)slot.SlotOwner)})"); return null; } StorageEntity val2 = Utils.CastTo<StorageEntity>((Il2CppObjectBase)(object)slot.SlotOwner); val = ((Component)val2).gameObject.GetComponent<GridItem>(); type = val2.StorageEntityName; } string name = ((Object)((BuildableItem)val).ParentProperty).name; Vector2 gridLocation = (Vector2)Utils.GetField<GridItem>("_originCoordinate", val); return new SlotIdentifier(name, gridLocation, (int)Utils.GetProperty<ItemSlot>("SlotIndex", slot), type); } public static ItemSlot DeserializeSlot(SlotIdentifier identifier) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) try { List<Property> source = ((IEnumerable<Property>)Object.FindObjectsOfType<Property>()).ToList(); List<GridItem> list = ((IEnumerable<GridItem>)Object.FindObjectsOfType<GridItem>()).ToList(); Property property = ((IEnumerable<Property>)source).FirstOrDefault((Func<Property, bool>)((Property p) => ((Object)p).name == identifier.property)); List<GridItem> source2 = list.FindAll((GridItem g) => (Object)(object)((BuildableItem)g).ParentProperty == (Object)(object)property); Vector2 targetCoord = new Vector2(identifier.gridLocation[0], identifier.gridLocation[1]); GridItem val = ((IEnumerable<GridItem>)source2).FirstOrDefault((Func<GridItem, bool>)((GridItem g) => (Vector2)Utils.GetField<GridItem>("_originCoordinate", g) == targetCoord)); if ((Object)(object)val == (Object)null) { Utils.Warn("Couldn't deserialize slot--coordinates did not map to a griditem"); return null; } IItemSlotOwner val2; if (Utils.IsStation(val)) { val2 = Utils.ToInterface<IItemSlotOwner>((Il2CppObjectBase)(object)val); } else { if (!Utils.Is<PlaceableStorageEntity>((Il2CppObjectBase)(object)val)) { Utils.Warn($"couldn't deserialize slot--obj was not a station or placeablestorageentity ({Utils.GetType((Il2CppObjectBase)(object)val)})"); return null; } StorageEntity storageEntity = Utils.CastTo<PlaceableStorageEntity>((Il2CppObjectBase)(object)val).StorageEntity; val2 = Utils.ToInterface<IItemSlotOwner>((Il2CppObjectBase)(object)storageEntity); } return val2.ItemSlots[identifier.slotIndex]; } catch (Exception e) { Utils.PrintException(e); } return null; } public static void CompleteTransactions(List<Transaction> transactions) { try { foreach (Transaction transaction in transactions) { ItemSlot val = DeserializeSlot(transaction.slotID); if (val == null) { Utils.Warn("Couldn't deserialize slot!"); continue; } StorableItemInstance itemInstance = Utils.GetItemInstance(transaction.itemID, (EQuality)2); TryRestocking(val, itemInstance, transaction.quantity); } } catch (Exception e) { Utils.PrintException(e); } } public static void Initialize() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) try { melonPrefs = MelonPreferences.GetCategory("AutoRestock"); timeManager = NetworkSingleton<TimeManager>.Instance; moneyManager = NetworkSingleton<MoneyManager>.Instance; saveManager = Singleton<SaveManager>.Instance; ledgerDay = timeManager.CurrentDay; oscar = ((IEnumerable<NPC>)Object.FindObjectsOfType<NPC>(true)).FirstOrDefault((Func<NPC, bool>)((NPC npc) => npc.ID == "oscar_holland")); playerClickedSlot = null; playerStationOperationSlots = new List<ItemSlot>(); coroutines = new Dictionary<Transaction, object>(); exclusiveLock = new Mutex(); TimeManager obj = timeManager; obj.onDayPass += Action.op_Implicit((Action)OnDayPass); saveManager.onSaveStart.AddListener(Utils.ToUnityAction(OnSaveStart)); ledgerString = GetSaveString() + "_ledger"; transactionString = GetSaveString() + "_inprogress"; if (!melonPrefs.HasEntry(ledgerString)) { melonPrefs.CreateEntry<string>(ledgerString, "[]", "", true); } if (!melonPrefs.HasEntry(transactionString)) { melonPrefs.CreateEntry<string>(transactionString, "[]", "", true); } melonPrefs.LoadFromFile(false); ledger = JsonConvert.DeserializeObject<List<Transaction>>(melonPrefs.GetEntry<string>(ledgerString).Value); isInitialized = true; Utils.Log("AutoRestock manager initialized."); } catch (Exception e) { Utils.PrintException(e); } try { List<Transaction> list = JsonConvert.DeserializeObject<List<Transaction>>(melonPrefs.GetEntry<string>(transactionString).Value); if (list.Count > 0) { Utils.Log($"Completing {list.Count} pending transaction{((list.Count > 1) ? "s" : "")}."); CompleteTransactions(list); } } catch (Exception e2) { Utils.PrintException(e2); } } public static void Stop() { if (isInitialized) { isInitialized = false; ledger.Clear(); StopCoroutines(); exclusiveLock.Dispose(); } } public static void StopCoroutines() { if (!isInitialized) { return; } foreach (KeyValuePair<Transaction, object> coroutine in coroutines) { MelonCoroutines.Stop(coroutine.Value); } coroutines.Clear(); } public static void AcquireMutex() { if (isInitialized) { exclusiveLock.WaitOne(); } } public static void ReleaseMutex() { if (isInitialized) { exclusiveLock.ReleaseMutex(); } } public static bool ItemIsRestockable(string itemID) { //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) if (isInitialized) { List<string> list = new List<string>(4) { "Agriculture", "Consumable", "Ingredient", "Packaging" }; List<string> list2 = new List<string>(1) { "speedgrow" }; List<string> list3 = new List<string>(4) { "cocaleaf", "cocainebase", "liquidmeth", "shroomspawn" }; List<string> list4 = new List<string>(6) { "cocaseed", "granddaddypurpleseed", "greencrackseed", "ogkushseed", "sourdieselseed", "sporesyringe" }; ItemDefinition item = Registry.GetItem(itemID); EItemCategory category = item.Category; return (list.Contains(((object)(EItemCategory)(ref category)).ToString()) || list2.Contains(item.ID)) && !list3.Contains(item.ID); } return false; } public static void TryRestocking(ItemSlot slot, StorableItemInstance item, int quantity) { if (isInitialized && InstanceFinder.IsServer) { string iD = ((ItemInstance)item).ID; int num = Mathf.Max(melonPrefs.GetEntry<int>("restockAmount").Value, 0); int num2 = Mathf.Min((num == 0) ? quantity : num, ((ItemInstance)item).StackLimit); float num3 = Mathf.Clamp01(melonPrefs.GetEntry<float>("itemDiscount").Value); float num4 = ((ItemInstance)item).GetMonetaryValue() * 2f / (float)((ItemInstance)item).Quantity; float num5 = num4 * (float)num2 * (1f - num3); bool value = melonPrefs.GetEntry<bool>("payWithCash").Value; SlotIdentifier slotIdentifier = SerializeSlot(slot); try { if (((ItemInstance)item).StackLimit == 0) { Utils.Debug($"Stacklimit ({((ItemInstance)item).StackLimit}) == 0. Not restocking."); ((ItemInstance)item).RequestClearSlot(); } else if (ItemIsRestockable(((ItemInstance)item).ID)) { float num6 = (value ? moneyManager.cashBalance : moneyManager.onlineBalance); if (num6 < num5) { Utils.Log($"Can't afford to restock {num2}x {iD} (${num5})."); } else if (num6 >= num5) { AcquireMutex(); Transaction transaction = new Transaction(iD, num2, num3, num4, num5, value, slotIdentifier); ledger.Add(transaction); Utils.Debug($"Starting restock coroutine ({iD} x{num2} at {slotIdentifier.property})."); coroutines[transaction] = MelonCoroutines.Start(RestockCoroutine(slot, item, transaction)); ReleaseMutex(); } } return; } catch (Exception e) { Utils.PrintException(e); ReleaseMutex(); ((ItemInstance)item).RequestClearSlot(); return; } } Utils.Log("Tried to restock item, but Manager was not initialized!"); } private static IEnumerator RestockCoroutine(ItemSlot slot, StorableItemInstance item, Transaction transaction) { yield return (object)new WaitForEndOfFrame(); slot.ApplyLock(((NetworkBehaviour)oscar).NetworkObject, "Restocking item", false); slot.SetIsAddLocked(true); yield return (object)new WaitForSeconds(1f); int quantity; float totalCost; if (transaction.quantity + slot.Quantity > ((ItemInstance)item).StackLimit) { quantity = ((ItemInstance)item).StackLimit - slot.Quantity; totalCost = (int)((float)quantity * transaction.unitPrice * transaction.discount); AcquireMutex(); transaction.quantity = quantity; transaction.totalCost = totalCost; ReleaseMutex(); } else { quantity = transaction.quantity; totalCost = transaction.totalCost; } Utils.VerboseLog($"Restocking {((ItemInstance)item).Name} (${transaction.unitPrice}) x{quantity} with a discount of {transaction.discount} at {transaction.slotID.property}. Total: ${totalCost}."); bool didPay = false; if (totalCost <= 0f) { Utils.VerboseLog("Total cost of transaction is $0. Get a freebie!"); didPay = true; } else { bool useCash = melonPrefs.GetEntry<bool>("payWithCash").Value; float balance = (useCash ? moneyManager.cashBalance : moneyManager.onlineBalance); if (balance < totalCost) { Utils.Log($"Insufficient balance to restock {((ItemInstance)item).Name} (${transaction.unitPrice}) x{quantity} with a discount of {transaction.discount}, at {transaction.slotID.property}, total ${totalCost}; aborting."); ledger.Remove(transaction); } else { if (useCash) { moneyManager.ChangeCashBalance(0f - totalCost, true, false); } else { moneyManager.CreateOnlineTransaction("Restock", 0f - totalCost, 1f, ((ItemInstance)item).Definition.Name ?? ""); } didPay = true; } } slot.SetIsAddLocked(false); slot.RemoveLock(false); if (didPay && quantity > 0) { ((ItemInstance)item).SetQuantity(quantity); slot.AddItem((ItemInstance)(object)item, false); } AcquireMutex(); coroutines.Remove(transaction); ReleaseMutex(); } private static void OnDayPass() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //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) if (isInitialized && InstanceFinder.IsServer) { NetworkSingleton<MessagingManager>.Instance.SendMessage(new Message(GetReceipt(), (ESenderType)1, true, -1), true, oscar.ID); ledger.Clear(); ledgerDay = timeManager.CurrentDay; } } private static string GetSaveString() { string[] array = Singleton<LoadManager>.Instance.LoadedGameFolderPath.Split('\\'); return array[^2] + "_" + array[^1]; } public static void OnSaveStart() { if (isInitialized && InstanceFinder.IsServer) { string text = GetSaveString() + "_ledger"; if (melonPrefs.HasEntry(text)) { melonPrefs.GetEntry<string>(text).EditedValue = LedgerToJson(); } else { MelonPreferences_Entry val = melonPrefs.CreateEntry<string>(text, "", "", true); val.BoxedEditedValue = LedgerToJson(); } string text2 = GetSaveString() + "_inprogress"; if (melonPrefs.HasEntry(text2)) { melonPrefs.GetEntry<string>(text2).EditedValue = PendingTransactionsToJson(); } else { MelonPreferences_Entry val2 = melonPrefs.CreateEntry<string>(text2, "", "", true); val2.BoxedEditedValue = PendingTransactionsToJson(); } melonPrefs.SaveToFile(false); } } public static List<Transaction> GetPendingTransactions() { return coroutines.Keys.ToList(); } public static string PendingTransactionsToJson() { return JsonConvert.SerializeObject((object)GetPendingTransactions()); } public static float LedgerTotal() { return ledger.Aggregate(0f, (float accum, Transaction transaction) => accum + transaction.totalCost); } public static string LedgerToJson() { return JsonConvert.SerializeObject((object)ledger); } private static string GetReceipt() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (isInitialized) { string text = $"Restock receipt for {ledgerDay}:\n\n"; float num = 0f; if (ledger.Count > 0) { Dictionary<string, Dictionary<string, float>> dictionary = new Dictionary<string, Dictionary<string, float>>(); Dictionary<string, Dictionary<string, int>> dictionary2 = new Dictionary<string, Dictionary<string, int>>(); Dictionary<string, float> dictionary3 = new Dictionary<string, float>(); Dictionary<string, float> dictionary4 = new Dictionary<string, float>(); foreach (Transaction item in ledger) { if (!dictionary.ContainsKey(item.slotID.property)) { dictionary[item.slotID.property] = new Dictionary<string, float>(); } if (!dictionary[item.slotID.property].ContainsKey(item.itemID)) { dictionary[item.slotID.property][item.itemID] = 0f; } if (!dictionary2.ContainsKey(item.slotID.property)) { dictionary2[item.slotID.property] = new Dictionary<string, int>(); } if (!dictionary2[item.slotID.property].ContainsKey(item.itemID)) { dictionary2[item.slotID.property][item.itemID] = 0; } dictionary2[item.slotID.property][item.itemID] += item.quantity; dictionary[item.slotID.property][item.itemID] += item.totalCost; dictionary3[item.itemID] = item.unitPrice; } foreach (string key2 in dictionary.Keys) { float num2 = 0f; text = text + key2 + ": \n"; foreach (KeyValuePair<string, int> item2 in dictionary2[key2]) { string key = item2.Key; float value = item2.Value; float num3 = dictionary[key2][key]; string name = Registry.GetItem(key).Name; text += $" {name} x{value} = ${num3}\n"; num2 += num3; } text += "=====================\n"; text += $" Property total: ${num2}\n\n"; num += num2; } } text += "=====================\n"; text += $" Grand total: ${num}\n\n"; return text + "Oscar says thank you for your business! :)"; } return "AutoRestock not initialized!"; } } [HarmonyPatch] public class PersistencePatches { [HarmonyPatch(typeof(LoadingScreen), "Close")] [HarmonyPostfix] public static void ClosePostfix(LoadingScreen __instance) { if (InstanceFinder.IsServer && !Manager.isInitialized) { Manager.Initialize(); } } [HarmonyPatch(typeof(LoadManager), "ExitToMenu")] [HarmonyPrefix] public static void ExitToMenuPrefix(LoadManager __instance) { if (InstanceFinder.IsServer && Manager.isInitialized) { Manager.Stop(); } } } [HarmonyPatch] public class CauldronPatches { [HarmonyPatch(typeof(Cauldron), "RemoveIngredients")] [HarmonyPrefix] public static void RemoveIngredientsPrefix(Cauldron __instance) { if (!InstanceFinder.IsServer || !Manager.isInitialized) { return; } try { if (Manager.melonPrefs.GetEntry<bool>("enableCauldrons").Value && __instance.LiquidSlot.ItemInstance.Quantity <= 1 && (Manager.melonPrefs.GetEntry<bool>("playerRestockStations").Value || (Object)(object)__instance.PlayerUserObject == (Object)null)) { StorableItemInstance val = Utils.CastTo<StorableItemInstance>((Il2CppObjectBase)(object)__instance.LiquidSlot.ItemInstance.GetCopy(-1)); Manager.TryRestocking(__instance.LiquidSlot, val, ((ItemInstance)val).StackLimit); } } catch (Exception e) { Utils.Warn(MethodBase.GetCurrentMethod().DeclaringType.Name + ":"); Utils.PrintException(e); } } } [HarmonyPatch] public class MixingStationPatches { [HarmonyPatch(typeof(MixingStation), "SendMixingOperation")] [HarmonyPrefix] public static void SendMixingOperationPrefix(MixingStation __instance, MixOperation operation) { if (!InstanceFinder.IsServer || !Manager.isInitialized) { return; } try { if (Manager.melonPrefs.GetEntry<bool>("enableMixingStations").Value) { float value = Utils.GetProperty<MixingStation, MixingStationConfiguration>("stationConfiguration", __instance).StartThrehold.GetData().Value; if (!((float)(__instance.MixerSlot.Quantity - operation.Quantity) >= value) && (Manager.melonPrefs.GetEntry<bool>("playerRestockStations").Value || (Object)(object)__instance.PlayerUserObject == (Object)null)) { StorableItemInstance itemInstance = Utils.GetItemInstance(operation.IngredientID, (EQuality)2); Manager.TryRestocking(__instance.MixerSlot, itemInstance, ((ItemInstance)itemInstance).StackLimit); } } } catch (Exception e) { Utils.Warn(MethodBase.GetCurrentMethod().DeclaringType.Name + ":"); Utils.PrintException(e); } } } [HarmonyPatch] public class PackagingStationPatches { [HarmonyPatch(typeof(PackagingStation), "PackSingleInstance")] [HarmonyPrefix] public static void PackSingleInstancePrefix(PackagingStation __instance) { if (!InstanceFinder.IsServer || !Manager.isInitialized) { return; } try { if (Manager.melonPrefs.GetEntry<bool>("enablePackagingStations").Value && __instance.PackagingSlot.ItemInstance != null && __instance.PackagingSlot.ItemInstance.Quantity <= 1 && (Manager.melonPrefs.GetEntry<bool>("playerRestockStations").Value || (Object)(object)__instance.PlayerUserObject == (Object)null)) { StorableItemInstance val = Utils.CastTo<StorableItemInstance>((Il2CppObjectBase)(object)__instance.PackagingSlot.ItemInstance.GetCopy(1)); Manager.TryRestocking(__instance.PackagingSlot, val, ((ItemInstance)val).StackLimit); } } catch (Exception e) { Utils.Warn(MethodBase.GetCurrentMethod().DeclaringType.Name + ":"); Utils.PrintException(e); } } } [HarmonyPatch] public class ChemistryStationPatches { private static List<List<T>> Permute<T>(List<T> nums) { List<List<T>> list = new List<List<T>>(); return DoPermute(nums, 0, nums.Count - 1, list); } private static List<List<T>> DoPermute<T>(List<T> nums, int start, int end, List<List<T>> list) { if (start == end) { list.Add(new List<T>(nums)); } else { for (int i = start; i <= end; i++) { Swap(nums, start, i); DoPermute(nums, start + 1, end, list); Swap(nums, start, i); } } return list; } private static void Swap<T>(List<T> list, int index1, int index2) { T value = list[index1]; list[index1] = list[index2]; list[index2] = value; } [HarmonyPatch(typeof(ChemistryStation), "SendCookOperation")] [HarmonyPrefix] public static bool SendCookOperationPrefix(ChemistryStation __instance, ChemistryCookOperation op) { //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) if (!InstanceFinder.IsServer || !Manager.isInitialized) { return true; } try { if (!Manager.melonPrefs.GetEntry<bool>("enableChemistryStations").Value) { return true; } if (Manager.melonPrefs.GetEntry<bool>("playerRestockStations").Value || (Object)(object)__instance.PlayerUserObject == (Object)null) { List<ItemDefinition> list2 = new List<ItemDefinition>(); Enumerator<IngredientQuantity> enumerator = op.Recipe.Ingredients.GetEnumerator(); while (enumerator.MoveNext()) { IngredientQuantity i = enumerator.Current; if (!((IEnumerable<ItemSlot>)__instance.IngredientSlots).Any((ItemSlot slot) => slot.ItemInstance != null && slot.ItemInstance.Definition.Name.Contains(i.Item.Name))) { list2.Add(i.Item); } } List<List<ItemDefinition>> list3 = new List<List<ItemDefinition>>(); List<List<ItemDefinition>> list4 = new List<List<ItemDefinition>>(); if (list2.Count > 0) { List<ItemSlot> emptySlots = new List<ItemSlot>(); foreach (ItemSlot item in (Il2CppArrayBase<ItemSlot>)(object)__instance.IngredientSlots) { if (item.Quantity == 0) { emptySlots.Add(item); } } list3 = Permute(list2); list4 = list3.Select(delegate(List<ItemDefinition> mapping) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) bool flag = true; for (int j = 0; j < mapping.Count; j++) { ItemInstance itemInstance2 = (ItemInstance)(object)Utils.GetItemInstance(mapping[j].ID, op.ProductQuality); if (!emptySlots[j].DoesItemMatchPlayerFilters(itemInstance2)) { flag = false; break; } } return flag ? mapping : null; }).ToList(); list4.RemoveAll((List<ItemDefinition> list) => list == null); if (list4.Count == 0) { string name = ((Object)((BuildableItem)__instance).ParentProperty).name; Vector2 val = (Vector2)Utils.GetField<GridItem>("_originCoordinate", __instance); Utils.Log($"Couldn't restock {((BuildableItem)__instance).GetManagementName()} at {name}({val.x}, {val.y}) because items do not agree with filters."); return true; } } int num = 0; foreach (ItemSlot item2 in (Il2CppArrayBase<ItemSlot>)(object)__instance.IngredientSlots) { if (item2.ItemInstance == null && list2.Count > 0) { ItemDefinition val2 = list4[0][num]; StorableItemInstance itemInstance = Utils.GetItemInstance(val2.ID, op.ProductQuality); Manager.TryRestocking(item2, itemInstance, ((ItemInstance)itemInstance).StackLimit); num++; continue; } int num2 = 0; Enumerator<IngredientQuantity> enumerator4 = op.Recipe.Ingredients.GetEnumerator(); while (enumerator4.MoveNext()) { IngredientQuantity current3 = enumerator4.Current; if (item2.ItemInstance.Definition.Name.Contains(current3.Item.Name)) { num2 = current3.Quantity; break; } } if (num2 > 0 && item2.ItemInstance.Quantity < num2) { StorableItemInstance val3 = Utils.CastTo<StorableItemInstance>((Il2CppObjectBase)(object)item2.ItemInstance.GetCopy(1)); Manager.TryRestocking(item2, val3, ((ItemInstance)val3).StackLimit); } } } } catch (Exception e) { Utils.Warn(MethodBase.GetCurrentMethod().DeclaringType.Name + ":"); Utils.PrintException(e); } return true; } } [HarmonyPatch] public class StorageEntityPatches { [HarmonyPatch(typeof(ItemUIManager), "Update")] [HarmonyPrefix] public static void UpdatePrefix(ItemUIManager __instance) { if (__instance.DraggingEnabled) { ItemSlotUI val = Utils.CallMethod<ItemUIManager, ItemSlotUI>("GetHoveredItemSlot", __instance); ItemSlotUI field = Utils.GetField<ItemUIManager, ItemSlotUI>("draggedSlot", __instance); if ((Object)(object)field == (Object)null && (Object)(object)val != (Object)null && (GameInput.GetButtonDown((ButtonCode)0) || GameInput.GetButtonDown((ButtonCode)1) || GameInput.GetButtonDown((ButtonCode)2)) && Manager.playerClickedSlot == null) { Manager.playerClickedSlot = val.assignedSlot; } } } [HarmonyPatch(typeof(ItemUIManager), "Update")] [HarmonyPostfix] public static void UpdatePostfix(ItemUIManager __instance) { if (__instance.DraggingEnabled) { ItemSlotUI field = Utils.GetField<ItemUIManager, ItemSlotUI>("draggedSlot", __instance); if ((Object)(object)field == (Object)null && Manager.playerClickedSlot != null) { Manager.playerClickedSlot = null; } } } [HarmonyPatch(typeof(ItemSlot), "ChangeQuantity")] [HarmonyPrefix] public static void ChangeQuantityPrefix(ItemSlot __instance, ref int change) { if (!InstanceFinder.IsServer || !Manager.isInitialized) { return; } try { if (__instance.ItemInstance != null && __instance.Quantity + change <= 0 && Manager.melonPrefs.GetEntry<bool>("enableStorage").Value && Manager.playerClickedSlot != __instance && Utils.IsStorageRack(__instance.SlotOwner)) { StorableItemInstance val = Utils.CastTo<StorableItemInstance>((Il2CppObjectBase)(object)__instance.ItemInstance.GetCopy(1)); Manager.TryRestocking(__instance, val, ((ItemInstance)val).StackLimit); } } catch (Exception e) { Utils.Warn(MethodBase.GetCurrentMethod().DeclaringType.Name + ":"); Utils.PrintException(e); } } } [HarmonyPatch] public class SpawnStationPatches { [HarmonyPatch(typeof(InocculateGrainBagTask), "Success")] [HarmonyPostfix] public static void SuccessPostfix(InocculateGrainBagTask __instance) { MushroomSpawnStation field = Utils.GetField<InocculateGrainBagTask, MushroomSpawnStation>("_station", __instance); if (field.GrainBagSlot.Quantity == 0 && Manager.melonPrefs.GetEntry<bool>("enableSpawnStations").Value && Manager.melonPrefs.GetEntry<bool>("playerRestockStations").Value) { StorableItemInstance itemInstance = Utils.GetItemInstance("grainbag", (EQuality)2); Manager.TryRestocking(field.GrainBagSlot, itemInstance, ((ItemInstance)itemInstance).StackLimit); } if (field.SyringeSlot.Quantity == 0 && Manager.melonPrefs.GetEntry<bool>("enableSpawnStations").Value && Manager.melonPrefs.GetEntry<bool>("playerRestockStations").Value) { StorableItemInstance itemInstance2 = Utils.GetItemInstance("sporesyringe", (EQuality)2); Manager.TryRestocking(field.SyringeSlot, itemInstance2, ((ItemInstance)itemInstance2).StackLimit); } } [HarmonyPatch(typeof(UseSpawnStationBehaviour), "StopWork")] [HarmonyPrefix] public static void StopWorkPrefix(UseSpawnStationBehaviour __instance) { if (__instance.Station.GrainBagSlot.Quantity == 0 && Manager.melonPrefs.GetEntry<bool>("enableSpawnStations").Value) { StorableItemInstance itemInstance = Utils.GetItemInstance("grainbag", (EQuality)2); Manager.TryRestocking(__instance.Station.GrainBagSlot, itemInstance, ((ItemInstance)itemInstance).StackLimit); } if (__instance.Station.SyringeSlot.Quantity == 0 && Manager.melonPrefs.GetEntry<bool>("enableSpawnStations").Value) { StorableItemInstance itemInstance2 = Utils.GetItemInstance("sporesyringe", (EQuality)2); Manager.TryRestocking(__instance.Station.SyringeSlot, itemInstance2, ((ItemInstance)itemInstance2).StackLimit); } } } } internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { int IReadOnlyCollection<T>.Count => _items.Length; T IReadOnlyList<T>.this[int index] => _items[index]; int ICollection<T>.Count => _items.Length; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return ((ICollection<T>)_items).Contains(item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { ((ICollection<T>)_items).CopyTo(array, arrayIndex); } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { return ((IList<T>)_items).IndexOf(item); } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } }