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.4
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.Text; 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 Il2CppSteamworks; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using SteamNetworkLib; using SteamNetworkLib.Core; using SteamNetworkLib.Events; using SteamNetworkLib.Models; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [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.4", "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.4.0")] [assembly: AssemblyInformationalVersion("1.1.4+4dd118c207a21269f16ad14e49014ccf6526e36e")] [assembly: AssemblyProduct("AutoRestockIL2CPP")] [assembly: AssemblyTitle("AutoRestockIL2CPP")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.4.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 SteamNetworkClient client; public CSteamID host; public CSteamID self; public Dictionary<CSteamID, string> steamIDToDisplayName; public override void OnInitializeMelon() { CreateMelonPreferences(); Utils.Initialize(this); ((MelonBase)this).LoggerInstance.Msg("Mod initialized."); } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown ((MelonMod)this).OnSceneWasInitialized(buildIndex, sceneName); if (!sceneName.ToLower().Contains("menu") || client != null) { return; } NetworkRules val = new NetworkRules { EnableRelay = true, DefaultSendType = (EP2PSend)2, AcceptOnlyFriends = false, MinReceiveChannel = 0, MaxReceiveChannel = 3 }; client = new SteamNetworkClient(val); if (!client.Initialize()) { return; } client.OnLobbyCreated += delegate(object? s, LobbyCreatedEventArgs e) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) Utils.Debug($"Lobby created: {e.Lobby.LobbyId}"); }; client.OnLobbyJoined += delegate(object? s, LobbyJoinedEventArgs e) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) Utils.Debug($"Joined lobby {e.Lobby.LobbyId}"); host = ((IEnumerable<MemberInfo>)client.GetLobbyMembers()).FirstOrDefault((Func<MemberInfo, bool>)((MemberInfo member) => member.IsOwner)).SteamId; self = ((IEnumerable<MemberInfo>)client.GetLobbyMembers()).FirstOrDefault((Func<MemberInfo, bool>)((MemberInfo member) => member.IsLocalPlayer)).SteamId; steamIDToDisplayName = new Dictionary<CSteamID, string>(client.GetLobbyMembers().ConvertAll((MemberInfo member) => new KeyValuePair<CSteamID, string>(member.SteamId, member.DisplayName))); }; client.OnMemberJoined += delegate(object? s, MemberJoinedEventArgs e) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) steamIDToDisplayName[e.Member.SteamId] = e.Member.DisplayName; }; client.OnP2PMessageReceived += delegate(object? s, P2PMessageReceivedEventArgs e) { //IL_0046: 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) Utils.Debug($"Received P2P {e.Message.MessageType.ToLower()} message from {steamIDToDisplayName[e.SenderId]}."); if (e.Message.MessageType == "TRANSACTION") { Utils.TransactionMessage transactionMessage = (Utils.TransactionMessage)(object)e.Message; Manager.Transaction payload = transactionMessage.Payload; Utils.Debug("Transaction: " + payload.ToString()); } if (e.Message.MessageType == "TEXT") { Utils.Debug("Text msg: " + ((TextMessage)e.Message).Content); } }; Utils.LateInitialize(); } public override void OnUpdate() { ((MelonBase)this).OnUpdate(); SteamNetworkClient obj = client; if (obj != null) { obj.ProcessIncomingMessages(); } } public override void OnDeinitializeMelon() { ((MelonBase)this).OnDeinitializeMelon(); SteamNetworkClient obj = client; if (obj != null) { obj.Dispose(); } } 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 TransactionMessage : P2PMessage { public override string MessageType => "TRANSACTION"; public Manager.Transaction Payload { get; set; } = null; public override byte[] Serialize() { string s = JsonConvert.SerializeObject((object)Payload); return Encoding.UTF8.GetBytes(s); } public override void Deserialize(byte[] data) { try { string @string = Encoding.UTF8.GetString(data); Payload = JsonConvert.DeserializeObject<Manager.Transaction>(@string); } catch (Exception e) { Warn("deserializing failed:"); PrintException(e); } } } 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; private static Dictionary<EQuality, string> qualityStrings = new Dictionary<EQuality, string> { { (EQuality)4, "heavenly" }, { (EQuality)3, "highquality" }, { (EQuality)2, "" }, { (EQuality)1, "lowquality" }, { (EQuality)0, "trash" } }; public static void Initialize(AutoRestockMod mod) { Mod = mod; S1Assembly = AppDomain.CurrentDomain.GetAssemblies().First((Assembly a) => a.GetName().Name == "Assembly-CSharp"); } public static void LateInitialize() { if (Mod.client != null) { Mod.client.RegisterMessageHandler<TransactionMessage>((Action<TransactionMessage, CSteamID>)ReceiveTransaction); } else { Warn("Client was null; couldn't register transaction message handler"); } } 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 string GetQualityItemID(QualityItemInstance item) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return qualityStrings[item.Quality] + ((ItemInstance)item).ID; } public static QualityItemInstance GetQualityItemInstance(string itemID, EQuality quality) { //IL_0011: 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) if (IsQualityIngredient(itemID)) { string text = qualityStrings[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>(9) { "safe", "wallmountedshelf", "smallstoragerack", "mediumstoragerack", "largestoragerack", "smallstoragecloset", "mediumstoragecloset", "largestoragecloset", "hugestoragecloset" }; 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 string SteamIDToDisplayName(CSteamID steamID) { //IL_000b: 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_0020: Unknown result type (might be due to invalid IL or missing references) if (Mod.steamIDToDisplayName.ContainsKey(steamID)) { return Mod.steamIDToDisplayName[steamID]; } return $"{steamID}"; } public static void ReceiveTransaction(TransactionMessage transactionMessage, CSteamID sender) { if (!Manager.isInitialized) { Warn("Couldn't process transaction, Manager is not initialized!"); return; } Manager.Transaction payload = transactionMessage.Payload; StorableItemInstance itemInstance = GetItemInstance(payload.itemID, (EQuality)2); ItemSlot val = Manager.DeserializeSlot(payload.slotID); if (val == null) { Warn("Couldn't resolve itemslot; aborting..."); } else { Manager.TryRestocking(val, itemInstance, payload.quantity); } } public static void ReceiveTextTransaction(TextMessage message, CSteamID sender) { try { Manager.Transaction transaction = JsonConvert.DeserializeObject<Manager.Transaction>(message.Content); if (transaction == null) { Warn("Couldn't deserialize json: " + message.Content); return; } StorableItemInstance itemInstance = GetItemInstance(transaction.itemID, (EQuality)2); ItemSlot val = Manager.DeserializeSlot(transaction.slotID); if (val == null) { Warn("Couldn't resolve itemslot; aborting..."); } else { Manager.TryRestocking(val, itemInstance, transaction.quantity); } } catch (Exception e) { PrintException(e); } } public static void SendTransaction(Manager.Transaction transaction) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) TransactionMessage transactionMessage = new TransactionMessage { Payload = transaction }; SteamNetworkClient client = Mod.client; if (client != null) { client.SendMessageToPlayerAsync(Mod.host, (P2PMessage)(object)transactionMessage); } } public static List<T> ListConvert<T>(List<T> list) { List<T> list2 = new List<T>(); Enumerator<T> enumerator = list.GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; list2.Add(current); } return list2; } } public static class Manager { public class Transaction { public string itemID; public int quality; public int quantity; public float discount; public float unitPrice; public float totalCost; public bool useCash; public SlotIdentifier slotID; public Transaction(string itemID, EQuality quality, int quantity, float discount, float unitPrice, float totalCost, bool useCash, SlotIdentifier slotID) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected I4, but got Unknown this.itemID = itemID; this.quality = (int)quality; this.quantity = quantity; this.discount = discount; this.unitPrice = unitPrice; this.totalCost = totalCost; this.useCash = useCash; this.slotID = slotID; } public override string ToString() { return $"{itemID} x{quantity} for {slotID.ToString()}"; } } public class SlotIdentifier { public List<float> gridLocation; public string type; public int slotIndex; public string property; public string grid; public SlotIdentifier(string property, Vector2 gridLocation, int slotIndex, string type, string grid) { //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; this.grid = grid; } [JsonConstructor] public SlotIdentifier(string property, List<float> gridLocation, int slotIndex, string type, string grid) { this.property = property; this.gridLocation = gridLocation; this.slotIndex = slotIndex; this.type = type; this.grid = grid; } public override string ToString() { return $"{type} slot {slotIndex} at {property} ({grid}: {gridLocation[0]}, {gridLocation[1]})"; } } public static bool isClient; public static ItemSlot playerClickedSlot; public static bool doRestockPlayerClickedSlot; 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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) GridItem val; if (Utils.IsStation(slot.SlotOwner)) { val = Utils.CastTo<GridItem>((Il2CppObjectBase)(object)slot.SlotOwner); } 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>(); } string iD = ((BuildableItem)val).ItemInstance.Definition.ID; string name = ((Object)((BuildableItem)val).ParentProperty).name; string name2 = ((Object)val.OwnerGrid).name; Vector2 gridLocation = (Vector2)Utils.GetField<GridItem>("_originCoordinate", val); int slotIndex = (int)Utils.GetProperty<ItemSlot>("SlotIndex", slot); return new SlotIdentifier(name, gridLocation, slotIndex, iD, name2); } public static ItemSlot DeserializeSlot(SlotIdentifier identifier) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) try { List<Property> source = ((IEnumerable<Property>)Object.FindObjectsOfType<Property>()).ToList(); Property val = ((IEnumerable<Property>)source).FirstOrDefault((Func<Property, bool>)((Property p) => ((Object)p).name == identifier.property && p.Grids.Count > 0)); List<BuildableItem> source2 = Utils.ListConvert<BuildableItem>(val.BuildableItems); Vector2 targetCoord = new Vector2(identifier.gridLocation[0], identifier.gridLocation[1]); BuildableItem val2 = ((IEnumerable<BuildableItem>)source2).FirstOrDefault((Func<BuildableItem, bool>)delegate(BuildableItem b) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (Utils.Is<GridItem>((Il2CppObjectBase)(object)b)) { GridItem val5 = Utils.CastTo<GridItem>((Il2CppObjectBase)(object)b); return (Vector2)Utils.GetField<GridItem>("_originCoordinate", val5) == targetCoord && ((Object)val5.OwnerGrid).name == identifier.grid; } return false; }); if ((Object)(object)val2 == (Object)null) { Utils.Warn("Couldn't deserialize slot--coordinates did not map to a griditem"); return null; } GridItem val3 = Utils.CastTo<GridItem>((Il2CppObjectBase)(object)val2); IItemSlotOwner val4; if (Utils.IsStation(val3)) { val4 = Utils.ToInterface<IItemSlotOwner>((Il2CppObjectBase)(object)val3); } else { if (!Utils.Is<PlaceableStorageEntity>((Il2CppObjectBase)(object)val3)) { Utils.Warn($"couldn't deserialize slot--obj was not a station or placeablestorageentity ({Utils.GetType((Il2CppObjectBase)(object)val3)})"); return null; } StorageEntity storageEntity = Utils.CastTo<PlaceableStorageEntity>((Il2CppObjectBase)(object)val3).StorageEntity; val4 = Utils.ToInterface<IItemSlotOwner>((Il2CppObjectBase)(object)storageEntity); } if (val4.ItemSlots.Count <= identifier.slotIndex) { Utils.Warn($"couldn't deserialize slot--slot index was greater than itemslot count ({identifier.slotIndex} > {val4.ItemSlots.Count})"); return null; } return val4.ItemSlots[identifier.slotIndex]; } catch (Exception e) { Utils.PrintException(e); } return null; } public static Transaction CreateTransaction(ItemSlot slot, ItemInstance item, int quantity) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) string iD = item.ID; EQuality quality = ((!Utils.Is<QualityItemInstance>((Il2CppObjectBase)(object)item)) ? ((EQuality)2) : Utils.CastTo<QualityItemInstance>((Il2CppObjectBase)(object)item).Quality); int num = Mathf.Max(melonPrefs.GetEntry<int>("restockAmount").Value, 0); int num2 = Mathf.Min((num == 0) ? quantity : num, item.StackLimit); float num3 = Mathf.Clamp01(melonPrefs.GetEntry<float>("itemDiscount").Value); float num4 = item.GetMonetaryValue() * 2f / (float)item.Quantity; float totalCost = num4 * (float)num2 * (1f - num3); bool value = melonPrefs.GetEntry<bool>("payWithCash").Value; SlotIdentifier slotID = SerializeSlot(slot); return new Transaction(iD, quality, num2, num3, num4, totalCost, value, slotID); } 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; doRestockPlayerClickedSlot = false; 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)); if (InstanceFinder.IsServer) { 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 { if (InstanceFinder.IsServer) { 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) { Transaction transaction = CreateTransaction(slot, (ItemInstance)(object)item, quantity); 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 num = (transaction.useCash ? moneyManager.cashBalance : moneyManager.onlineBalance); if (num < transaction.totalCost) { Utils.Log($"Can't afford to restock {transaction.quantity}x {transaction.itemID} (${transaction.totalCost})."); } else if (num >= transaction.totalCost) { AcquireMutex(); ledger.Add(transaction); coroutines[transaction] = MelonCoroutines.Start(RestockCoroutine(transaction)); ReleaseMutex(); } } return; } catch (Exception e) { Utils.PrintException(e); ReleaseMutex(); return; } } Utils.Log("Tried to restock item, but Manager was not initialized!"); } private static IEnumerator RestockCoroutine(Transaction transaction) { yield return (object)new WaitForEndOfFrame(); ItemSlot slot = DeserializeSlot(transaction.slotID); slot.ApplyLock(((NetworkBehaviour)oscar).NetworkObject, "Restocking item", false); slot.SetIsAddLocked(true); yield return (object)new WaitForSeconds(1f); StorableItemInstance item = Utils.GetItemInstance(transaction.itemID, (EQuality)2); if (Utils.Is<QualityItemInstance>((Il2CppObjectBase)(object)item)) { Utils.CastTo<QualityItemInstance>((Il2CppObjectBase)(object)item).Quality = (EQuality)transaction.quality; } 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) { if (quantity > 0) { 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."); AcquireMutex(); ledger.Remove(transaction); ReleaseMutex(); } 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 (!Manager.isInitialized) { Manager.Initialize(); } } [HarmonyPatch(typeof(LoadManager), "ExitToMenu")] [HarmonyPrefix] public static void ExitToMenuPrefix(LoadManager __instance) { if (Manager.isInitialized) { Manager.Stop(); } } } [HarmonyPatch] public class CauldronPatches { [HarmonyPatch(typeof(Cauldron), "RemoveIngredients")] [HarmonyPrefix] public static void RemoveIngredientsPrefix(Cauldron __instance) { if (!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 (!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 (!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_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: 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_0264: Unknown result type (might be due to invalid IL or missing references) if (!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) { return; } 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; if (((ButtonControl)Keyboard.current.leftCtrlKey).isPressed) { Manager.doRestockPlayerClickedSlot = true; } } } [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; Manager.doRestockPlayerClickedSlot = false; } } } [HarmonyPatch(typeof(ItemSlot), "ChangeQuantity")] [HarmonyPrefix] public static void ChangeQuantityPrefix(ItemSlot __instance, ref int change) { if (!Manager.isInitialized) { return; } try { if (__instance.ItemInstance != null && __instance.Quantity + change <= 0 && Manager.melonPrefs.GetEntry<bool>("enableStorage").Value && Utils.IsStorageRack(__instance.SlotOwner) && ((Manager.playerClickedSlot == __instance && Manager.doRestockPlayerClickedSlot) || Manager.playerClickedSlot != __instance)) { StorableItemInstance val = Utils.CastTo<StorableItemInstance>((Il2CppObjectBase)(object)__instance.ItemInstance.GetCopy(1)); if (!InstanceFinder.IsServer) { Manager.Transaction transaction = Manager.CreateTransaction(__instance, __instance.ItemInstance, __instance.ItemInstance.StackLimit); Utils.SendTransaction(transaction); } else { Manager.TryRestocking(__instance, Utils.CastTo<StorableItemInstance>((Il2CppObjectBase)(object)__instance.ItemInstance), __instance.ItemInstance.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(); } }