Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of StoreRotationConfig v3.0.0
BepInEx/plugins/StoreRotationConfig.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using MrovLib.ContentType; using StoreRotationConfig.Compatibility; using StoreRotationConfig.NetcodePatcher; using StoreRotationConfig.Networking; using StoreRotationConfig.Patches; using TerminalFormatter; using TerminalFormatter.Nodes; using TerminalStuff.StoreTweaks; using TerminalUtils.Nodes; using Unity.Netcode; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("BepInEx")] [assembly: IgnoresAccessChecksTo("ClientNetworkTransform")] [assembly: IgnoresAccessChecksTo("com.olegknyazev.softmask")] [assembly: IgnoresAccessChecksTo("darmuhsTerminalStuff")] [assembly: IgnoresAccessChecksTo("DissonanceVoip")] [assembly: IgnoresAccessChecksTo("DunGen")] [assembly: IgnoresAccessChecksTo("DunGen.Integration.ASPP")] [assembly: IgnoresAccessChecksTo("DunGen.Integration.UnityNav")] [assembly: IgnoresAccessChecksTo("EasyTextEffects")] [assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("TerminalFormatter")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Jobs")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")] [assembly: IgnoresAccessChecksTo("Unity.Services.QoS")] [assembly: IgnoresAccessChecksTo("Unity.Services.Relay")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.XR.CoreUtils")] [assembly: IgnoresAccessChecksTo("Unity.XR.Management")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.ConformanceAutomation")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MetaQuestSupport")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MockRuntime")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.OculusQuestSupport")] [assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.RuntimeDebugger")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.SpatialTracking")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: IgnoresAccessChecksTo("UnityEngine.XR.LegacyInputHelpers")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("StoreRotationConfig")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Configure the number of items in each store rotation, show them all, remove purchases, sort them, and/or enable sales for them.")] [assembly: AssemblyFileVersion("3.0.0.0")] [assembly: AssemblyInformationalVersion("3.0.0+39acc986a06095266233a89b26b40aa2e85922b5")] [assembly: AssemblyProduct("StoreRotationConfig")] [assembly: AssemblyTitle("StoreRotationConfig")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("3.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] [CompilerGenerated] internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; 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(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } 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(); } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 StoreRotationConfig { public sealed class Config { [CompilerGenerated] private HashSet<UnlockableItem> <WhitelistedItems>k__BackingField; [CompilerGenerated] private HashSet<UnlockableItem> <BlacklistedItems>k__BackingField; public HashSet<UnlockableItem> WhitelistedItems => <WhitelistedItems>k__BackingField ?? (<WhitelistedItems>k__BackingField = new HashSet<UnlockableItem>()); public HashSet<UnlockableItem> BlacklistedItems => <BlacklistedItems>k__BackingField ?? (<BlacklistedItems>k__BackingField = new HashSet<UnlockableItem>()); public ConfigEntry<int> MIN_ITEMS { get; private set; } public ConfigEntry<int> MAX_ITEMS { get; private set; } public ConfigEntry<bool> STOCK_ALL { get; private set; } public ConfigEntry<bool> REMOVE_PURCHASED { get; private set; } public ConfigEntry<string> ITEM_WHITELIST { get; private set; } public ConfigEntry<string> ITEM_BLACKLIST { get; private set; } public ConfigEntry<float> SALE_CHANCE { get; private set; } public ConfigEntry<int> MIN_SALE_ITEMS { get; private set; } public ConfigEntry<int> MAX_SALE_ITEMS { get; private set; } public ConfigEntry<int> MIN_DISCOUNT { get; private set; } public ConfigEntry<int> MAX_DISCOUNT { get; private set; } public ConfigEntry<bool> ROUND_TO_NEAREST_TEN { get; private set; } public ConfigEntry<bool> DISPLAY_AD_DISCOUNTS { get; private set; } public ConfigEntry<bool> SORT_ITEMS { get; private set; } public ConfigEntry<bool> RELATIVE_SCROLL { get; private set; } public ConfigEntry<int> LINES_TO_SCROLL { get; private set; } public Config(ConfigFile cfg) { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Expected O, but got Unknown cfg.SaveOnConfigSet = false; MIN_ITEMS = cfg.Bind<int>("General", "minItems", 8, "Minimum number of items in the store rotation."); MAX_ITEMS = cfg.Bind<int>("General", "maxItems", 12, "Maximum number of items in the store rotation."); STOCK_ALL = cfg.Bind<bool>("General", "stockAll", false, "Make every item available in the store rotation."); REMOVE_PURCHASED = cfg.Bind<bool>("General", "removePurchased", true, "Remove purchased items from the current and future store rotations.If enabled, prevents purchased items from showing up again in future store rotations, and removes them from the current one."); ITEM_WHITELIST = cfg.Bind<string>("General", "itemWhitelist", "", "The comma-separated names of items that will be guaranteed to show up in every store rotation. Whitelisted items are always added on top of the range defined by the 'minItems' and 'maxItems' settings, and take priority over the blacklist. Has no effect with the 'stockAll' setting enabled.\nExample: \"Bee suit,Goldfish,Television\""); ITEM_BLACKLIST = cfg.Bind<string>("General", "itemBlacklist", "", "The comma-separated names of items that will never show up in the store rotation. You're a mean one, Mr. Grinch.\nExample: \"Bee suit,Goldfish,Television\""); SALE_CHANCE = cfg.Bind<float>("Sales", "saleChance", 33.333332f, new ConfigDescription("The percentage chance for ANY item to be on sale in the store rotation. Setting this to '0' disables the entire sales system.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); MIN_SALE_ITEMS = cfg.Bind<int>("Sales", "minSaleItems", 1, "The minimum number of items that can be on sale at a time."); MAX_SALE_ITEMS = cfg.Bind<int>("Sales", "maxSaleItems", 5, "The maximum number of items that can be on sale at a time."); MIN_DISCOUNT = cfg.Bind<int>("Sales", "minDiscount", 10, new ConfigDescription("The minimum discount to apply to items on sale.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); MAX_DISCOUNT = cfg.Bind<int>("Sales", "maxDiscount", 50, new ConfigDescription("The maximum discount to apply to items on sale.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); ROUND_TO_NEAREST_TEN = cfg.Bind<bool>("Sales", "roundToNearestTen", true, "Round rotation store discounts to the nearest ten (like the regular store)."); DISPLAY_AD_DISCOUNTS = cfg.Bind<bool>("Sales", "displayAdDiscounts", true, "Display rotation store discounts in advertisements (like regular tools)."); SORT_ITEMS = cfg.Bind<bool>("Miscellaneous", "sortItems", false, "Sort every item in the store rotation alphabetically."); RELATIVE_SCROLL = cfg.Bind<bool>("Miscellaneous", "relativeScroll", true, "Adapt terminal scroll to the number of lines in the current terminal page, instead of a flat value. Should fix cases where scrolling skips over several lines, which is especially noticeable when enabling 'stockAll' with a large number of items added to the rotating store."); LINES_TO_SCROLL = cfg.Bind<int>("Miscellaneous", "linesToScroll", 20, new ConfigDescription("Number of lines to scroll at a time with 'relativeScroll' enabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 28), Array.Empty<object>())); LINES_TO_SCROLL.SettingChanged += delegate { TerminalScrollMousePatch.currentText = string.Empty; }; ITEM_WHITELIST.SettingChanged += RefreshConfigLists; ITEM_BLACKLIST.SettingChanged += RefreshConfigLists; MIN_ITEMS.SettingChanged += RefreshRotation; MAX_ITEMS.SettingChanged += RefreshRotation; STOCK_ALL.SettingChanged += RefreshRotation; REMOVE_PURCHASED.SettingChanged += RefreshRotation; ITEM_BLACKLIST.SettingChanged += RefreshRotation; SALE_CHANCE.SettingChanged += RefreshRotation; MIN_SALE_ITEMS.SettingChanged += RefreshRotation; MAX_SALE_ITEMS.SettingChanged += RefreshRotation; MIN_DISCOUNT.SettingChanged += RefreshRotation; MAX_DISCOUNT.SettingChanged += RefreshRotation; ROUND_TO_NEAREST_TEN.SettingChanged += RefreshRotation; SORT_ITEMS.SettingChanged += RefreshRotation; cfg.OrphanedEntries.Clear(); cfg.SaveOnConfigSet = true; cfg.Save(); } private static void RefreshRotation(object obj, EventArgs args) { if ((Object)(object)StartOfRound.Instance != (Object)null && ((NetworkBehaviour)StartOfRound.Instance).IsHost && (Object)(object)Plugin.Terminal != (Object)null) { Plugin.Terminal.RotateShipDecorSelection(); } } internal void RefreshConfigLists() { WhitelistedItems.Clear(); BlacklistedItems.Clear(); if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.unlockablesList == (Object)null) { return; } string[] array = ITEM_WHITELIST.Value.Split(new char[2] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = ITEM_BLACKLIST.Value.Split(new char[2] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < StartOfRound.Instance.unlockablesList.unlockables?.Count; i++) { UnlockableItem val = StartOfRound.Instance.unlockablesList.unlockables[i]; if (val == null || (Object)(object)val.shopSelectionNode == (Object)null) { continue; } string displayName = string.Join(string.Empty, val.shopSelectionNode.creatureName.Split((string[]?)null, StringSplitOptions.RemoveEmptyEntries)); string unlockableName = string.Join(string.Empty, val.unlockableName.Split((string[]?)null, StringSplitOptions.RemoveEmptyEntries)); int num = Array.FindIndex(array, (string whitelistName) => whitelistName.Equals(displayName, StringComparison.OrdinalIgnoreCase) || whitelistName.Equals(unlockableName, StringComparison.OrdinalIgnoreCase)); if (num != -1) { WhitelistedItems.Add(val); continue; } int num2 = Array.FindIndex(array2, (string blacklistName) => blacklistName.Equals(displayName, StringComparison.OrdinalIgnoreCase) || blacklistName.Equals(unlockableName, StringComparison.OrdinalIgnoreCase)); if (num2 != -1) { BlacklistedItems.Add(val); } } } private void RefreshConfigLists(object obj, EventArgs args) { RefreshConfigLists(); } } [BepInPlugin("pacoito.StoreRotationConfig", "StoreRotationConfig", "3.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string PLUGIN_GUID = "pacoito.StoreRotationConfig"; public const string PLUGIN_NAME = "StoreRotationConfig"; public const string VERSION = "3.0.0"; [CompilerGenerated] private static ManualLogSource <Logger>k__BackingField; [CompilerGenerated] private static Harmony <Harmony>k__BackingField; [CompilerGenerated] private static Terminal? <Terminal>k__BackingField; internal static ManualLogSource Logger => <Logger>k__BackingField ?? (<Logger>k__BackingField = Logger.CreateLogSource("StoreRotationConfig")); internal static Harmony Harmony { get { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown object obj = <Harmony>k__BackingField; if (obj == null) { Harmony val = new Harmony("pacoito.StoreRotationConfig"); <Harmony>k__BackingField = val; obj = (object)val; } return (Harmony)obj; } } public static Config? Settings { get; private set; } public static Terminal? Terminal { get { if ((Object)(object)<Terminal>k__BackingField == (Object)null) { <Terminal>k__BackingField = Object.FindAnyObjectByType<Terminal>((FindObjectsInactive)0); } return <Terminal>k__BackingField; } } private void Awake() { try { Settings = new Config(((BaseUnityPlugin)this).Config); SerializeNetworkVariables(); Harmony.PatchAll(typeof(NetworkingInitPatches)); Harmony.PatchAll(typeof(RotateShipDecorSelectionPatch)); Harmony.PatchAll(typeof(TerminalItemSalesPatches)); Harmony.PatchAll(typeof(TerminalScrollMousePatch)); Harmony.PatchAll(typeof(UnlockableDisplayAdsPatches)); Harmony.PatchAll(typeof(UnlockShipObjectPatch)); Harmony.PatchAll(typeof(MenuManagerPatch)); Logger.LogInfo((object)"StoreRotationConfig v3.0.0 loaded!"); } catch (Exception arg) { Logger.LogError((object)string.Format("Error while initializing '{0}': {1}", "StoreRotationConfig", arg)); } } private static void SerializeNetworkVariables() { NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedByMemcpy<StoreRotationEntry>(); NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable<StoreRotationEntry>(); } } } namespace StoreRotationConfig.Patches { internal static class MenuManagerPatch { [HarmonyPatch(typeof(MenuManager), "Start")] [HarmonyWrapSafe] [HarmonyPrefix] private static void MenuManagerStart_Prefix() { if ((Object)(object)GameNetworkManager.Instance == (Object)null || !GameNetworkManager.Instance.firstTimeInMenu) { return; } if (TerminalStuffCompatibility.Enabled) { try { Plugin.Harmony.PatchAll(typeof(TerminalStuffCompatibility)); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Error while patching compatibility for 'TerminalStuff': {arg}"); } } if (!TerminalUtilsCompatibility.Enabled) { return; } try { Plugin.Harmony.PatchAll(typeof(TerminalUtilsCompatibility)); } catch (Exception arg2) { Plugin.Logger.LogError((object)$"Error while patching compatibility for 'TerminalUtils': {arg2}"); } if (!TerminalFormatterCompatibility.Enabled) { return; } try { Plugin.Harmony.PatchAll(typeof(TerminalFormatterCompatibility)); } catch (Exception arg3) { Plugin.Logger.LogError((object)$"Error while patching compatibility for 'TerminalFormatter': {arg3}"); } } } internal static class NetworkingInitPatches { [CompilerGenerated] private static StoreRotationNetworker? <NetworkerPrefab>k__BackingField; public static StoreRotationNetworker? NetworkerPrefab { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown if ((Object)(object)<NetworkerPrefab>k__BackingField == (Object)null) { GameObject val = new GameObject("StoreRotationNetworker") { hideFlags = (HideFlags)61 }; try { byte[] value = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(Assembly.GetExecutingAssembly().GetName().Name)); val.AddComponent<NetworkObject>().GlobalObjectIdHash = BitConverter.ToUInt32(value, 0); } catch (Exception arg) { Plugin.Logger.LogError((object)$"Could not override default Networker hash: {arg}"); } <NetworkerPrefab>k__BackingField = val.AddComponent<StoreRotationNetworker>(); } return <NetworkerPrefab>k__BackingField; } } [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyWrapSafe] [HarmonyPrefix] private static void StartOfRoundStart_Prefix(StartOfRound __instance) { if (!((NetworkBehaviour)__instance).NetworkManager.IsHost) { return; } if ((Object)(object)NetworkerPrefab == (Object)null) { Plugin.Logger.LogError((object)"Networker prefab is missing and could not be created! Store rotations won't work..."); return; } GameObject val = Object.Instantiate<GameObject>(((Component)NetworkerPrefab).gameObject); ((Object)val).hideFlags = (HideFlags)0; NetworkObject val2 = default(NetworkObject); if (val.TryGetComponent<NetworkObject>(ref val2)) { val2.Spawn(true); } } [HarmonyPatch(typeof(GameNetworkManager), "Start")] [HarmonyWrapSafe] [HarmonyPrefix] private static void GameNetworkManagerStart_Prefix(GameNetworkManager __instance) { NetworkManager val = default(NetworkManager); if (!((Component)__instance).TryGetComponent<NetworkManager>(ref val)) { return; } if ((Object)(object)NetworkerPrefab == (Object)null) { Plugin.Logger.LogError((object)"Networker prefab is missing and could not be created! Store rotations won't work..."); return; } NetworkConfig networkConfig = val.NetworkConfig; if (networkConfig != null) { NetworkPrefabs prefabs = networkConfig.Prefabs; if (((prefabs != null) ? new bool?(prefabs.Contains(((Component)NetworkerPrefab).gameObject)) : ((bool?)null)) == false) { val.AddNetworkPrefab(((Component)NetworkerPrefab).gameObject); } } } } internal static class RotateShipDecorSelectionPatch { private static void RotateShipDecorSelection(Random random) { if ((Object)(object)StoreRotationNetworker.Instance == (Object)null || StoreRotationNetworker.Instance.StoreRotation == null) { Plugin.Logger.LogError((object)"StoreRotationNetworker instance is missing! Store rotation won't work..."); } else { if (!((NetworkBehaviour)StoreRotationNetworker.Instance).IsHost) { return; } if (Plugin.Settings == null) { Plugin.Logger.LogError((object)"Configuration could not be loaded or is missing! Store rotation won't work..."); return; } int num = Math.Abs(Plugin.Settings.MAX_ITEMS.Value); int num2 = Math.Abs(Plugin.Settings.MIN_ITEMS.Value); bool value = Plugin.Settings.STOCK_ALL.Value; bool value2 = Plugin.Settings.SORT_ITEMS.Value; bool removePurchased = Plugin.Settings.REMOVE_PURCHASED.Value; HashSet<UnlockableItem> whitelistedItems = Plugin.Settings.WhitelistedItems; HashSet<UnlockableItem> blacklistedItems = Plugin.Settings.BlacklistedItems; Plugin.Logger.LogInfo((object)"Rotating store..."); StoreRotationNetworker.Instance.StoreRotation.Clear(); if (num2 > num && !value) { Plugin.Logger.LogWarning((object)"Value for 'minItems' is larger than 'maxItems', using it instead..."); num = num2; } int num3 = ((num2 != num && !value) ? random.Next(num2, num + 1) : num); List<UnlockableItem> list = StartOfRound.Instance.unlockablesList.unlockables.ToList(); list.RemoveAll((UnlockableItem item) => item == null || (Object)(object)item.shopSelectionNode == (Object)null || item.alwaysInStock || whitelistedItems.Contains(item) || blacklistedItems.Contains(item) || (removePurchased && item.hasBeenUnlockedByPlayer)); if (value) { num3 = list.Count; } List<UnlockableItem> list2 = whitelistedItems.ToList(); list2.RemoveAll((UnlockableItem item) => item == null || (Object)(object)item.shopSelectionNode == (Object)null || item.alwaysInStock || (removePurchased && item.hasBeenUnlockedByPlayer)); for (int num4 = 0; num4 < num3; num4++) { if (list.Count == 0) { break; } int index = random.Next(0, list.Count); list2.Add(list[index]); list.RemoveAt(index); } if (value2 && list2.Count > 1) { list2.Sort((UnlockableItem x, UnlockableItem y) => string.Compare(x.shopSelectionNode.creatureName, y.shopSelectionNode.creatureName, StringComparison.Ordinal)); } int[] array = TerminalItemSalesPatches.RollSales(list2.Count); for (int num5 = 0; num5 < list2.Count; num5++) { UnlockableItem val = list2[num5]; int shipUnlockableID = val.shopSelectionNode.shipUnlockableID; int itemCost = val.shopSelectionNode.itemCost; int unlockableDiscount = ((array != null) ? array[num5] : 0); bool isSuit = val.unlockableType == 0 && (Object)(object)val.suitMaterial != (Object)null; StoreRotationNetworker.Instance.StoreRotation.Add(new StoreRotationEntry(shipUnlockableID, itemCost, unlockableDiscount, isSuit)); } } } [HarmonyPatch(typeof(Terminal), "RotateShipDecorSelection")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> RotateShipDecorSelection_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown FieldInfo field = typeof(Terminal).GetField("ShipDecorSelection", BindingFlags.Instance | BindingFlags.Public); MethodInfo method = typeof(List<TerminalNode>).GetMethod("Clear", BindingFlags.Instance | BindingFlags.Public); CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)field, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)method, (string)null) }); if (val.IsInvalid) { Plugin.Logger.LogError((object)"Could not match Terminal 'ShipDecorSelection' list clearing."); return instructions; } MethodInfo method2 = typeof(RotateShipDecorSelectionPatch).GetMethod("RotateShipDecorSelection", BindingFlags.Static | BindingFlags.NonPublic); return val.Insert((CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Ldloc_0, (object)null), new CodeInstruction(OpCodes.Call, (object)method2), new CodeInstruction(OpCodes.Ret, (object)null) }).InstructionEnumeration(); } } internal static class TerminalItemSalesPatches { internal static int[]? RollSales(int itemsInRotation) { if (Plugin.Settings == null) { Plugin.Logger.LogError((object)"Configuration could not be loaded or is missing! Store rotation won't work..."); return null; } float num = Math.Clamp(Plugin.Settings.SALE_CHANCE.Value, 0f, 100f); int num2 = Math.Abs(Plugin.Settings.MIN_SALE_ITEMS.Value); int num3 = Math.Abs(Plugin.Settings.MAX_SALE_ITEMS.Value); int num4 = Math.Clamp(Plugin.Settings.MIN_DISCOUNT.Value, 0, 100); int num5 = Math.Clamp(Plugin.Settings.MAX_DISCOUNT.Value, 0, 100); bool value = Plugin.Settings.ROUND_TO_NEAREST_TEN.Value; if (num == 0f) { return null; } Random random = new Random(StartOfRound.Instance.randomMapSeed + 90); if ((float)random.NextDouble() > num / 100f) { Plugin.Logger.LogInfo((object)"No items on sale for this rotation..."); return null; } int[] array = new int[itemsInRotation]; if (num2 > num3) { Plugin.Logger.LogWarning((object)"Value for 'minSaleItems' is larger than 'maxSaleItems', using it instead..."); num3 = num2; } if (num4 > num5) { Plugin.Logger.LogWarning((object)"Value for 'minDiscount' is larger than 'maxDiscount', using it instead..."); num5 = num4; } int num6 = random.Next(num2, num3 + 1); int num7 = num6; if (num6 <= 0) { Plugin.Logger.LogInfo((object)"No items on sale for this rotation..."); return null; } for (int i = 0; i < array.Length; i++) { if (num7 == 0) { break; } if ((float)random.NextDouble() < (float)num7 / (float)(array.Length - i)) { int num8 = random.Next(num4, num5 + 1); if (value) { num8 = (int)Math.Round((float)num8 / 10f) * 10; } array[i] = num8; num7--; } } Plugin.Logger.LogInfo((object)$"{num6 - num7} items on sale!"); return array; } [HarmonyPatch(typeof(Terminal), "LoadNewNodeIfAffordable")] [HarmonyPriority(600)] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> TerminalLoadNewNodeIfAffordable_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown FieldInfo field = typeof(TerminalNode).GetField("itemCost", BindingFlags.Instance | BindingFlags.Public); FieldInfo field2 = typeof(Terminal).GetField("totalCostOfItems", BindingFlags.Instance | BindingFlags.NonPublic); CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(true, (CodeMatch[])(object)new CodeMatch[4] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldarg_1, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)field, (string)null), new CodeMatch((OpCode?)OpCodes.Stfld, (object)field2, (string)null) }); if (val.Advance(1).IsInvalid) { Plugin.Logger.LogError((object)"Could not match Terminal 'totalCostOfItems' field assignment."); return instructions; } MethodInfo method = typeof(TerminalItemSalesPatches).GetMethod("ApplyDiscount", BindingFlags.Static | BindingFlags.NonPublic); return val.Insert((CodeInstruction[])(object)new CodeInstruction[4] { new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldflda, (object)field2), new CodeInstruction(OpCodes.Call, (object)method) }).InstructionEnumeration(); } private static void ApplyDiscount(TerminalNode unlockableNode, ref int totalCostOfItems) { if (unlockableNode.buyRerouteToMoon != -1) { return; } List<TerminalNode> list = (((Object)(object)Plugin.Terminal != (Object)null) ? Plugin.Terminal.ShipDecorSelection : null); int num = (unlockableNode.buyUnlockable ? (list?.FindIndex((TerminalNode node) => node.shipUnlockableID == unlockableNode.shipUnlockableID) ?? (-1)) : (list?.IndexOf(unlockableNode) ?? (-1))); if (num == -1) { return; } if ((Object)(object)StoreRotationNetworker.Instance == (Object)null || StoreRotationNetworker.Instance.StoreRotation == null) { Plugin.Logger.LogError((object)("StoreRotationNetworker instance is missing! No discount could be applied to '" + unlockableNode.creatureName + "'...")); return; } StoreRotationEntry storeRotationEntry = StoreRotationNetworker.Instance.StoreRotation[num]; if (storeRotationEntry.UnlockableDiscount > 0) { totalCostOfItems = storeRotationEntry.GetDiscountedPrice(unlockableNode); Plugin.Logger.LogDebug((object)$"Applying discount of '{storeRotationEntry.UnlockableDiscount}%' to '{unlockableNode.creatureName}': '{storeRotationEntry.UnlockablePrice}' -> '{totalCostOfItems}'"); } } [HarmonyPatch(typeof(Terminal), "TextPostProcess")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> TextPostProcessTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldarg_1, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"[unlockablesSelectionList]", (string)null), new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"[No items available]", (string)null) }); if (val.IsInvalid) { Plugin.Logger.LogError((object)"Could not match '[unlockablesSelectionList]' parameter in store page."); return instructions; } FieldInfo field = typeof(TerminalNode).GetField("itemCost", BindingFlags.Instance | BindingFlags.Public); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[4] { new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)field, (string)null), new CodeMatch((OpCode?)OpCodes.Box, (object)typeof(int), (string)null) }); if (val.IsInvalid) { Plugin.Logger.LogError((object)"Could not match TerminalNode 'itemCost' field parameter in store page item display."); return instructions; } CodeInstruction instruction = val.Instruction; MethodInfo method = typeof(TerminalItemSalesPatches).GetMethod("AppendDiscountTag", BindingFlags.Static | BindingFlags.NonPublic); return val.Advance(2).SetInstructionAndAdvance(instruction).SetInstruction(new CodeInstruction(OpCodes.Call, (object)method)) .InstructionEnumeration(); } private static string AppendDiscountTag(TerminalNode unlockableNode, int rotationIndex) { if ((Object)(object)StoreRotationNetworker.Instance == (Object)null || StoreRotationNetworker.Instance.StoreRotation == null) { Plugin.Logger.LogError((object)("StoreRotationNetworker instance is missing! No discount could be applied to '" + unlockableNode.creatureName + "'...")); return $"{unlockableNode.itemCost}"; } return StoreRotationNetworker.Instance.StoreRotation[rotationIndex].GetTerminalPriceString(unlockableNode); } } internal static class TerminalScrollMousePatch { public static string currentText = string.Empty; private static float scrollAmount = 1f / 3f; private static void ScrollMouse_performed(Scrollbar scrollbar, float scrollDirection) { Config? settings = Plugin.Settings; if (settings == null || !settings.RELATIVE_SCROLL.Value) { scrollbar.value += scrollDirection / 3f; return; } if ((Object)(object)Plugin.Terminal != (Object)null && !string.Equals(Plugin.Terminal.currentText, currentText, StringComparison.Ordinal)) { currentText = Plugin.Terminal.currentText; int num = currentText.Split('\n').Length; scrollAmount = (float)Plugin.Settings.LINES_TO_SCROLL.Value / (float)num; Plugin.Logger.LogDebug((object)$"Setting terminal scroll amount to '{scrollAmount}'!"); } scrollbar.value += scrollDirection * scrollAmount; } [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed", new Type[] { typeof(CallbackContext) })] private static IEnumerable<CodeInstruction> ScrollMousePerformed_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown FieldInfo field = typeof(PlayerControllerB).GetField("terminalScrollVertical", BindingFlags.Instance | BindingFlags.Public); CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)field, (string)null) }); if (val.IsInvalid) { Plugin.Logger.LogError((object)"Could not match Player 'terminalScrollVertical' field."); return instructions; } MethodInfo method = typeof(TerminalScrollMousePatch).GetMethod("ScrollMouse_performed", BindingFlags.Static | BindingFlags.NonPublic); return val.Insert((CodeInstruction[])(object)new CodeInstruction[5] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)field), new CodeInstruction(OpCodes.Ldloc_0, (object)null), new CodeInstruction(OpCodes.Call, (object)method), new CodeInstruction(OpCodes.Ret, (object)null) }).InstructionEnumeration(); } } internal static class UnlockableDisplayAdsPatches { private static bool TryGetDiscount(int rotationIndex, ref string saleText) { Config? settings = Plugin.Settings; if (settings == null || !settings.DISPLAY_AD_DISCOUNTS.Value) { return false; } if ((Object)(object)StoreRotationNetworker.Instance == (Object)null || StoreRotationNetworker.Instance.StoreRotation == null) { Plugin.Logger.LogError((object)$"StoreRotationNetworker instance is missing! No discount could be applied to item at index '{rotationIndex}'..."); return false; } StoreRotationEntry storeRotationEntry = StoreRotationNetworker.Instance.StoreRotation[rotationIndex]; if (storeRotationEntry.UnlockableDiscount > 0) { saleText = $"{storeRotationEntry.UnlockableDiscount}% OFF!"; return true; } return false; } [HarmonyPatch(typeof(HUDManager), "ChooseAdItem")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> ChooseAdItem_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_0019: 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_003e: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Expected O, but got Unknown MethodInfo method = typeof(HUDManager).GetMethod("CreateFurnitureAdModelAndDisplayAdClientRpc", BindingFlags.Instance | BindingFlags.Public); CodeMatcher val = new CodeMatcher(instructions, generator).End().MatchBack(false, (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)method, (string)null) }); if (val.Advance(1).IsInvalid) { Plugin.Logger.LogError((object)"Could not match ChooseAdItem 'CreateFurnitureAdModelAndDisplayAdClientRpc()' call."); return instructions; } CodeInstruction instruction = val.Instruction; MethodInfo method2 = typeof(HUDManager).GetMethod("BeginDisplayAd", BindingFlags.Instance | BindingFlags.Public); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[4] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)method2, (string)null) }); if (val.Advance(2).IsInvalid) { Plugin.Logger.LogError((object)"Could not match ChooseAdItem 'BeginDisplayAd()' call."); return instructions; } object operand = val.Operand; MethodInfo method3 = typeof(UnlockableDisplayAdsPatches).GetMethod("TryGetDiscount", BindingFlags.Static | BindingFlags.NonPublic); Label label = default(Label); Label label2 = default(Label); return val.CreateLabelAt(val.Pos + 1, ref label).CreateLabel(ref label2).Insert((CodeInstruction[])(object)new CodeInstruction[4] { instruction, new CodeInstruction(OpCodes.Ldloca_S, operand), new CodeInstruction(OpCodes.Call, (object)method3), new CodeInstruction(OpCodes.Pop, (object)null) }) .InstructionEnumeration(); } [HarmonyPatch(typeof(HUDManager), "CreateFurnitureAdModelAndDisplayAdClientRpc")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> CreateFurnitureAdModelAndDisplayAdClientRpc_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_0030: 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) //IL_0055: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown MethodInfo method = typeof(HUDManager).GetMethod("ChooseSaleText", BindingFlags.Instance | BindingFlags.NonPublic); MethodInfo method2 = typeof(HUDManager).GetMethod("BeginDisplayAd", BindingFlags.Instance | BindingFlags.Public); CodeMatcher val = new CodeMatcher(instructions, generator).End().MatchBack(true, (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)method, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)method2, (string)null) }); if (val.IsInvalid) { Plugin.Logger.LogError((object)"Could not match CreateFurnitureAdModelAndDisplayAdClientRpc 'BeginDisplayAd()' call."); return instructions; } LocalBuilder localBuilder = generator.DeclareLocal(typeof(string)); MethodInfo method3 = typeof(UnlockableDisplayAdsPatches).GetMethod("TryGetDiscount", BindingFlags.Static | BindingFlags.NonPublic); Label label = default(Label); Label label2 = default(Label); return val.CreateLabel(ref label).Advance(-2).CreateLabel(ref label2) .Insert((CodeInstruction[])(object)new CodeInstruction[6] { new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Ldloca_S, (object)localBuilder), new CodeInstruction(OpCodes.Call, (object)method3), new CodeInstruction(OpCodes.Brfalse_S, (object)label2), new CodeInstruction(OpCodes.Ldloc_S, (object)localBuilder), new CodeInstruction(OpCodes.Br_S, (object)label) }) .InstructionEnumeration(); } } internal static class UnlockShipObjectPatch { [HarmonyPatch(typeof(StartOfRound), "BuyShipUnlockableServerRpc")] [HarmonyPrefix] private static void BuyShipUnlockableServerRpc_Prefix(StartOfRound __instance, int unlockableID) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 if ((int)((NetworkBehaviour)__instance).__rpc_exec_stage != 1 || unlockableID < 0) { return; } Config? settings = Plugin.Settings; if (settings == null || !settings.REMOVE_PURCHASED.Value) { return; } List<TerminalNode> list = (((Object)(object)Plugin.Terminal != (Object)null) ? Plugin.Terminal.ShipDecorSelection : null); int num = list?.FindIndex((TerminalNode node) => (Object)(object)node != (Object)null && node.shipUnlockableID == unlockableID) ?? (-1); if (num >= 0 && list != null && num < list.Count) { if ((Object)(object)StoreRotationNetworker.Instance == (Object)null || StoreRotationNetworker.Instance.StoreRotation == null) { Plugin.Logger.LogError((object)"StoreRotationNetworker instance is missing! Could not remove purchased item..."); } else { StoreRotationNetworker.Instance.StoreRotation.RemoveAt(num); } } } } } namespace StoreRotationConfig.Networking { [Serializable] public struct StoreRotationEntry : INetworkSerializable, IEquatable<StoreRotationEntry> { public readonly int UnlockableID => <unlockableID>P; public readonly int UnlockablePrice => <unlockablePrice>P; public readonly int UnlockableDiscount => <unlockableDiscount>P; public readonly bool IsSuit => <isSuit>P; public StoreRotationEntry(int unlockableID, int unlockablePrice, int unlockableDiscount, bool isSuit) { <unlockableID>P = unlockableID; <unlockablePrice>P = unlockablePrice; <unlockableDiscount>P = unlockableDiscount; <isSuit>P = isSuit; } public static implicit operator TerminalNode?(StoreRotationEntry entry) { return ((UnlockableItem?)entry)?.shopSelectionNode; } public static implicit operator UnlockableItem?(StoreRotationEntry entry) { int unlockableID = entry.UnlockableID; List<UnlockableItem> list = (((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.unlockablesList != (Object)null) ? StartOfRound.Instance.unlockablesList.unlockables : null); if (unlockableID < 0 || list == null || unlockableID >= list.Count) { Plugin.Logger.LogError((object)$"Could not obtain item with ID '{unlockableID}' from list of unlockable items!"); return null; } return list[unlockableID]; } public readonly int GetDiscountedPrice() { return GetDiscountedPrice(this); } public readonly int GetDiscountedPrice(TerminalNode? node) { if (!((Object)(object)node != (Object)null)) { return -1; } return node.itemCost - (int)((float)node.itemCost * ((float)<unlockableDiscount>P / 100f)); } public readonly string GetTerminalPriceString() { return GetTerminalPriceString(this); } public readonly string GetTerminalPriceString(TerminalNode? node) { if (!((Object)(object)node != (Object)null)) { return string.Empty; } if (<unlockableDiscount>P != 0) { return $"{GetDiscountedPrice(node)} ({<unlockableDiscount>P}% OFF!)"; } return $"{node.itemCost}"; } public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_0026: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref <unlockableID>P, default(ForPrimitives)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref <unlockablePrice>P, default(ForPrimitives)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref <unlockableDiscount>P, default(ForPrimitives)); ((BufferSerializer<bool>*)(&serializer))->SerializeValue<bool>(ref <isSuit>P, default(ForPrimitives)); } public readonly bool Equals(StoreRotationEntry other) { if (<unlockableID>P == other.UnlockableID && <unlockablePrice>P == other.UnlockablePrice && <unlockableDiscount>P == other.UnlockableDiscount) { return <isSuit>P == other.IsSuit; } return false; } public override readonly bool Equals(object obj) { if (obj is StoreRotationEntry other) { return Equals(other); } return false; } public static bool operator ==(StoreRotationEntry left, StoreRotationEntry right) { return left.Equals(right); } public static bool operator !=(StoreRotationEntry left, StoreRotationEntry right) { return !(left == right); } public override readonly int GetHashCode() { return HashCode.Combine(<unlockableID>P, <unlockablePrice>P, <unlockableDiscount>P, <isSuit>P); } } public sealed class StoreRotationNetworker : NetworkBehaviour { public static StoreRotationNetworker? Instance { get; private set; } public NetworkList<StoreRotationEntry>? StoreRotation { get; private set; } private void Awake() { Instance = this; StoreRotation = new NetworkList<StoreRotationEntry>(); } public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); NetworkList<StoreRotationEntry>? storeRotation = StoreRotation; if (storeRotation != null) { storeRotation.OnListChanged += OnListChanged; } if ((Object)(object)Plugin.Terminal == (Object)null) { Plugin.Logger.LogError((object)"Could not find Terminal instance! Store rotation doesn't exist..."); } else if (!((NetworkBehaviour)this).IsHost && StoreRotation != null) { Terminal terminal = Plugin.Terminal; if (terminal.ShipDecorSelection == null) { terminal.ShipDecorSelection = new List<TerminalNode>(); } List<TerminalNode> shipDecorSelection = Plugin.Terminal.ShipDecorSelection; NetworkList<StoreRotationEntry> storeRotation2 = StoreRotation; int num = 0; TerminalNode[] array = (TerminalNode[])(object)new TerminalNode[storeRotation2.Count]; foreach (StoreRotationEntry item in storeRotation2) { array[num] = item; num++; } shipDecorSelection.AddRange(new <>z__ReadOnlyArray<TerminalNode>(array)); } else { Plugin.Settings?.RefreshConfigLists(); } } private static void OnListChanged(NetworkListEvent<StoreRotationEntry> changeEvent) { //IL_003c: 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_0049: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected I4, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Plugin.Terminal == (Object)null) { Plugin.Logger.LogError((object)"Could not find Terminal instance! Store rotation doesn't exist..."); return; } Terminal terminal = Plugin.Terminal; List<TerminalNode> list = terminal.ShipDecorSelection ?? (terminal.ShipDecorSelection = new List<TerminalNode>()); TerminalNode val = changeEvent.Value; EventType<StoreRotationEntry> type = changeEvent.Type; switch ((int)type) { case 0: if ((Object)(object)val != (Object)null) { list.Add(val); } break; case 1: if ((Object)(object)val != (Object)null && changeEvent.Index >= 0 && changeEvent.Index < list.Count) { list.Insert(changeEvent.Index, val); } break; case 2: if ((Object)(object)val != (Object)null) { list.Remove(val); } break; case 3: if (changeEvent.Index >= 0 && changeEvent.Index < list.Count) { list.RemoveAt(changeEvent.Index); } break; case 5: list.Clear(); break; case 4: if ((Object)(object)val != (Object)null && changeEvent.Index >= 0 && changeEvent.Index < list.Count) { list[changeEvent.Index] = val; } break; case 6: break; } } protected override void __initializeVariables() { if (StoreRotation == null) { throw new Exception("StoreRotationNetworker.<StoreRotation>k__BackingField cannot be null. All NetworkVariableBase instances must be initialized."); } ((NetworkVariableBase)StoreRotation).Initialize((NetworkBehaviour)(object)this); ((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)StoreRotation, "StoreRotation"); base.NetworkVariableFields.Add((NetworkVariableBase)(object)StoreRotation); ((NetworkBehaviour)this).__initializeVariables(); } protected override void __initializeRpcs() { ((NetworkBehaviour)this).__initializeRpcs(); } [MethodImpl(MethodImplOptions.NoInlining)] protected internal override string? __getTypeName() { return "StoreRotationNetworker"; } } } namespace StoreRotationConfig.Compatibility { internal static class TerminalFormatterCompatibility { private static bool? _enabled; public static bool Enabled { get { bool valueOrDefault = _enabled == true; if (!_enabled.HasValue) { valueOrDefault = Chainloader.PluginInfos.ContainsKey("TerminalFormatter"); _enabled = valueOrDefault; } return _enabled.Value; } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] [HarmonyPatch(typeof(Store), "GetNodeText")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> GetNodeText_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Expected O, but got Unknown //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Expected O, but got Unknown //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Expected O, but got Unknown //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Expected O, but got Unknown //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Expected O, but got Unknown //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Expected O, but got Unknown //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Expected O, but got Unknown //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Expected O, but got Unknown //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Expected O, but got Unknown //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Expected O, but got Unknown //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Expected O, but got Unknown MethodInfo getMethod = typeof(BuyableThing).GetProperty("Name").GetGetMethod(); MethodInfo getMethod2 = typeof(BuyableThing).GetProperty("Price").GetGetMethod(); MethodInfo method = typeof(string).GetMethod("Format", new Type[2] { typeof(string), typeof(object) }); CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[9] { new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)getMethod, (string)null), new CodeMatch((OpCode?)OpCodes.Stloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"${0}", (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)getMethod2, (string)null), new CodeMatch((OpCode?)OpCodes.Box, (object)typeof(int), (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)method, (string)null), new CodeMatch((OpCode?)OpCodes.Stloc_S, (object)null, (string)null) }); if (val.IsInvalid) { Plugin.Logger.LogError((object)"Could not match Store 'price' formatting."); return instructions; } CodeInstruction instruction = val.Instruction; object operand = val.Advance(2).Operand; object operand2 = val.Advance(6).Operand; FieldInfo field = typeof(Settings).GetField("itemNameWidth", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo method2 = typeof(string).GetMethod("PadRight", new Type[1] { typeof(int) }); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[9] { new CodeMatch((OpCode?)OpCodes.Ldloc_1, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_3, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Newarr, (object)typeof(object), (string)null), new CodeMatch((OpCode?)OpCodes.Dup, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldsfld, (object)field, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)method2, (string)null), new CodeMatch((OpCode?)OpCodes.Dup, (object)null, (string)null) }); if (val.IsInvalid) { Plugin.Logger.LogError((object)"Could not match Store 'nameWithDiscount' padding."); return instructions; } MethodInfo method3 = typeof(TerminalFormatterCompatibility).GetMethod("AppendDiscountTag", BindingFlags.Static | BindingFlags.NonPublic); return val.SetAndAdvance(instruction.opcode, instruction.operand).Insert((CodeInstruction[])(object)new CodeInstruction[4] { new CodeInstruction(OpCodes.Ldloca_S, operand), new CodeInstruction(OpCodes.Ldloca_S, operand2), new CodeInstruction(OpCodes.Call, (object)method3), new CodeInstruction(OpCodes.Ldloc_1, (object)null) }).InstructionEnumeration(); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static void AppendDiscountTag(BuyableThing thing, ref string nameWithDiscount, ref string price) { BuyableUnlockable val = (BuyableUnlockable)(object)((thing is BuyableUnlockable) ? thing : null); TerminalNode val2 = ((val == null) ? ((BuyableSuit)(((thing is BuyableSuit) ? thing : null)?)).Suit?.shopSelectionNode : val.Unlockable?.shopSelectionNode); if ((Object)(object)val2 == (Object)null) { return; } int num = (((Object)(object)Plugin.Terminal != (Object)null) ? Plugin.Terminal.ShipDecorSelection : null)?.IndexOf(val2) ?? (-1); if (num == -1) { return; } if ((Object)(object)StoreRotationNetworker.Instance == (Object)null || StoreRotationNetworker.Instance.StoreRotation == null) { Plugin.Logger.LogError((object)("StoreRotationNetworker instance is missing! No discount could be applied to '" + val2.creatureName + "'...")); return; } StoreRotationEntry storeRotationEntry = StoreRotationNetworker.Instance.StoreRotation[num]; int unlockableDiscount = storeRotationEntry.UnlockableDiscount; if (unlockableDiscount > 0) { string text = $" -{unlockableDiscount}%"; nameWithDiscount = ((nameWithDiscount.Length + text.Length > Settings.itemNameWidth) ? (nameWithDiscount.Substring(0, Settings.itemNameWidth - 4 - text.Length) + "... " + text) : (nameWithDiscount.PadRight(Settings.itemNameWidth - text.Length) + text).PadRight(Settings.itemNameWidth)); price = $"${storeRotationEntry.GetDiscountedPrice(val2)}"; } } } internal static class TerminalStuffCompatibility { private static bool? _enabled; public static bool Enabled { get { bool valueOrDefault = _enabled == true; if (!_enabled.HasValue) { valueOrDefault = Chainloader.PluginInfos.ContainsKey("darmuh.TerminalStuff"); _enabled = valueOrDefault; } return _enabled.Value; } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] [HarmonyPatch(typeof(StoreInfo), "PriceChecks")] [HarmonyPostfix] private static void PriceChecks_Postfix(StoreInfo __instance, TerminalNode ___terminalNode) { if (__instance.Unlockable == null) { return; } __instance.OnSale = false; int num = (((Object)(object)Plugin.Terminal != (Object)null) ? Plugin.Terminal.ShipDecorSelection : null)?.IndexOf(___terminalNode) ?? (-1); if (num != -1) { if ((Object)(object)StoreRotationNetworker.Instance == (Object)null || StoreRotationNetworker.Instance.StoreRotation == null) { Plugin.Logger.LogError((object)("StoreRotationNetworker instance is missing! No discount could be applied to '" + ___terminalNode.creatureName + "'...")); return; } StoreRotationEntry storeRotationEntry = StoreRotationNetworker.Instance.StoreRotation[num]; __instance.price = storeRotationEntry.GetDiscountedPrice(___terminalNode); __instance.OnSale = storeRotationEntry.UnlockableDiscount > 0; } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] [HarmonyPatch(typeof(StorePlus), "GetSalesPercentage")] [HarmonyPostfix] private static void GetSalesPercentage_Postfix(ref int __result, StoreInfo item) { if (item.Unlockable == null) { return; } int num = (((Object)(object)Plugin.Terminal != (Object)null) ? Plugin.Terminal.ShipDecorSelection : null)?.IndexOf(item.terminalNode) ?? (-1); if (num != -1) { if ((Object)(object)StoreRotationNetworker.Instance == (Object)null || StoreRotationNetworker.Instance.StoreRotation == null) { Plugin.Logger.LogError((object)("StoreRotationNetworker instance is missing! No discount could be applied to '" + item.terminalNode.creatureName + "'...")); } else { __result = StoreRotationNetworker.Instance.StoreRotation[num].UnlockableDiscount; } } } } internal static class TerminalUtilsCompatibility { private static bool? _enabled; public static bool Enabled { get { bool valueOrDefault = _enabled == true; if (!_enabled.HasValue) { valueOrDefault = Chainloader.PluginInfos.ContainsKey("mrov.TerminalUtils"); _enabled = valueOrDefault; } return _enabled.Value; } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] [HarmonyPatch(typeof(StoreCatalogue), "GetNodeText")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> GetNodeText_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Expected O, but got Unknown //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Expected O, but got Unknown //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Castclass, (object)typeof(BuyableItem), (string)null), new CodeMatch((OpCode?)OpCodes.Stloc_S, (object)null, (string)null) }); if (val.IsInvalid) { Plugin.Logger.LogError((object)"Could not match StoreCatalogue BuyableItem casting."); return instructions; } CodeInstruction instruction = val.Instruction; MethodInfo method = typeof(string).GetMethod("Concat", new Type[2] { typeof(string), typeof(string) }); val.MatchForward(true, (CodeMatch[])(object)new CodeMatch[12] { new CodeMatch((OpCode?)OpCodes.Ldloc_1, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_2, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Newarr, (object)typeof(object), (string)null), new CodeMatch((OpCode?)OpCodes.Dup, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"* ", (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)method, (string)null), new CodeMatch((OpCode?)OpCodes.Stelem_Ref, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Dup, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_1, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null) }); if (val.IsInvalid) { Plugin.Logger.LogError((object)"Could not match StoreCatalogue 'priceWithDiscount' concatenation."); return instructions; } object operand = val.Operand; MethodInfo method2 = typeof(TerminalUtilsCompatibility).GetMethod("AppendDiscountTag", BindingFlags.Static | BindingFlags.NonPublic); return val.Advance(-11).SetAndAdvance(instruction.opcode, instruction.operand).Insert((CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Ldloca_S, operand), new CodeInstruction(OpCodes.Call, (object)method2), new CodeInstruction(OpCodes.Ldloc_1, (object)null) }) .InstructionEnumeration(); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static void AppendDiscountTag(BuyableThing thing, ref string priceWithDiscount) { BuyableUnlockable val = (BuyableUnlockable)(object)((thing is BuyableUnlockable) ? thing : null); TerminalNode val2 = ((val == null) ? ((BuyableSuit)(((thing is BuyableSuit) ? thing : null)?)).Suit?.shopSelectionNode : val.Unlockable?.shopSelectionNode); if ((Object)(object)val2 == (Object)null) { return; } int num = (((Object)(object)Plugin.Terminal != (Object)null) ? Plugin.Terminal.ShipDecorSelection : null)?.IndexOf(val2) ?? (-1); if (num == -1) { return; } if ((Object)(object)StoreRotationNetworker.Instance == (Object)null || StoreRotationNetworker.Instance.StoreRotation == null) { Plugin.Logger.LogError((object)("StoreRotationNetworker instance is missing! No discount could be applied to '" + val2.creatureName + "'...")); return; } StoreRotationEntry storeRotationEntry = StoreRotationNetworker.Instance.StoreRotation[num]; int unlockableDiscount = storeRotationEntry.UnlockableDiscount; if (unlockableDiscount > 0) { priceWithDiscount = $"${storeRotationEntry.GetDiscountedPrice(val2)} (-{unlockableDiscount}%)"; } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace __GEN { internal class NetworkVariableSerializationHelper { [RuntimeInitializeOnLoadMethod] internal static void InitializeSerialization() { NetworkVariableSerializationTypes.InitializeSerializer_UnmanagedINetworkSerializable<StoreRotationEntry>(); NetworkVariableSerializationTypes.InitializeEqualityChecker_UnmanagedIEquatable<StoreRotationEntry>(); } } } namespace StoreRotationConfig.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }