diff --git a/MailboxMenu/CodePatches.cs b/MailboxMenu/CodePatches.cs index c9645ea1..e27664af 100644 --- a/MailboxMenu/CodePatches.cs +++ b/MailboxMenu/CodePatches.cs @@ -2,21 +2,32 @@ using StardewModdingAPI; using StardewValley; using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; +using StardewValley.Tools; namespace MailboxMenu { public partial class ModEntry { - - [HarmonyPatch(typeof(GameLocation), nameof(GameLocation.mailbox))] public class GameLocation_mailbox_Patch { + private static bool UsingMailServices() { + if (!isMailServicesActive) return false; + + return Game1.player.ActiveObject != null || + Game1.player.CurrentTool is Axe || + Game1.player.CurrentTool is Pickaxe || + Game1.player.CurrentTool is Hoe || + Game1.player.CurrentTool is WateringCan; + } + public static bool Prefix(GameLocation __instance) { - if (!Config.ModEnabled || !Config.MenuOnMailbox || (Config.ModKey != SButton.None && !SHelper.Input.IsDown(Config.ModKey))) + if (!Config.ModEnabled || + !Config.MenuOnMailbox || + (Config.ModKey != SButton.None && !SHelper.Input.IsDown(Config.ModKey)) || + UsingMailServices()) return true; + List list = new List(); foreach(var str in Game1.mailbox) { @@ -25,6 +36,7 @@ public static bool Prefix(GameLocation __instance) list.Add(str); } } + if(list.Count > 0) { foreach (var str in Game1.mailbox) @@ -39,6 +51,7 @@ public static bool Prefix(GameLocation __instance) } return true; } + Game1.activeClickableMenu = new MailMenu(); return false; } diff --git a/MailboxMenu/IGenericModConfigMenuApi.cs b/MailboxMenu/IGenericModConfigMenuApi.cs index ae9fa13d..3a48778d 100644 --- a/MailboxMenu/IGenericModConfigMenuApi.cs +++ b/MailboxMenu/IGenericModConfigMenuApi.cs @@ -24,25 +24,51 @@ public interface IGenericModConfigMenuApi /// Each mod can only be registered once, unless it's deleted via before calling this again. void Register(IManifest mod, Action reset, Action save, bool titleScreenOnly = false); - /// Add a key binding at the current position in the form. + + /**** + ** Basic options + ****/ + /// Add a section title at the current position in the form. + /// The mod's manifest. + /// The title text shown in the form. + /// The tooltip text shown when the cursor hovers on the title, or null to disable the tooltip. + void AddSectionTitle(IManifest mod, Func text, Func tooltip = null); + + /// Add a paragraph of text at the current position in the form. + /// The mod's manifest. + /// The paragraph text to display. + void AddParagraph(IManifest mod, Func text); + + /// Add an image at the current position in the form. + /// The mod's manifest. + /// The image texture to display. + /// The pixel area within the texture to display, or null to show the entire image. + /// The zoom factor to apply to the image. + void AddImage(IManifest mod, Func texture, Rectangle? texturePixelArea = null, int scale = Game1.pixelZoom); + + /// Add a boolean option at the current position in the form. /// The mod's manifest. /// Get the current value from the mod config. /// Set a new value in the mod config. /// The label text to show in the form. /// The tooltip text shown when the cursor hovers on the field, or null to disable the tooltip. /// The unique field ID for use with , or null to auto-generate a randomized ID. - void AddKeybind(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, string fieldId = null); + void AddBoolOption(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, string fieldId = null); - /// Add a boolean option at the current position in the form. + /// Add an integer option at the current position in the form. /// The mod's manifest. /// Get the current value from the mod config. /// Set a new value in the mod config. /// The label text to show in the form. /// The tooltip text shown when the cursor hovers on the field, or null to disable the tooltip. + /// The minimum allowed value, or null to allow any. + /// The maximum allowed value, or null to allow any. + /// The interval of values that can be selected. + /// Get the display text to show for a value, or null to show the number as-is. /// The unique field ID for use with , or null to auto-generate a randomized ID. - void AddBoolOption(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, string fieldId = null); + void AddNumberOption(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, int? min = null, int? max = null, int? interval = null, Func formatValue = null, string fieldId = null); - /// Add an integer option at the current position in the form. + /// Add a float option at the current position in the form. /// The mod's manifest. /// Get the current value from the mod config. /// Set a new value in the mod config. @@ -51,8 +77,9 @@ public interface IGenericModConfigMenuApi /// The minimum allowed value, or null to allow any. /// The maximum allowed value, or null to allow any. /// The interval of values that can be selected. + /// Get the display text to show for a value, or null to show the number as-is. /// The unique field ID for use with , or null to auto-generate a randomized ID. - void AddNumberOption(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, int? min = null, int? max = null, int? interval = null, string fieldId = null); + void AddNumberOption(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, float? min = null, float? max = null, float? interval = null, Func formatValue = null, string fieldId = null); /// Add a string option at the current position in the form. /// The mod's manifest. @@ -65,8 +92,86 @@ public interface IGenericModConfigMenuApi /// The unique field ID for use with , or null to auto-generate a randomized ID. void AddTextOption(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, string[] allowedValues = null, Func formatAllowedValue = null, string fieldId = null); + /// Add a key binding at the current position in the form. + /// The mod's manifest. + /// Get the current value from the mod config. + /// Set a new value in the mod config. + /// The label text to show in the form. + /// The tooltip text shown when the cursor hovers on the field, or null to disable the tooltip. + /// The unique field ID for use with , or null to auto-generate a randomized ID. + void AddKeybind(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, string fieldId = null); + + /// Add a key binding list at the current position in the form. + /// The mod's manifest. + /// Get the current value from the mod config. + /// Set a new value in the mod config. + /// The label text to show in the form. + /// The tooltip text shown when the cursor hovers on the field, or null to disable the tooltip. + /// The unique field ID for use with , or null to auto-generate a randomized ID. + void AddKeybindList(IManifest mod, Func getValue, Action setValue, Func name, Func tooltip = null, string fieldId = null); + + + /**** + ** Multi-page management + ****/ + /// Start a new page in the mod's config UI, or switch to that page if it already exists. All options registered after this will be part of that page. + /// The mod's manifest. + /// The unique page ID. + /// The page title shown in its UI, or null to show the value. + /// You must also call to make the page accessible. This is only needed to set up a multi-page config UI. If you don't call this method, all options will be part of the mod's main config UI instead. + void AddPage(IManifest mod, string pageId, Func pageTitle = null); + + /// Add a link to a page added via at the current position in the form. + /// The mod's manifest. + /// The unique ID of the page to open when the link is clicked. + /// The link text shown in the form. + /// The tooltip text shown when the cursor hovers on the link, or null to disable the tooltip. + void AddPageLink(IManifest mod, string pageId, Func text, Func tooltip = null); + + + /**** + ** Advanced + ****/ + /// Add an option at the current position in the form using custom rendering logic. + /// The mod's manifest. + /// The label text to show in the form. + /// Draw the option in the config UI. This is called with the sprite batch being rendered and the pixel position at which to start drawing. + /// The tooltip text shown when the cursor hovers on the field, or null to disable the tooltip. + /// A callback raised just before the menu containing this option is opened. + /// A callback raised before the form's current values are saved to the config (i.e. before the save callback passed to ). + /// A callback raised after the form's current values are saved to the config (i.e. after the save callback passed to ). + /// A callback raised before the form is reset to its default values (i.e. before the reset callback passed to ). + /// A callback raised after the form is reset to its default values (i.e. after the reset callback passed to ). + /// A callback raised just before the menu containing this option is closed. + /// The pixel height to allocate for the option in the form, or null for a standard input-sized option. This is called and cached each time the form is opened. + /// The unique field ID for use with , or null to auto-generate a randomized ID. + /// The custom logic represented by the callback parameters is responsible for managing its own state if needed. For example, you can store state in a static field or use closures to use a state variable. + void AddComplexOption(IManifest mod, Func name, Action draw, Func tooltip = null, Action beforeMenuOpened = null, Action beforeSave = null, Action afterSave = null, Action beforeReset = null, Action afterReset = null, Action beforeMenuClosed = null, Func height = null, string fieldId = null); + + /// Set whether the options registered after this point can only be edited from the title screen. + /// The mod's manifest. + /// Whether the options can only be edited from the title screen. + /// This lets you have different values per-field. Most mods should just set it once in . + void SetTitleScreenOnlyForNextOptions(IManifest mod, bool titleScreenOnly); + + /// Register a method to notify when any option registered by this mod is edited through the config UI. + /// The mod's manifest. + /// The method to call with the option's unique field ID and new value. + /// Options use a randomized ID by default; you'll likely want to specify the fieldId argument when adding options if you use this. + void OnFieldChanged(IManifest mod, Action onChange); + + /// Open the config UI for a specific mod. + /// The mod's manifest. + void OpenModMenu(IManifest mod); + + /// Get the currently-displayed mod config menu, if any. + /// The manifest of the mod whose config menu is being shown, or null if not applicable. + /// The page ID being shown for the current config menu, or null if not applicable. This may be null even if a mod config menu is shown (e.g. because the mod doesn't have pages). + /// Returns whether a mod config menu is being shown. + bool TryGetCurrentMenu(out IManifest mod, out string page); + /// Remove a mod from the config UI and delete all its options and pages. /// The mod's manifest. void Unregister(IManifest mod); } -} +} \ No newline at end of file diff --git a/MailboxMenu/MailMenu.cs b/MailboxMenu/MailMenu.cs index 5a67e6a1..44711d96 100644 --- a/MailboxMenu/MailMenu.cs +++ b/MailboxMenu/MailMenu.cs @@ -136,9 +136,7 @@ private void PopulateMailList() { List strings = new List(); int count = 0; - for (int i = 0; i < Game1.player.mailReceived.Count; i++) - { - string id = Game1.player.mailReceived[i]; + foreach (var id in Game1.player.mailReceived) { if (!mail.TryGetValue(id, out string mailData)) continue; if (Game1.mailbox.Contains(id)) @@ -157,7 +155,7 @@ private void PopulateMailList() } if (count >= mainScrolled * ModEntry.Config.GridColumns) { - AddMail(id, count - mainScrolled * ModEntry.Config.GridColumns, mailData); + AddMail(id, count - mainScrolled * ModEntry.Config.GridColumns, mailData); } count++; } @@ -347,8 +345,10 @@ public override void draw(SpriteBatch b) lines++; } } - SpriteText.drawString(b, ModEntry.Config.InboxText, inboxButton.bounds.X, inboxButton.bounds.Y, color: whichTab == 0 ? 0 : 8); - SpriteText.drawString(b, ModEntry.Config.ArchiveText, allMailButton.bounds.X, allMailButton.bounds.Y, color: whichTab == 1 ? 0 : 8); + SpriteText.drawString(b, ModEntry.Config.InboxText, inboxButton.bounds.X, inboxButton.bounds.Y, + color: whichTab == 0 ? Color.Black : Color.DarkGray); + SpriteText.drawString(b, ModEntry.Config.ArchiveText, allMailButton.bounds.X, allMailButton.bounds.Y, + color: whichTab == 1 ? Color.Black : Color.DarkGray); for(int i = 0; i < senders.Count; i++) { string str = senders[i].name; diff --git a/MailboxMenu/MailboxMenu.csproj b/MailboxMenu/MailboxMenu.csproj index 1e517c41..7080e75e 100644 --- a/MailboxMenu/MailboxMenu.csproj +++ b/MailboxMenu/MailboxMenu.csproj @@ -1,7 +1,7 @@  1.0.0 - net5.0 + net6.0 true AnyCPU;x64 diff --git a/MailboxMenu/ModEntry.cs b/MailboxMenu/ModEntry.cs index e7025c0e..1390f94b 100644 --- a/MailboxMenu/ModEntry.cs +++ b/MailboxMenu/ModEntry.cs @@ -1,22 +1,11 @@ using HarmonyLib; -using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using Newtonsoft.Json; using StardewModdingAPI; using StardewValley; -using StardewValley.BellsAndWhistles; -using StardewValley.Locations; -using StardewValley.Menus; -using StardewValley.Objects; -using StardewValley.TerrainFeatures; -using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; using System.IO; using System.Linq; -using System.Security.Permissions; -using Object = StardewValley.Object; +using Microsoft.Xna.Framework; namespace MailboxMenu { @@ -29,6 +18,7 @@ public partial class ModEntry : Mod public static ModConfig Config; public static ModEntry context; + public static bool isMailServicesActive; public static string npcPath = "aedenthorn.MailboxMenu/npcs"; public static string mailPath = "aedenthorn.MailboxMenu/letters"; @@ -55,7 +45,10 @@ public override void Entry(IModHelper helper) Helper.Events.Input.ButtonPressed += Input_ButtonPressed; var harmony = new Harmony(ModManifest.UniqueID); - harmony.PatchAll(); + harmony.Patch( + original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.mailbox)), + prefix: new HarmonyMethod(typeof(GameLocation_mailbox_Patch), nameof(GameLocation_mailbox_Patch.Prefix)) + ); } private void Input_ButtonPressed(object sender, StardewModdingAPI.Events.ButtonPressedEventArgs e) @@ -112,11 +105,14 @@ private void GameLoop_GameLaunched(object sender, StardewModdingAPI.Events.GameL { phoneAPI.AddApp("aedenthorn.MailboxMenu", "Mailbox", OpenMenu, Helper.ModContent.Load(Path.Combine("assets", "icon.png"))); } + // get Generic Mod Config Menu's API (if it's installed) var configMenu = Helper.ModRegistry.GetApi("spacechase0.GenericModConfigMenu"); if (configMenu is null) return; + isMailServicesActive = Helper.ModRegistry.IsLoaded("Digus.MailServicesMod"); + // register mod configMenu.Register( mod: ModManifest, diff --git a/MailboxMenu/manifest.json b/MailboxMenu/manifest.json index 0e9d8c5d..b04ba193 100644 --- a/MailboxMenu/manifest.json +++ b/MailboxMenu/manifest.json @@ -1,14 +1,14 @@ { "Name": "Mailbox Menu", "Author": "aedenthorn", - "Version": "0.3.3", + "Version": "0.3.5", "Description": "Mailbox Menu.", "UniqueID": "aedenthorn.MailboxMenu", "EntryDll": "MailboxMenu.dll", - "MinimumApiVersion": "3.15.0", + "MinimumApiVersion": "4.0.0", "ModUpdater": { "Repository": "StardewValleyMods", - "User": "aedenthorn", + "User": "tem696969696969", "Directory": "_releases", "ModFolder": "MailboxMenu" }, @@ -18,5 +18,5 @@ "IsRequired": false } ], - "UpdateKeys": [ "Nexus:14439" ] + "UpdateKeys": [ "Nexus:21068" ] } \ No newline at end of file