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 10 hours 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(); } } } }