From 1ceb2df3371fb9bebb1f32660a8e743a503e720e Mon Sep 17 00:00:00 2001 From: pacoito123 Date: Thu, 6 Jun 2024 17:49:21 -0600 Subject: [PATCH] [v2.2.0] Transpilers now used in place of some prefix patches, some minor refactoring. - Switched to using Transpilers for `Terminal.RotateShipDecorSelection()` and `PlayerControllerB.ScrollMouse_performed()` patches. - Should be much better for compatibility with any other mods that might potentially want to patch these methods as well. - From initial testing, everything seems to be working fine, but please let me know if any issues are encountered. - Changed `maxItems` and `minItems` to use their absolute values when rotating the store, to avoid any issues with negative numbers in the configuration file. - Modifying `linesToScroll` in-game (e.g. through `LethalConfig`) should now apply changes immediately, instead of until after scrolling on a different terminal page. - Updated minimum `CSync` library dependency to patch `v5.0.1`. - Previous release also works with `v5.0.1`, and is recommended. --- CHANGELOG.md | 11 +++ README.md | 22 ++--- StoreRotationConfig/Config.cs | 15 ++-- .../Patches/RotateShipDecorSelectionPatch.cs | 90 +++++++++++++------ .../Patches/SyncShipUnlockablesPatches.cs | 5 +- .../Patches/TerminalScrollMousePatch.cs | 81 +++++++++++------ .../Patches/UnlockShipObjectPatches.cs | 17 +--- StoreRotationConfig/Plugin.cs | 28 +++++- .../StoreRotationConfig.csproj | 6 +- global.json | 6 +- manifest.json | 6 +- 11 files changed, 186 insertions(+), 101 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6851bb4..62e3d05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +### [2.2.0] + +Transpilers now used in place of some prefix patches, some minor refactoring. +- Switched to using Transpilers for `Terminal.RotateShipDecorSelection()` and `PlayerControllerB.ScrollMouse_performed()` patches. + - Should be much better for compatibility with any other mods that might potentially want to patch these methods as well. + - From initial testing, everything seems to be working fine, but please let me know if any issues are encountered. +- Changed `maxItems` and `minItems` to use their absolute values when rotating the store, to avoid any issues with negative numbers in the configuration file. +- Modifying `linesToScroll` in-game (e.g. through `LethalConfig`) should now apply changes immediately, instead of until after scrolling on a different terminal page. +- Updated minimum `CSync` library dependency to patch `v5.0.1`. + - Previous release also works with `v5.0.1`, and is recommended. + ### [2.1.0] Update to 'CSync' v5, more configuration for terminal scrolling. diff --git a/README.md b/README.md index e72b7eb..9645dda 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![License](https://img.shields.io/github/license/pacoito123/LC_StoreRotationConfig?style=for-the-badge&logo=github&color=teal )](https://github.com/pacoito123/LC_StoreRotationConfig/blob/main/LICENSE) -> Configure the number of purchasable items in each store rotation, or simply show them all. +> Configure the number of items in each store rotation, show them all, remove purchased items, or sort them. ## Description @@ -17,33 +17,33 @@ Intended for when there's a large number of modded items (suits, furniture, etc. Compatible with `v45`, `v49`, and `v50`. -Uses [CSync (v5.0.0 and above)](https://thunderstore.io/c/lethal-company/p/Sigurd/CSync) by [Lordfirespeed](https://github.com/Lorefirespeed) to sync config settings between host and clients. +Uses [CSync (v5.0.1 and above)](https://thunderstore.io/c/lethal-company/p/Sigurd/CSync) by [Lordfirespeed](https://github.com/Lorefirespeed) to sync config settings between host and clients. **NOTE:** In case an older version of CSync is needed, usually due to mods that have not yet updated to the latest versions, refer to the following table for which specific version of this mod to downgrade to: | CSync | StoreRotationConfig | | :-------------: | :-----------------: | -| v5.0.0 | `v2.1.0` | +| v5.0.1 | `v2.1.0+` | | v4.1.0 | `v2.0.1` | | v3.1.1 | `v1.3.0` | ## Configuration -By default, the number of available items in the store is increased from **4-5** (vanilla) to **8-12**, but this range can be configured via the `minItems` and `maxItems` config settings. Set both numbers to the same value to have a fixed number of items in every rotation. +By default, the number of available items in the store is increased from **4-5** (vanilla) to **8-12**, but this range can be configured via the `minItems` and `maxItems` config settings. Set both numbers to the same value to have a fixed number of items in every rotation. If `minItems` is larger than `maxItems`, both numbers are set to the larger value. To avoid any issues with negative numbers, the absolute value of these two settings is used when generating the store rotation. -Alternatively, the `showAll` setting (off by default) can be toggled to simply add every purchasable item to the store rotation. Partly intended for fixing name conflict issues when buying stuff at the terminal, but there should be no problems using it during a regular run. +Alternatively, the `showAll` setting (off by default) can be enabled to simply add every purchasable item to the store rotation. Partly intended for fixing name conflict issues when buying stuff at the terminal, but there should be no problems using it during a regular run. -Toggling the `showPurchased` setting (on by default) will prevent already-purchased items from showing up in future store rotations, and will also immediately remove newly-purchased items from the current rotation. +Disabling the `showPurchased` setting (on by default) will prevent already-purchased items from showing up in future store rotations, and will also immediately remove newly-purchased items from the current rotation. -The store rotation can also be displayed in alphabetical order by toggling the `sortItems` setting (off by default). +The store rotation can also be displayed in alphabetical order by enabling the `sortItems` setting (off by default). -For cases where having too many items in the store rotation causes scrolling to skip over several lines, either with `stockAll` enabled or with a high `minItems`/`maxItems` value, toggling the `relativeScroll` setting (off by default) will adapt scrolling to a certain number of lines at a time, determined by the `linesToScroll` setting (20 by default). +For cases where having too many items in the store rotation causes scrolling to skip over several lines, either with `stockAll` enabled or with a high `minItems`/`maxItems` value, enabling the `relativeScroll` setting (off by default) will adapt scrolling to a certain number of lines at a time, determined by the `linesToScroll` setting (20 by default), and relative to the length of the currently shown terminal page. ## Compatibility The patched `Terminal.RotateShipDecorSelection()` method is functionally the same as vanilla, only with some configurability added, so it _should_ play nicely with other mods (as long as they don't also clear the `Terminal.ShipDecorSelection` list to generate their own, or forcibly add items without checking if they're already present in it). -There's also the possibility of something going wrong if the `Terminal.ShipDecorSelection` list is needed by another mod immediately after joining a lobby, but prior to the config file sync; the patched method to fill the list with additional items only runs _after_ a successful sync, so it remains empty until then. So far I haven't encountered any issues with it, but if any incompatibilities _are_ found, please let me know in the [relevant thread](https://discord.com/channels/1168655651455639582/1212542584610881557) in the Lethal Company Modding Discord server, or [open an issue on GitHub](https://github.com/pacoito123/LC_StoreRotationConfig/issues). +There's also the possibility of something going wrong if the `Terminal.ShipDecorSelection` list is required by another mod immediately after joining a lobby, but prior to the ship unlockables sync; the list is only filled _after_ a successful sync with the host, and it remains empty until then. So far I haven't encountered any issues with it, but if any incompatibilities _are_ found, please let me know in the [relevant thread](https://discord.com/channels/1168655651455639582/1212542584610881557) in the Lethal Company Modding Discord server, or [open an issue on GitHub](https://github.com/pacoito123/LC_StoreRotationConfig/issues). In `v49`, there's a name conflict between the `Purple suit` and the `Pajama suit`, which adds a second, unpurchasable `Pajama suit` to the store. If every item available in the store is bought, with the `showPurchased` setting disabled, only the `Pajama suit` will remain in the store rotation. This is fixed in `v50`, with the `Purple suit` having been made properly purchasable. @@ -51,8 +51,8 @@ The `relativeScroll` tweak is not limited to just the store page, and could pote ~~**NOTE:** This mod is _technically_ server-side, but clients need the mod installed to be able to see and purchase any of the additional items added to the vanilla store rotation. Similarly, joining a lobby that doesn't have this mod installed will not modify the store rotation.~~ -**NOTE:** As of `v2.0.0`, this mod is now required to be installed on **both host and clients**, though I have commented code ready to once again make it (technically) server-side, if `CSync v4` reimplements the ability to join a lobby with either client or host missing this mod. +**NOTE:** As of `v2.0.0`, this mod is now required to be installed on **both host and clients**, though I have commented code ready to once again make it (technically) server-side, if `CSync` reimplements the ability to join a lobby with either client or host missing a mod that depends on it. --- -![alt](https://files.catbox.moe/o35ptg.png "Store with every vanilla item available for purchase, in alphabetical order.") \ No newline at end of file +![alt](https://files.catbox.moe/5nli7q.png "Store with every vanilla item available for purchase in v50, in alphabetical order.") \ No newline at end of file diff --git a/StoreRotationConfig/Config.cs b/StoreRotationConfig/Config.cs index 8f03e57..8f4f3ee 100644 --- a/StoreRotationConfig/Config.cs +++ b/StoreRotationConfig/Config.cs @@ -1,6 +1,7 @@ using BepInEx.Configuration; using CSync.Extensions; using CSync.Lib; +using StoreRotationConfig.Patches; using System.Runtime.Serialization; // using Unity.Netcode; // using UnityEngine; @@ -79,10 +80,16 @@ public Config(ConfigFile cfg) : base(Plugin.GUID) + "'relativeScroll' enabled.", new AcceptableValueRange(1, 28))); // ... + // Reset cached text if 'linesToScroll' is updated in-game. + LINES_TO_SCROLL.SettingChanged += new((_, _) => + { + TerminalScrollMousePatch.CurrentText = ""; + }); + // Register to sync config files between host and clients. ConfigManager.Register(this); - // Function to run once config is synced. + // Function to run once the config sync is completed. /* InitialSyncCompleted += new((_, _) => { // Return if local game instance is hosting the server. @@ -91,15 +98,11 @@ public Config(ConfigFile cfg) : base(Plugin.GUID) return; } - Plugin.StaticLogger.LogInfo("Config synced! тно Rotating store..."); - // Set config sync status to true (successfully synced). ConfigSynced = true; // Manually trigger a store rotation after config sync. - Terminal terminal = Object.FindObjectOfType(); - terminal?.ShipDecorSelection.Clear(); - terminal?.RotateShipDecorSelection(); + Plugin.Terminal.RotateShipDecorSelection(); }); */ } } diff --git a/StoreRotationConfig/Patches/RotateShipDecorSelectionPatch.cs b/StoreRotationConfig/Patches/RotateShipDecorSelectionPatch.cs index c20a394..db91576 100644 --- a/StoreRotationConfig/Patches/RotateShipDecorSelectionPatch.cs +++ b/StoreRotationConfig/Patches/RotateShipDecorSelectionPatch.cs @@ -1,6 +1,7 @@ using HarmonyLib; using System; using System.Collections.Generic; +using System.Reflection.Emit; using Unity.Netcode; namespace StoreRotationConfig.Patches @@ -14,7 +15,12 @@ internal class RotateShipDecorSelectionPatch // Cached list of every purchasable, non-persistent item available in the store. public static List AllItems { get; private set; } - private static bool Prefix(Terminal __instance) + /// + /// Fills 'Terminal.ShipDecorSelection' list with items, reading from the configuration file. + /// + /// List containing items currently shown in the store rotation. + /// Seeded Random instance used for generating store rotation. + private static void RotateShipDecorSelection(List shipDecorSelection, Random random) { // Return if client has not yet fully synced with the host. if (!NetworkManager.Singleton.IsHost && !NetworkManager.Singleton.IsServer && !SyncShipUnlockablesPatch.UnlockablesSynced) @@ -22,21 +28,20 @@ private static bool Prefix(Terminal __instance) { Plugin.StaticLogger.LogInfo("Waiting for sync from server before rotating store..."); - // Return false to stop vanilla method from executing. - return false; + return; } - // Obtain values from config file. - int maxItems = Plugin.Settings.MAX_ITEMS.Value, - minItems = Plugin.Settings.MIN_ITEMS.Value; + // Obtain values from the config file. + int maxItems = Math.Abs(Plugin.Settings.MAX_ITEMS.Value), + minItems = Math.Abs(Plugin.Settings.MIN_ITEMS.Value); bool stockAll = Plugin.Settings.STOCK_ALL.Value, sortItems = Plugin.Settings.SORT_ITEMS.Value; // ... // Check if 'Terminal.ShipDecorSelection' list is empty (first load). - if (__instance.ShipDecorSelection.Count == 0) + if (shipDecorSelection.Count == 0) { - // Initialize 'AllItems' list with specified capacity. + // Initialize 'AllItems' list with its capacity set to the total number of unlockable items. AllItems = new(StartOfRound.Instance.unlockablesList.unlockables.Count); // Fill 'AllItems' list with every purchasable, non-persistent item. @@ -55,54 +60,83 @@ private static bool Prefix(Terminal __instance) AllItems.Sort((x, y) => string.Compare(x.unlockableName, y.unlockableName)); } - // Fill store rotation with every item in 'AllItems'. - AllItems.ForEach(item => __instance.ShipDecorSelection.Add(item.shopSelectionNode)); + // Fill store rotation with every item in the 'AllItems' list. + AllItems.ForEach(item => shipDecorSelection.Add(item.shopSelectionNode)); } } - // Return false if 'stockAll' setting is enabled, since the store rotation list has already been filled at this point. + // Return if 'stockAll' setting is enabled, since the store rotation list has already been filled at this point. if (stockAll) { - return false; + return; } Plugin.StaticLogger.LogInfo("Rotating store..."); - // Clear previous store rotation list. - __instance.ShipDecorSelection.Clear(); + // Clear previous store rotation. + shipDecorSelection.Clear(); // Use 'maxItems' for 'minItems' if the latter is greater than the former. - minItems = (minItems < maxItems) ? minItems : maxItems; + if (minItems > maxItems) + { + minItems = maxItems; + } // Obtain a random number of items using the map seed, or use a fixed number if 'minItems' and 'maxItems' are equal. - Random random = new(StartOfRound.Instance.randomMapSeed + 65); - int num = (minItems != maxItems) ? random.Next(minItems, maxItems + 1) : maxItems; + int numItems = (minItems != maxItems) ? random.Next(minItems, maxItems + 1) : maxItems; - // Create 'storeRotation' list (for sorting), and clone 'AllItems' list (for item selection). - List storeRotation = new(num), allItems = new(AllItems); + // Create 'storeRotation' list (for sorting), and clone the 'AllItems' list (for item selection). + List storeRotation = new(numItems), allItems = new(AllItems); - // Iterate for every item to add to the store rotation (and exit early if there are no more items in 'allItems' cloned list). - for (int i = 0; i < num && allItems.Count != 0; i++) + // Iterate for every item to add to the store rotation, exiting early if there are no more items in the 'allItems' cloned list. + for (int i = 0; i < numItems && allItems.Count != 0; i++) { - // Add random item to 'storeRotation' list, and remove it from 'allItems' cloned list. + // Obtain a random item from the 'allItems' cloned list. int index = random.Next(0, allItems.Count); + + // Add random item to the 'storeRotation' list, and remove it from the 'allItems' cloned list. storeRotation.Add(allItems[index]); allItems.RemoveAt(index); } - // Sort 'storeRotation' list alphabetically if 'sortItems' is enabled. - if (sortItems && storeRotation.Count > 1) + // Check if 'sortItems' setting is enabled, and if there's more than one item in the 'shipDecorSelection' list. + if (sortItems && shipDecorSelection.Count > 1) { + // Sort 'storeRotation' list alphabetically. storeRotation.Sort((x, y) => string.Compare(x.unlockableName, y.unlockableName)); } - // Fill store rotation with every item in 'storeRotation' list. - storeRotation.ForEach(item => __instance.ShipDecorSelection.Add(item.shopSelectionNode)); + // Fill store rotation with every item in the 'storeRotation' list. + storeRotation.ForEach(item => shipDecorSelection.Add(item.shopSelectionNode)); Plugin.StaticLogger.LogInfo("Store rotated!"); + } - // Return false to stop vanilla method from executing. - return false; + /// + /// Inserts a call to 'RotateShipDecorSelectionPatch.RotateShipDecorSelection()', followed by a return instruction. + /// + /// ... (Terminal:1564) + /// Random random = new Random(StartOfRound.Instance.randomMapSeed + 65); + /// + /// -> StoreRotationConfig.Patches.RotateShipDecorSelectionPatch.RotateShipDecorSelection(this.ShipDecorSelection, random); + /// -> return; + /// + /// this.ShipDecorSelection.Clear(); + /// Iterator with original IL instructions. + /// Iterator with modified IL instructions. + private static IEnumerable Transpiler(IEnumerable instructions) + { + return new CodeMatcher(instructions).MatchForward(false, + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, AccessTools.Field(typeof(Terminal), nameof(Terminal.ShipDecorSelection))), + new(OpCodes.Callvirt, AccessTools.Method(typeof(List), nameof(List.Clear)))) + .Insert( + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, AccessTools.Field(typeof(Terminal), nameof(Terminal.ShipDecorSelection))), + new(OpCodes.Ldloc_0), + new(OpCodes.Call, AccessTools.Method(typeof(RotateShipDecorSelectionPatch), nameof(RotateShipDecorSelection))), + new(OpCodes.Ret) + ).InstructionEnumeration(); } } } \ No newline at end of file diff --git a/StoreRotationConfig/Patches/SyncShipUnlockablesPatches.cs b/StoreRotationConfig/Patches/SyncShipUnlockablesPatches.cs index c24e99d..c1d17c8 100644 --- a/StoreRotationConfig/Patches/SyncShipUnlockablesPatches.cs +++ b/StoreRotationConfig/Patches/SyncShipUnlockablesPatches.cs @@ -31,13 +31,14 @@ private static void SyncShipUnlockablesClientPost(int[] playerSuitIDs, bool ship // Return if unlockables are already synced with the host; toggle unlockable sync status if not. if (UnlockablesSynced) { - Plugin.StaticLogger.LogWarning("Purchased unlockable items already synced with the host..."); + Plugin.StaticLogger.LogDebug("Purchased unlockable items already synced with the host."); + return; } UnlockablesSynced = true; // Manually trigger a store rotation. - Object.FindObjectOfType().RotateShipDecorSelection(); + Plugin.Terminal.RotateShipDecorSelection(); } [HarmonyPatch(typeof(MenuManager), "Start")] diff --git a/StoreRotationConfig/Patches/TerminalScrollMousePatch.cs b/StoreRotationConfig/Patches/TerminalScrollMousePatch.cs index 043cfe6..ae88c5c 100644 --- a/StoreRotationConfig/Patches/TerminalScrollMousePatch.cs +++ b/StoreRotationConfig/Patches/TerminalScrollMousePatch.cs @@ -1,57 +1,82 @@ using GameNetcodeStuff; using HarmonyLib; +using System.Collections.Generic; using System.Linq; -using UnityEngine; +using System.Reflection.Emit; using UnityEngine.InputSystem; +using UnityEngine.UI; namespace StoreRotationConfig.Patches { /// - /// Patch for 'PlayerControllerB.ScrollMouse_performed()' method; replaces vanilla method unless the 'relativeScroll' setting is disabled. + /// Patch for 'PlayerControllerB.ScrollMouse_performed()' method; overrides vanilla scroll amount if the 'relativeScroll' setting is enabled. /// [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed", typeof(InputAction.CallbackContext))] internal class TerminalScrollMousePatch { - // Cached terminal instance. - private static Terminal terminal; + // Text shown in the current terminal page, to determine if scroll amount needs to be updated. + public static string CurrentText { get; internal set; } = ""; - // Text shown in the current terminal page. - private static string currentText = ""; + // Amount to add/subtract from the terminal scrollbar, relative to the number of lines in the current terminal page. + private static float scrollAmount = 1 / 3f; - // Amount to add/subtract from scrollbar value, relative to number of lines in the current terminal page. - private static float scrollAmount = 0f; - - private static bool Prefix(PlayerControllerB __instance, ref InputAction.CallbackContext context) + /// + /// Handles mouse scrolling while the terminal is open. + /// + /// Scrollbar instance used by the terminal. + /// Direction to move the scrollbar, determined by the mouse wheel input. + private static void ScrollMouse_performed(Scrollbar scrollbar, float scrollDirection) { - // Execute vanilla method if the 'relativeScroll' setting is disabled, or if the player instance does not have the terminal open. - if (!Plugin.Settings.RELATIVE_SCROLL.Value || !__instance.inTerminalMenu) + // Perform vanilla scroll if the 'relativeScroll' setting is disabled. + if (!Plugin.Settings.RELATIVE_SCROLL.Value) { - return true; - } + // Increment scrollbar value by vanilla scroll amount (a third of the page). + scrollbar.value += scrollDirection / 3f; - // Ensure cached terminal instance exists. - if (terminal == null) - { - terminal = Object.FindObjectOfType(); + return; } - // Check if text currently shown in the terminal has changed, to avoid calculating scroll amount more than once. - if (!currentText.Equals(terminal.currentText)) + // Check if text currently shown in the terminal has changed, to avoid calculating the scroll amount more than once. + if (string.CompareOrdinal(Plugin.Terminal.currentText, CurrentText) != 0) { // Cache text currently shown in the terminal. - currentText = terminal.currentText; + CurrentText = Plugin.Terminal.currentText; - // Calculate relative scroll amount using number of lines in the current terminal page. - int numLines = currentText.Count(c => c.Equals('\n')) + 1; + // Calculate relative scroll amount using the number of lines in the current terminal page. + int numLines = CurrentText.Count(c => c.Equals('\n')) + 1; scrollAmount = Plugin.Settings.LINES_TO_SCROLL.Value / (float)numLines; + + Plugin.StaticLogger.LogDebug($"Setting terminal scroll amount to '{scrollAmount}'!"); } - // Increment/decrement terminal scrollbar value by relative scroll amount. - float scrollDirection = context.ReadValue(); - __instance.terminalScrollVertical.value += scrollDirection * scrollAmount; + // Increment terminal scrollbar value by the relative scroll amount, in the direction given by the mouse wheel input. + scrollbar.value += scrollDirection * scrollAmount; + } - // Return false to stop vanilla method from executing. - return false; + /// + /// Inserts a call to 'TerminalScrollMousePatch.ScrollMouse_performed()', followed by a return instruction. + /// + /// ... (GameNetcodeStuff.PlayerControllerB:1263) + /// float num = context.ReadValue(); + /// + /// -> StoreRotationConfig.Patches.TerminalScrollMousePatch.ScrollMouse_performed(this.terminalScrollVertical, num); + /// -> return; + /// + /// this.terminalScrollVertical.value += num / 3f; + /// Iterator with original IL instructions. + /// Iterator with modified IL instructions. + private static IEnumerable Transpiler(IEnumerable instructions) + { + return new CodeMatcher(instructions).MatchForward(false, + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, AccessTools.Field(typeof(PlayerControllerB), nameof(PlayerControllerB.terminalScrollVertical)))) + .Insert( + new(OpCodes.Ldarg_0), + new(OpCodes.Ldfld, AccessTools.Field(typeof(PlayerControllerB), nameof(PlayerControllerB.terminalScrollVertical))), + new(OpCodes.Ldloc_0), + new(OpCodes.Call, AccessTools.Method(typeof(TerminalScrollMousePatch), nameof(ScrollMouse_performed))), + new(OpCodes.Ret)) + .InstructionEnumeration(); } } } \ No newline at end of file diff --git a/StoreRotationConfig/Patches/UnlockShipObjectPatches.cs b/StoreRotationConfig/Patches/UnlockShipObjectPatches.cs index 5ccdbc6..4005139 100644 --- a/StoreRotationConfig/Patches/UnlockShipObjectPatches.cs +++ b/StoreRotationConfig/Patches/UnlockShipObjectPatches.cs @@ -1,6 +1,5 @@ using HarmonyLib; using Unity.Netcode; -using UnityEngine; namespace StoreRotationConfig.Patches { @@ -10,15 +9,12 @@ namespace StoreRotationConfig.Patches [HarmonyPatch(typeof(StartOfRound))] internal class UnlockShipObjectPatch { - // Cached terminal instance. - private static Terminal terminal; - [HarmonyPatch("UnlockShipObject", typeof(int))] [HarmonyPrefix] private static void UnlockShipObjectPre(int unlockableID) { // Return if 'stockPurchased' setting is enabled, or if local game instance is not hosting the server. - if (Plugin.Settings.STOCK_PURCHASED || !(NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer)) + if (Plugin.Settings.STOCK_PURCHASED.Value || !(NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer)) { return; } @@ -33,7 +29,7 @@ private static void UnlockShipObjectPre(int unlockableID) private static void BuyShipUnlockableClientPre(int newGroupCreditsAmount, int unlockableID = -1) { // Return if 'stockPurchased' setting is true, or if local game instance is hosting the server. - if (Plugin.Settings.STOCK_PURCHASED || (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer)) + if (Plugin.Settings.STOCK_PURCHASED.Value || NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer) { return; } @@ -62,20 +58,15 @@ private static void RemoveItemFromRotation(int unlockableID) if (item.hasBeenUnlockedByPlayer || item.alreadyUnlocked) { Plugin.StaticLogger.LogWarning($"Unlockable #{unlockableID} has already been purchased."); + return; } // Remove item from 'RotateShipDecorSelectionPatch.AllItems' list. if (RotateShipDecorSelectionPatch.AllItems.Remove(item)) { - // Ensure cached terminal instance exists. - if (terminal == null) - { - terminal = Object.FindObjectOfType(); - } - // Remove item from 'Terminal.ShipDecorSelection' list. - if (!terminal.ShipDecorSelection.Remove(item.shopSelectionNode)) + if (!Plugin.Terminal.ShipDecorSelection.Remove(item.shopSelectionNode)) { Plugin.StaticLogger.LogWarning($"Unlockable #{unlockableID} was not found in the store rotation."); } diff --git a/StoreRotationConfig/Plugin.cs b/StoreRotationConfig/Plugin.cs index 02e65f9..baf525a 100644 --- a/StoreRotationConfig/Plugin.cs +++ b/StoreRotationConfig/Plugin.cs @@ -7,13 +7,13 @@ namespace StoreRotationConfig { /// - /// Simple mod that adds configurability to the number of items that show up in the store every week. + /// Configure the number of items in each store rotation, show them all, remove purchased items, or sort them. /// [BepInPlugin(GUID, PLUGIN_NAME, VERSION)] - [BepInDependency("com.sigurd.csync", "5.0.0")] + [BepInDependency("com.sigurd.csync", "5.0.1")] public class Plugin : BaseUnityPlugin { - internal const string GUID = "pacoito.StoreRotationConfig", PLUGIN_NAME = "StoreRotationConfig", VERSION = "2.1.0"; + internal const string GUID = "pacoito.StoreRotationConfig", PLUGIN_NAME = "StoreRotationConfig", VERSION = "2.2.0"; internal static ManualLogSource StaticLogger { get; private set; } /// @@ -21,6 +21,26 @@ public class Plugin : BaseUnityPlugin /// public static Config Settings { get; private set; } + /// + /// Cached terminal instance. + /// + /// An error will be thrown if the Terminal cannot be found or is missing. + public static Terminal Terminal + { + get + { + // Ensure cached terminal instance exists. + if (_terminal == null) + { + Terminal = FindObjectOfType(); + } + + return _terminal; + } + private set => _terminal = value ?? throw new ArgumentNullException("_terminal", "Terminal GameObject not found..."); + } + private static Terminal _terminal; + private void Awake() { StaticLogger = Logger; @@ -30,7 +50,7 @@ private void Awake() Settings = new(Config); _ = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), $"{GUID}"); - StaticLogger.LogInfo($"{PLUGIN_NAME} loaded!"); + StaticLogger.LogMessage($"{PLUGIN_NAME} loaded!"); } catch (Exception e) { diff --git a/StoreRotationConfig/StoreRotationConfig.csproj b/StoreRotationConfig/StoreRotationConfig.csproj index b82a979..9ab447c 100644 --- a/StoreRotationConfig/StoreRotationConfig.csproj +++ b/StoreRotationConfig/StoreRotationConfig.csproj @@ -2,8 +2,8 @@ StoreRotationConfig - Configure the number of purchasable items in each store rotation, or simply show them all. - 2.1.0 + Configure the number of items in each store rotation, show them all, remove purchased items, or sort them. + 2.1.1 @@ -38,7 +38,7 @@ - + managed\Assembly-CSharp.dll diff --git a/global.json b/global.json index 9912d94..5d26efd 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { - "sdk": { - "version": "7.0.408" - } + "sdk": { + "version": "7.0.408" + } } \ No newline at end of file diff --git a/manifest.json b/manifest.json index 6b946d6..e516aa9 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ { "name": "StoreRotationConfig", - "version_number": "2.1.0", + "version_number": "2.2.0", "website_url": "https://github.com/pacoito123/LC_StoreRotationConfig", - "description": "Configure the number of purchasable items in each store rotation, or simply show them all.", + "description": "Configure the number of items in each store rotation, show them all, remove purchased items, or sort them. Also includes a fix for the terminal scrolling too far and skipping lines.", "dependencies": [ "BepInEx-BepInExPack-5.4.2100", - "Sigurd-CSync-5.0.0" + "Sigurd-CSync-5.0.1" ] } \ No newline at end of file