Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of MetalStorage v1.2.0
MetalStorage.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using MelonLoader; using MelonLoader.Preferences; using MetalStorage; using MetalStorage.Features; using Microsoft.CodeAnalysis; using S1API.Building; using S1API.Internal.Utils; using S1API.Items; using S1API.Lifecycle; using S1API.Rendering; using S1API.Shops; using S1API.Storage; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "MetalStorage", "1.2.0", "HazDS", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MetalStorage")] [assembly: AssemblyConfiguration("CrossCompat")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c8b5d110366f04652da57807cfdb201e2247fba3")] [assembly: AssemblyProduct("MetalStorage")] [assembly: AssemblyTitle("MetalStorage")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.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 MetalStorage { public class Core : MelonMod { [CompilerGenerated] private sealed class <AddToShopsDelayed>d__15 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Core <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <AddToShopsDelayed>d__15(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; if (<>4__this._shopsInitialized) { return false; } ((MelonBase)<>4__this).LoggerInstance.Msg("Adding metal storage racks to shops..."); MetalStorageRackCreator.AddToShops(); <>4__this._shopsInitialized = true; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private bool _itemsInitialized; private bool _shopsInitialized; private static MelonPreferences_Category _prefsCategory; private static MelonPreferences_Entry<int> _smallExtraSlots; private static MelonPreferences_Entry<int> _mediumExtraSlots; private static MelonPreferences_Entry<int> _largeExtraSlots; private static MelonPreferences_Entry<int> _smallPrice; private static MelonPreferences_Entry<int> _mediumPrice; private static MelonPreferences_Entry<int> _largePrice; public static int GetExtraSlots(string itemId) { if (1 == 0) { } int result = itemId switch { "metalsmallstoragerack" => _smallExtraSlots?.Value ?? 2, "metalmediumstoragerack" => _mediumExtraSlots?.Value ?? 2, "metallargestoragerack" => _largeExtraSlots?.Value ?? 2, _ => 0, }; if (1 == 0) { } return result; } public static int GetPrice(string itemId) { if (1 == 0) { } int result = itemId switch { "metalsmallstoragerack" => _smallPrice?.Value ?? 72, "metalmediumstoragerack" => _mediumPrice?.Value ?? 104, "metallargestoragerack" => _largePrice?.Value ?? 144, _ => 0, }; if (1 == 0) { } return result; } public override void OnInitializeMelon() { _prefsCategory = MelonPreferences.CreateCategory("MetalStorage", "Metal Storage Settings"); _smallExtraSlots = _prefsCategory.CreateEntry<int>("SmallExtraSlots", 2, "Small Rack Extra Slots", "Extra slots for Small Metal Storage Rack (base: 4, max extra: 16)", false, false, (ValueValidator)null, (string)null); _mediumExtraSlots = _prefsCategory.CreateEntry<int>("MediumExtraSlots", 2, "Medium Rack Extra Slots", "Extra slots for Medium Metal Storage Rack (base: 6, max extra: 14)", false, false, (ValueValidator)null, (string)null); _largeExtraSlots = _prefsCategory.CreateEntry<int>("LargeExtraSlots", 2, "Large Rack Extra Slots", "Extra slots for Large Metal Storage Rack (base: 8, max extra: 12)", false, false, (ValueValidator)null, (string)null); _smallPrice = _prefsCategory.CreateEntry<int>("SmallRackPrice", 72, "Small Rack Price", "Purchase price for Small Metal Storage Rack", false, false, (ValueValidator)null, (string)null); _mediumPrice = _prefsCategory.CreateEntry<int>("MediumRackPrice", 104, "Medium Rack Price", "Purchase price for Medium Metal Storage Rack", false, false, (ValueValidator)null, (string)null); _largePrice = _prefsCategory.CreateEntry<int>("LargeRackPrice", 144, "Large Rack Price", "Purchase price for Large Metal Storage Rack", false, false, (ValueValidator)null, (string)null); ClampEntry(_smallExtraSlots, 0, 16); ClampEntry(_mediumExtraSlots, 0, 14); ClampEntry(_largeExtraSlots, 0, 12); ClampEntry(_smallPrice, 1, 10000); ClampEntry(_mediumPrice, 1, 10000); ClampEntry(_largePrice, 1, 10000); GameLifecycle.OnPreLoad += OnPreLoad; } private static void ClampEntry(MelonPreferences_Entry<int> entry, int min, int max) { if (entry.Value < min) { entry.Value = min; } if (entry.Value > max) { entry.Value = max; } } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (sceneName == "Main") { if (!_shopsInitialized) { MelonCoroutines.Start(AddToShopsDelayed()); } } else if (sceneName == "Menu") { _itemsInitialized = false; _shopsInitialized = false; } } private void OnPreLoad() { if (!_itemsInitialized) { ((MelonBase)this).LoggerInstance.Msg("Creating metal storage racks..."); MetalStorageRackCreator.CreateAllMetalRacks(); _itemsInitialized = true; } } [IteratorStateMachine(typeof(<AddToShopsDelayed>d__15))] private IEnumerator AddToShopsDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <AddToShopsDelayed>d__15(0) { <>4__this = this }; } } } namespace MetalStorage.Utils { public static class Constants { public static class Game { public const string GAME_STUDIO = "TVGS"; public const string GAME_NAME = "Schedule I"; } public static class StorageRacks { public const string SMALL = "smallstoragerack"; public const string MEDIUM = "mediumstoragerack"; public const string LARGE = "largestoragerack"; } public static class ItemIds { public const string SMALL = "metalsmallstoragerack"; public const string MEDIUM = "metalmediumstoragerack"; public const string LARGE = "metallargestoragerack"; } public const string MOD_NAME = "MetalStorage"; public const string MOD_VERSION = "1.2.0"; public const string MOD_AUTHOR = "HazDS"; public const string MOD_DESCRIPTION = "Adds metal variants of storage racks to the game."; public const string PREFERENCES_CATEGORY = "MetalStorage"; } } namespace MetalStorage.Features { public static class MetalStorageRackCreator { private static readonly Color MetalColor = new Color(0.5f, 0.5f, 0.55f, 1f); public static readonly HashSet<string> MetalItemIds = new HashSet<string>(); private static readonly Dictionary<string, Sprite> _loadedIcons = new Dictionary<string, Sprite>(); private static readonly Dictionary<string, int> BaseSlotsByItemId = new Dictionary<string, int> { { "metalsmallstoragerack", 4 }, { "metalmediumstoragerack", 6 }, { "metallargestoragerack", 8 } }; private static readonly Dictionary<string, string> DisplayNamesByItemId = new Dictionary<string, string>(); private static bool _eventsRegistered; private static readonly HashSet<int> _expandedStorages = new HashSet<int>(); public static void CreateAllMetalRacks() { LoadIcons(); if (!_eventsRegistered) { BuildEvents.OnGridItemCreated += OnItemBuilt; BuildEvents.OnSurfaceItemCreated += OnItemBuilt; BuildEvents.OnBuildableItemInitialized += OnItemBuilt; StorageEvents.OnStorageCreated += OnStorageCreated; StorageEvents.OnStorageLoading += OnStorageLoading; StorageEvents.OnStorageOpening += OnStorageOpening; _eventsRegistered = true; } CreateMetalStorageRack("smallstoragerack", "Small Metal Storage Rack", "metalsmallstoragerack", "MetalStorageRack_Small-Icon"); CreateMetalStorageRack("mediumstoragerack", "Medium Metal Storage Rack", "metalmediumstoragerack", "MetalStorageRack_1.5x0.5-Icon"); CreateMetalStorageRack("largestoragerack", "Large Metal Storage Rack", "metallargestoragerack", "MetalStorageRack_Large-Icon"); MelonLogger.Msg($"Created {MetalItemIds.Count} metal storage rack variants"); } private static void LoadIcons() { string[] array = new string[3] { "MetalStorageRack_Small-Icon", "MetalStorageRack_1.5x0.5-Icon", "MetalStorageRack_Large-Icon" }; Assembly executingAssembly = Assembly.GetExecutingAssembly(); string[] array2 = array; foreach (string text in array2) { string text2 = "MetalStorage.Assets." + text + ".png"; Sprite val = ImageUtils.LoadImageFromResource(executingAssembly, text2, 100f, (FilterMode)1); if ((Object)(object)val != (Object)null) { _loadedIcons[text] = val; } } } private static void CreateMetalStorageRack(string originalId, string newName, string newId, string iconName) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) try { Sprite value; Sprite val = (_loadedIcons.TryGetValue(iconName, out value) ? value : null); int price = Core.GetPrice(newId); BuildableItemDefinition val2 = BuildableItemCreator.CloneFrom(originalId).WithBasicInfo(newId, newName, "A metal version of the storage rack. More industrial looking.").WithIcon(val) .WithPricing((float)price, 0.5f) .WithBuildSound((BuildSoundType)1) .WithLabelColor(Color.white) .Build(); MetalItemIds.Add(newId); DisplayNamesByItemId[newId] = newName; MelonLogger.Msg("Created " + newName + " (ID: " + newId + ")"); } catch (Exception ex) { MelonLogger.Error("Failed to create metal storage rack '" + newId + "': " + ex.Message); } } private static int GetTargetSlotCount(string itemId, int minimumSlots = 0) { int value; int num = (BaseSlotsByItemId.TryGetValue(itemId, out value) ? value : 0); int extraSlots = Core.GetExtraSlots(itemId); return Math.Max(num + extraSlots, minimumSlots); } private static void EnsureSlotCapacity(StorageEntity storage, string itemId, int minimumSlots = 0) { if (storage == null || string.IsNullOrEmpty(itemId)) { return; } int item = ((object)storage.ItemInstance)?.GetHashCode() ?? ((object)storage).GetHashCode(); if (!_expandedStorages.Contains(item)) { int targetSlotCount = GetTargetSlotCount(itemId, minimumSlots); int slotCount = storage.SlotCount; int num = targetSlotCount - slotCount; if (num <= 0) { _expandedStorages.Add(item); } else if (storage.AddSlots(num)) { _expandedStorages.Add(item); } else { MelonLogger.Warning($"Failed to expand storage '{itemId}' to {targetSlotCount} slots (current {slotCount})"); } } } public static void AddToShops() { int num = 0; foreach (string metalItemId in MetalItemIds) { ItemDefinition itemDefinition = ItemManager.GetItemDefinition(metalItemId); if (itemDefinition == (ItemDefinition)null) { MelonLogger.Warning("Could not find item definition for '" + metalItemId + "'"); continue; } int num2 = ShopManager.AddToCompatibleShops(itemDefinition, (float?)null); num += num2; } MelonLogger.Msg($"Added metal storage racks to {num} shop listing(s)"); } private static void OnItemBuilt(BuildEventArgs args) { if (args != null && MetalItemIds.Contains(args.ItemId)) { MaterialHelper.ReplaceMaterials(args.GameObject, (Func<Material, bool>)((Material mat) => ((Object)mat).name.ToLower().Contains("brownwood")), (Action<Material>)delegate(Material mat) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) MaterialHelper.RemoveAllTextures(mat); MaterialHelper.SetColor(mat, "_BaseColor", MetalColor); MaterialHelper.SetColor(mat, "_Color", MetalColor); MaterialHelper.SetFloat(mat, "_Metallic", 0.8f); MaterialHelper.SetFloat(mat, "_Smoothness", 0.5f); MaterialHelper.SetFloat(mat, "_Glossiness", 0.5f); }); } } private static void OnStorageCreated(StorageEventArgs args) { if (((args != null) ? args.Storage : null) != null && MetalItemIds.Contains(args.ItemId)) { if (DisplayNamesByItemId.TryGetValue(args.ItemId, out var value)) { args.Storage.Name = value; } EnsureSlotCapacity(args.Storage, args.ItemId); } } private static void OnStorageLoading(StorageLoadingEventArgs args) { if (((args != null) ? ((StorageEventArgs)args).Storage : null) != null && MetalItemIds.Contains(((StorageEventArgs)args).ItemId)) { if (DisplayNamesByItemId.TryGetValue(((StorageEventArgs)args).ItemId, out var value)) { ((StorageEventArgs)args).Storage.Name = value; } EnsureSlotCapacity(((StorageEventArgs)args).Storage, ((StorageEventArgs)args).ItemId, args.ItemCountBeingLoaded); } } private static void OnStorageOpening(StorageEventArgs args) { if (((args != null) ? args.Storage : null) != null) { args.Storage.SyncCustomNameToDisplayName(); } } } }