Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of OscarsInventoryTweaksMono v1.2.0
Mods/OscarsInventoryTweaks.Mono.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Fxcpds; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using OscarsInventoryTweaks; using ScheduleOne; using ScheduleOne.Core.Items.Framework; using ScheduleOne.NPCs; using ScheduleOne.NPCs.CharacterClasses; using ScheduleOne.PlayerScripts; using ScheduleOne.UI.Shop; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: MelonInfo(typeof(Mod), "Oscar's Inventory Tweaks", "1.2.0", "Foxcapades", null)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("OscarsInventoryTweaks")] [assembly: AssemblyConfiguration("Mono")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+7d32857f571070ba18933c47e913d0f34ddd7d5d")] [assembly: AssemblyProduct("OscarsInventoryTweaks")] [assembly: AssemblyTitle("OscarsInventoryTweaks")] [assembly: AssemblyVersion("1.0.0.0")] 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; } } } namespace Fxcpds { public abstract class FxMod : MelonMod { protected const string SCENE_NAME_MAIN = "Main"; private static FxMod? instance; public static FxMod Instance => instance; protected string Scene { get; private set; } = ""; public bool InMainScene { get; private set; } protected virtual string? configPath { get; } public string? ConfigPath => (configPath == null) ? null : Path.Combine(MelonEnvironment.UserDataDirectory, configPath); public override void OnEarlyInitializeMelon() { instance = this; } public override void OnInitializeMelon() { Player.onPlayerSpawned = (Action<Player>)Delegate.Combine(Player.onPlayerSpawned, new Action<Player>(onPlayerSpawned)); } public override void OnSceneWasLoaded(int _, string sceneName) { Scene = sceneName; if (sceneName == "Main") { InMainScene = true; onMainLoaded(); } } public override void OnSceneWasInitialized(int _, string sceneName) { if (sceneName == "Main") { onMainInitialized(); } } public override void OnSceneWasUnloaded(int _, string sceneName) { if (Scene == sceneName) { Scene = ""; } if (sceneName == "Main") { InMainScene = false; onMainUnloaded(); } } public sealed override void OnPreferencesSaved(string filepath) { if (configPath != null && filepath.EndsWith(configPath)) { ((MelonBase)this).LoggerInstance.Debug("calling onModPreferencesSaved()"); onModPreferencesSaved(); } } public override void OnPreferencesLoaded(string filepath) { if (configPath != null && filepath.EndsWith(configPath)) { ((MelonBase)this).LoggerInstance.Debug("calling onModPreferencesLoaded()"); onModPreferencesSaved(); } } protected virtual void onModPreferencesSaved() { } protected virtual void onModPreferencesLoaded() { } private void onPlayerSpawned(Player player) { if (player.IsLocalPlayer) { ((MelonBase)this).LoggerInstance.Debug("local player loaded"); onLocalPlayerLoaded(player); } onPlayerLoaded(player); } protected virtual void onPlayerLoaded(Player player) { } protected virtual void onLocalPlayerLoaded(Player player) { } protected virtual void onMainLoaded() { } protected virtual void onMainInitialized() { } protected virtual void onMainUnloaded() { } } internal static class DebugTools { public static void Debug(this Instance logger, string message) { } public static void Debug(this Instance logger, string message, object? a1) { } } public static class Interop { public static T? cast<T>(Object? obj) where T : Object { return (obj == (Object)null) ? default(T) : ((T)(object)obj); } } public static class NPC { public const string Oscar = "oscar_holland"; public const string Dan = "dan_samwell"; public const string Hank = "hank_stevenson"; public static T? Get<T>(string id) where T : NPC { return Interop.cast<T>((Object?)(object)NPCManager.GetNPC(id)); } } } namespace OscarsInventoryTweaks { internal readonly struct Category { public static readonly Category Additives = new Category("Additives", "extralonglifesoil"); public static readonly Category Storage = new Category("Storage", "bed"); public static readonly Category Equipment = new Category("Growing", "soilpourer"); public static readonly Category[] allCategories = new Category[3] { Additives, Storage, Equipment }; public readonly string name; public readonly string appearsAfter; private Category(string name, string appearsAfter) { this.name = name; this.appearsAfter = appearsAfter; } public override bool Equals(object? obj) { return obj != null && (obj as Category?)?.name == name; } public override int GetHashCode() { return name.GetHashCode(); } public static bool operator ==(Category a, Category b) { return a.name == b.name; } public static bool operator !=(Category a, Category b) { return a.name != b.name; } } internal readonly struct Item { public static readonly Item Fertilizer = new Item("fertilizer", Category.Additives); public static readonly Item PGR = new Item("pgr", Category.Additives); public static readonly Item SpeedGrow = new Item("speedgrow", Category.Additives); public static readonly Item Locker = new Item("locker", Category.Storage); public static readonly Item SmallStorageCloset = new Item("smallstoragecloset", Category.Storage); public static readonly Item MediumStorageCloset = new Item("mediumstoragecloset", Category.Storage); public static readonly Item LargeStorageCloset = new Item("largestoragecloset", Category.Storage); public static readonly Item HugeStorageCloset = new Item("hugestoragecloset", Category.Storage); public static readonly Item SmallStorageRack = new Item("smallstoragerack", Category.Storage); public static readonly Item MediumStorageRack = new Item("mediumstoragerack", Category.Storage); public static readonly Item LargeStorageRack = new Item("largestoragerack", Category.Storage); public static readonly Item BigSprinkler = new Item("bigsprinkler", Category.Equipment); public static readonly Item AirConditioner = new Item("acunit", Category.Equipment); public static readonly Item[] allItems = new Item[13] { Fertilizer, PGR, SpeedGrow, Locker, BigSprinkler, AirConditioner, SmallStorageCloset, MediumStorageCloset, LargeStorageCloset, HugeStorageCloset, SmallStorageRack, MediumStorageRack, LargeStorageRack }; public readonly string id; public readonly Category category; public static int itemCount => allItems.Length; private Item(string id, Category category) { this.id = id; this.category = category; } } public class Mod : FxMod { public const string MOD_ID = "Oscar's Inventory Tweaks"; private static readonly ShopListing[] targetItemListings = (ShopListing[])(object)new ShopListing[Item.itemCount]; private static Preferences? preferences; protected override string configPath => "OscarsInventoryTweaks.cfg"; public override void OnInitializeMelon() { preferences = new Preferences(base.ConfigPath); base.OnInitializeMelon(); } protected override void onModPreferencesSaved() { if (base.InMainScene) { updateShopListings(); } } protected override void onLocalPlayerLoaded(Player _) { init(); updateShopListings(); } private static void init() { ((MelonBase)FxMod.Instance).LoggerInstance.Debug("initializing"); ShopInterface shopInterface = NPC.Get<Dan>("dan_samwell").ShopInterface; for (int i = 0; i < Item.itemCount; i++) { targetItemListings[i] = shopInterface.GetListing(Item.allItems[i].id); ((MelonBase)FxMod.Instance).LoggerInstance.Debug("grabbed {0} listing from dan", ((BaseItemDefinition)targetItemListings[i].Item).ID); } } private static void moveItem<T>(List<T> items, int from, int to) { T item = items[from]; items.RemoveAt(from); items.Insert(to, item); } private static Dictionary<string, ShopListing?> buildListings() { Dictionary<string, ShopListing> dictionary = new Dictionary<string, ShopListing>(Item.itemCount); (Item, bool)[] items = preferences.getItems(); for (int i = 0; i < items.Length; i++) { var (item, flag) = items[i]; dictionary[item.id] = (flag ? targetItemListings[i] : null); } return dictionary; } private static void pruneDisabledListings(ShopInterface oscar, Dictionary<string, ShopListing?> newListings, List<ListingUI> uiListings, UIPanel listingPanel) { foreach (var (text2, val2) in newListings) { if (val2 != null) { continue; } ShopListing listing = oscar.GetListing(text2); if (listing == null) { continue; } ((MelonBase)FxMod.Instance).LoggerInstance.Debug("removing {0} from Oscar's inventory", text2); oscar.Listings.Remove(listing); ListingUI val3 = null; for (int i = 0; i < uiListings.Count; i++) { if (((BaseItemDefinition)uiListings[i].Listing.Item).ID == text2) { val3 = uiListings[i]; uiListings.RemoveAt(i); break; } } if (!((Object)(object)val3 == (Object)null)) { listingPanel.RemoveSelectable(((Component)val3).GetComponent<UISelectable>(), true); Object.Destroy((Object)(object)((Component)val3).gameObject); } } } private static void injectNewListings(ShopInterface oscar, Dictionary<string, ShopListing?> newListings, List<ListingUI> uiListings) { MethodInfo method = typeof(ShopInterface).GetMethod("CreateListingUI", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { typeof(ShopListing) }, null); object[] array = new object[1]; foreach (ShopListing listing in oscar.Listings) { newListings.Remove(((BaseItemDefinition)listing.Item).ID); } for (int num = Item.allItems.Length - 1; num >= 0; num--) { Item item = Item.allItems[num]; if (newListings.TryGetValue(item.id, out ShopListing value) && value != null) { oscar.Listings.Add(Utils.copyListing(targetItemListings[num], oscar)); array[0] = value; method.Invoke(oscar, array); int num2 = findInsertPosition(uiListings, item.category.appearsAfter); if (num2 > -1) { moveItem(uiListings, uiListings.Count - 1, num2); } } } } private static int findInsertPosition(List<ListingUI> list, string target) { for (int i = 0; i < list.Count; i++) { if (((BaseItemDefinition)list[i].Listing.Item).ID == target) { return i + 1; } } return -1; } private static void updateShopListings() { ShopInterface val = NPC.Get<Oscar>("oscar_holland")?.ShopInterface; if ((Object)(object)val == (Object)null) { ((MelonBase)FxMod.Instance).LoggerInstance.Debug("oscar was null"); return; } List<ListingUI> list = val.ListingUIItems(); if (list == null) { ((MelonBase)FxMod.Instance).LoggerInstance.Debug("uiListings was null"); return; } UIPanel val2 = val.ListingPanel(); if ((Object)(object)val2 == (Object)null) { ((MelonBase)FxMod.Instance).LoggerInstance.Debug("uiPanel was null"); return; } Dictionary<string, ShopListing> newListings = buildListings(); pruneDisabledListings(val, newListings, list, val2); injectNewListings(val, newListings, list); } } internal sealed class Preferences { private readonly MelonPreferences_Entry<bool> sellFertilizer; private readonly MelonPreferences_Entry<bool> sellPGR; private readonly MelonPreferences_Entry<bool> sellSpeedGrow; private readonly MelonPreferences_Entry<bool> sellBigSprinkler; private readonly MelonPreferences_Entry<bool> sellLocker; private readonly MelonPreferences_Entry<bool> sellShelves; private readonly MelonPreferences_Entry<bool> sellClosets; private readonly MelonPreferences_Entry<bool> sellAirCon; public bool SellFertilizer => sellFertilizer.Value; public bool SellPgr => sellPGR.Value; public bool SellSpeedGrow => sellSpeedGrow.Value; public bool SellBigSprinkler => sellBigSprinkler.Value; public bool SellLocker => sellLocker.Value; public bool SellShelves => sellShelves.Value; public bool SellClosets => sellClosets.Value; public bool SellAirCon => sellAirCon.Value; public Preferences(string configPath) { MelonPreferences_Category val = MelonPreferences.CreateCategory("Oscar's Inventory Tweaks - Additives", "Growth Additives"); val.SetFilePath(configPath); sellFertilizer = val.CreateEntry<bool>("sellFertilizer", true, "Sell Fertilizer", (string)null, false, false, (ValueValidator)null, (string)null); sellPGR = val.CreateEntry<bool>("sellPGR", true, "Sell PGR", (string)null, false, false, (ValueValidator)null, (string)null); sellSpeedGrow = val.CreateEntry<bool>("sellSpeedGrow", true, "Sell Speed Grow", (string)null, false, false, (ValueValidator)null, (string)null); MelonPreferences_Category val2 = MelonPreferences.CreateCategory("Oscar's Inventory Tweaks - Growing", "Equipment"); val2.SetFilePath(configPath); sellBigSprinkler = val2.CreateEntry<bool>("sellBigSprinkler", true, "Sell Big Sprinkler", (string)null, false, false, (ValueValidator)null, (string)null); sellAirCon = val2.CreateEntry<bool>("sellAirConditioner", true, "Sell AC Unit", (string)null, false, false, (ValueValidator)null, (string)null); MelonPreferences_Category val3 = MelonPreferences.CreateCategory("Oscar's Inventory Tweaks - Storage", "Storage"); val3.SetFilePath(configPath); sellLocker = val3.CreateEntry<bool>("sellLocker", true, "Sell Locker", (string)null, false, false, (ValueValidator)null, (string)null); sellShelves = val3.CreateEntry<bool>("sellShelves", true, "Sell Shelves", (string)null, false, false, (ValueValidator)null, (string)null); sellClosets = val3.CreateEntry<bool>("sellClosets", true, "Sell Closets", (string)null, false, false, (ValueValidator)null, (string)null); } } internal static class Utils { public static (Item, bool)[] getItems(this Preferences prefs) { return new(Item, bool)[13] { (Item.Fertilizer, prefs.SellFertilizer), (Item.PGR, prefs.SellPgr), (Item.SpeedGrow, prefs.SellSpeedGrow), (Item.Locker, prefs.SellLocker), (Item.BigSprinkler, prefs.SellBigSprinkler), (Item.AirConditioner, prefs.SellAirCon), (Item.SmallStorageCloset, prefs.SellClosets), (Item.MediumStorageCloset, prefs.SellClosets), (Item.LargeStorageCloset, prefs.SellClosets), (Item.HugeStorageCloset, prefs.SellClosets), (Item.SmallStorageRack, prefs.SellShelves), (Item.MediumStorageRack, prefs.SellShelves), (Item.LargeStorageRack, prefs.SellShelves) }; } public static List<ListingUI>? ListingUIItems(this ShopInterface shop) { FieldInfo field = typeof(ShopInterface).GetField("listingUI", BindingFlags.Instance | BindingFlags.NonPublic); ((MelonBase)FxMod.Instance).LoggerInstance.Debug("reflectively got field {0}", field); return (List<ListingUI>)field.GetValue(shop); } public static UIPanel? ListingPanel(this ShopInterface shop) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown FieldInfo field = typeof(ShopInterface).GetField("listingPanel", BindingFlags.Instance | BindingFlags.NonPublic); ((MelonBase)FxMod.Instance).LoggerInstance.Debug("reflectively got field {0}", field); return (UIPanel)field.GetValue(shop); } public static ShopListing copyListing(ShopListing old, ShopInterface shop) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown ShopListing val = new ShopListing { name = old.name, Item = old.Item, LimitedStock = old.LimitedStock, DefaultStock = old.DefaultStock, RestockRate = old.RestockRate, TieStockToNumberVariable = old.TieStockToNumberVariable, StockVariableName = old.StockVariableName, TrackPurchases = old.TrackPurchases, PurchasedQuantityVariableName = old.PurchasedQuantityVariableName, EnforceMinimumGameCreationVersion = old.EnforceMinimumGameCreationVersion, MinimumGameCreationVersion = old.MinimumGameCreationVersion, CanBeDelivered = old.CanBeDelivered, UseIconTint = old.UseIconTint, IconTint = old.IconTint, ConditionalVisibility = old.ConditionalVisibility, ConditionalVisibilityVariableName = old.ConditionalVisibilityVariableName }; val.Initialize(shop); val.SetStock(old.CurrentStock, true); return val; } } }