diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/.editorconfig | 2 | ||||
-rw-r--r-- | src/StardewModdingAPI/Context.cs | 17 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs | 4 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/Models/ModCompatibility.cs | 7 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/SGame.cs | 192 | ||||
-rw-r--r-- | src/StardewModdingAPI/Mod.cs | 2 | ||||
-rw-r--r-- | src/StardewModdingAPI/Program.cs | 17 | ||||
-rw-r--r-- | src/StardewModdingAPI/StardewModdingAPI.config.json | 307 |
8 files changed, 349 insertions, 199 deletions
diff --git a/src/.editorconfig b/src/.editorconfig index 3037884e..132fe6cb 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -11,6 +11,8 @@ indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true +[*.json] +indent_size = 2 ########## ## C# formatting diff --git a/src/StardewModdingAPI/Context.cs b/src/StardewModdingAPI/Context.cs index 45f6a05f..6bc5ae56 100644 --- a/src/StardewModdingAPI/Context.cs +++ b/src/StardewModdingAPI/Context.cs @@ -4,18 +4,27 @@ using StardewValley.Menus; namespace StardewModdingAPI { /// <summary>Provides information about the current game state.</summary> - internal static class Context + public static class Context { /********* ** Accessors *********/ + /**** + ** Public + ****/ + /// <summary>Whether the player has loaded a save and the world has finished initialising.</summary> + public static bool IsWorldReady { get; internal set; } + + /**** + ** Internal + ****/ /// <summary>Whether a player save has been loaded.</summary> - public static bool IsSaveLoaded => Game1.hasLoadedGame && !string.IsNullOrEmpty(Game1.player.name); + internal static bool IsSaveLoaded => Game1.hasLoadedGame && !string.IsNullOrEmpty(Game1.player.name); /// <summary>Whether the game is currently writing to the save file.</summary> - public static bool IsSaving => Game1.activeClickableMenu is SaveGameMenu || Game1.activeClickableMenu is ShippingMenu; // saving is performed by SaveGameMenu, but it's wrapped by ShippingMenu on days when the player shipping something + internal static bool IsSaving => Game1.activeClickableMenu is SaveGameMenu || Game1.activeClickableMenu is ShippingMenu; // saving is performed by SaveGameMenu, but it's wrapped by ShippingMenu on days when the player shipping something /// <summary>Whether the game is currently running the draw loop.</summary> - public static bool IsInDrawLoop { get; set; } + internal static bool IsInDrawLoop { get; set; } } } diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs index 2b081edc..00d4448b 100644 --- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs +++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs @@ -55,7 +55,7 @@ namespace StardewModdingAPI.Framework.ModLoading compatibility = ( from mod in compatibilityRecords where - mod.ID == key + mod.ID.Contains(key, StringComparer.InvariantCultureIgnoreCase) && (mod.LowerSemanticVersion == null || !manifest.Version.IsOlderThan(mod.LowerSemanticVersion)) && !manifest.Version.IsNewerThan(mod.UpperSemanticVersion) select mod @@ -93,7 +93,7 @@ namespace StardewModdingAPI.Framework.ModLoading bool hasUnofficialUrl = !string.IsNullOrWhiteSpace(mod.Compatibility.UnofficialUpdateUrl); string reasonPhrase = compatibility.ReasonPhrase ?? "it's not compatible with the latest version of the game"; - string error = $"{reasonPhrase}. Please check for a version newer than {compatibility.UpperVersion} here:"; + string error = $"{reasonPhrase}. Please check for a version newer than {compatibility.UpperVersionLabel ?? compatibility.UpperVersion} here:"; if (hasOfficialUrl) error += !hasUnofficialUrl ? $" {compatibility.UpdateUrl}" : $"{Environment.NewLine}- official mod: {compatibility.UpdateUrl}"; if (hasUnofficialUrl) diff --git a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs index 1e71dae0..90cbd237 100644 --- a/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs +++ b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs @@ -12,8 +12,8 @@ namespace StardewModdingAPI.Framework.Models /**** ** From config ****/ - /// <summary>The unique mod ID.</summary> - public string ID { get; set; } + /// <summary>The unique mod IDs.</summary> + public string[] ID { get; set; } /// <summary>The mod name.</summary> public string Name { get; set; } @@ -24,6 +24,9 @@ namespace StardewModdingAPI.Framework.Models /// <summary>The most recent incompatible mod version.</summary> public string UpperVersion { get; set; } + /// <summary>A label to show to the user instead of <see cref="UpperVersion"/>, when the manifest version differs from the user-facing version.</summary> + public string UpperVersionLabel { get; set; } + /// <summary>The URL the user can check for an official updated version.</summary> public string UpdateUrl { get; set; } diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index 7ee72af2..a340b995 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -39,9 +39,6 @@ namespace StardewModdingAPI.Framework /// <summary>The number of consecutive failed draws.</summary> private int FailedDraws; - /// <summary>Whether the player has loaded a save and the world has finished initialising.</summary> - private bool IsWorldReady => this.AfterLoadTimer < 0; - /// <summary>Whether the game is returning to the menu.</summary> private bool IsExiting; @@ -90,6 +87,9 @@ namespace StardewModdingAPI.Framework /// <summary>The keys that just entered the up state.</summary> private Keys[] FrameReleasedKeys => this.PreviouslyPressedKeys.Except(this.CurrentlyPressedKeys).ToArray(); + /// <summary>The previous save ID at last check.</summary> + private ulong PreviousSaveID; + /// <summary>A hash of <see cref="Game1.locations"/> at last check.</summary> private int PreviousGameLocations; @@ -168,7 +168,7 @@ namespace StardewModdingAPI.Framework private static Stopwatch _fpsStopwatch => SGame.Reflection.GetPrivateField<Stopwatch>(typeof(Game1), nameof(SGame._fpsStopwatch)).GetValue(); private static float _fps { - set { SGame.Reflection.GetPrivateField<float>(typeof(Game1), nameof(_fps)).SetValue(value); } + set => SGame.Reflection.GetPrivateField<float>(typeof(Game1), nameof(_fps)).SetValue(value); } private static Task _newDayTask => SGame.Reflection.GetPrivateField<Task>(typeof(Game1), nameof(_newDayTask)).GetValue(); private Color bgColor => SGame.Reflection.GetPrivateField<Color>(this, nameof(bgColor)).GetValue(); @@ -202,6 +202,15 @@ namespace StardewModdingAPI.Framework SGame.Reflection = reflection; Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef; // required by Stardew Valley + + // The game uses the default content manager instead of Game1.CreateContentManager in + // several cases (See http://community.playstarbound.com/threads/130058/page-27#post-3159274). + // The workaround is... + // 1. Override the default content manager. + // 2. Since Game1.content isn't initialised yet, and we need one main instance to + // support custom map tilesheets, detect when Game1.content is being initialised + // and use the same instance. + this.Content = new SContentManager(this.Content.ServiceProvider, this.Content.RootDirectory, this.Monitor); } /**** @@ -212,6 +221,12 @@ namespace StardewModdingAPI.Framework /// <param name="rootDirectory">The root directory to search for content.</param> protected override LocalizedContentManager CreateContentManager(IServiceProvider serviceProvider, string rootDirectory) { + // When Game1.content is being initialised, use SMAPI's main content manager instance. + // See comment in SGame constructor. + if (Game1.content == null && this.Content is SContentManager mainContentManager) + return mainContentManager; + + // build new instance return new SContentManager(this.Content.ServiceProvider, this.Content.RootDirectory, this.Monitor); } @@ -306,6 +321,7 @@ namespace StardewModdingAPI.Framework if (this.AfterLoadTimer == 0) { this.Monitor.Log($"Context: loaded saved game '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace); + Context.IsWorldReady = true; SaveEvents.InvokeAfterLoad(this.Monitor); PlayerEvents.InvokeLoadedGame(this.Monitor, new EventArgsLoadedGameChanged(Game1.hasLoadedGame)); @@ -322,9 +338,11 @@ namespace StardewModdingAPI.Framework this.IsExiting = true; // after exit to title - if (this.IsWorldReady && this.IsExiting && Game1.activeClickableMenu is TitleMenu) + if (Context.IsWorldReady && this.IsExiting && Game1.activeClickableMenu is TitleMenu) { this.Monitor.Log("Context: returned to title", LogLevel.Trace); + Context.IsWorldReady = false; + SaveEvents.InvokeAfterReturnToTitle(this.Monitor); this.AfterLoadTimer = 5; this.IsExiting = false; @@ -418,109 +436,83 @@ namespace StardewModdingAPI.Framework /********* ** World & player events *********/ - if (this.IsWorldReady) + if (Context.IsWorldReady) { - // raise location list changed - if (this.GetHash(Game1.locations) != this.PreviousGameLocations) - { - LocationEvents.InvokeLocationsChanged(this.Monitor, Game1.locations); - this.PreviousGameLocations = this.GetHash(Game1.locations); - } - - // raise current location changed - if (Game1.currentLocation != this.PreviousGameLocation) - { - if (this.VerboseLogging) - this.Monitor.Log($"Context: set location to {Game1.currentLocation?.Name ?? "(none)"}.", LogLevel.Trace); - LocationEvents.InvokeCurrentLocationChanged(this.Monitor, this.PreviousGameLocation, Game1.currentLocation); - this.PreviousGameLocation = Game1.currentLocation; - } - - // raise player changed - if (Game1.player != this.PreviousFarmer) - { - PlayerEvents.InvokeFarmerChanged(this.Monitor, this.PreviousFarmer, Game1.player); - this.PreviousFarmer = Game1.player; - } - - // raise player leveled up a skill - if (Game1.player.combatLevel != this.PreviousCombatLevel) - { - PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Combat, Game1.player.combatLevel); - this.PreviousCombatLevel = Game1.player.combatLevel; - } - if (Game1.player.farmingLevel != this.PreviousFarmingLevel) - { - PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Farming, Game1.player.farmingLevel); - this.PreviousFarmingLevel = Game1.player.farmingLevel; - } - if (Game1.player.fishingLevel != this.PreviousFishingLevel) - { - PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Fishing, Game1.player.fishingLevel); - this.PreviousFishingLevel = Game1.player.fishingLevel; - } - if (Game1.player.foragingLevel != this.PreviousForagingLevel) - { - PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Foraging, Game1.player.foragingLevel); - this.PreviousForagingLevel = Game1.player.foragingLevel; - } - if (Game1.player.miningLevel != this.PreviousMiningLevel) - { - PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Mining, Game1.player.miningLevel); - this.PreviousMiningLevel = Game1.player.miningLevel; - } - if (Game1.player.luckLevel != this.PreviousLuckLevel) + // raise events (only when something changes, not on the initial load) + if (Game1.uniqueIDForThisGame == this.PreviousSaveID) { - PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Luck, Game1.player.luckLevel); - this.PreviousLuckLevel = Game1.player.luckLevel; - } + // raise location list changed + if (this.GetHash(Game1.locations) != this.PreviousGameLocations) + LocationEvents.InvokeLocationsChanged(this.Monitor, Game1.locations); - // raise player inventory changed - ItemStackChange[] changedItems = this.GetInventoryChanges(Game1.player.items, this.PreviousItems).ToArray(); - if (changedItems.Any()) - { - PlayerEvents.InvokeInventoryChanged(this.Monitor, Game1.player.items, changedItems); - this.PreviousItems = Game1.player.items.Where(n => n != null).ToDictionary(n => n, n => n.Stack); - } - - // raise current location's object list changed - { - int? objectHash = Game1.currentLocation?.objects != null ? this.GetHash(Game1.currentLocation.objects) : (int?)null; - if (objectHash != null && this.PreviousLocationObjects != objectHash) + // raise current location changed + if (Game1.currentLocation != this.PreviousGameLocation) { - LocationEvents.InvokeOnNewLocationObject(this.Monitor, Game1.currentLocation.objects); - this.PreviousLocationObjects = objectHash.Value; + if (this.VerboseLogging) + this.Monitor.Log($"Context: set location to {Game1.currentLocation?.Name ?? "(none)"}.", LogLevel.Trace); + LocationEvents.InvokeCurrentLocationChanged(this.Monitor, this.PreviousGameLocation, Game1.currentLocation); } - } - // raise time changed - if (Game1.timeOfDay != this.PreviousTime) - { - TimeEvents.InvokeTimeOfDayChanged(this.Monitor, this.PreviousTime, Game1.timeOfDay); - this.PreviousTime = Game1.timeOfDay; - } - if (Game1.dayOfMonth != this.PreviousDay) - { - TimeEvents.InvokeDayOfMonthChanged(this.Monitor, this.PreviousDay, Game1.dayOfMonth); - this.PreviousDay = Game1.dayOfMonth; - } - if (Game1.currentSeason != this.PreviousSeason) - { - TimeEvents.InvokeSeasonOfYearChanged(this.Monitor, this.PreviousSeason, Game1.currentSeason); - this.PreviousSeason = Game1.currentSeason; - } - if (Game1.year != this.PreviousYear) - { - TimeEvents.InvokeYearOfGameChanged(this.Monitor, this.PreviousYear, Game1.year); - this.PreviousYear = Game1.year; - } + // raise player changed + if (Game1.player != this.PreviousFarmer) + PlayerEvents.InvokeFarmerChanged(this.Monitor, this.PreviousFarmer, Game1.player); + + // raise player leveled up a skill + if (Game1.player.combatLevel != this.PreviousCombatLevel) + PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Combat, Game1.player.combatLevel); + if (Game1.player.farmingLevel != this.PreviousFarmingLevel) + PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Farming, Game1.player.farmingLevel); + if (Game1.player.fishingLevel != this.PreviousFishingLevel) + PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Fishing, Game1.player.fishingLevel); + if (Game1.player.foragingLevel != this.PreviousForagingLevel) + PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Foraging, Game1.player.foragingLevel); + if (Game1.player.miningLevel != this.PreviousMiningLevel) + PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Mining, Game1.player.miningLevel); + if (Game1.player.luckLevel != this.PreviousLuckLevel) + PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Luck, Game1.player.luckLevel); + + // raise player inventory changed + ItemStackChange[] changedItems = this.GetInventoryChanges(Game1.player.items, this.PreviousItems).ToArray(); + if (changedItems.Any()) + PlayerEvents.InvokeInventoryChanged(this.Monitor, Game1.player.items, changedItems); + + // raise current location's object list changed + if (this.GetHash(Game1.currentLocation.objects) != this.PreviousLocationObjects) + LocationEvents.InvokeOnNewLocationObject(this.Monitor, Game1.currentLocation.objects); - // raise mine level changed - if (Game1.mine != null && Game1.mine.mineLevel != this.PreviousMineLevel) - { - MineEvents.InvokeMineLevelChanged(this.Monitor, this.PreviousMineLevel, Game1.mine.mineLevel); - this.PreviousMineLevel = Game1.mine.mineLevel; + // raise time changed + if (Game1.timeOfDay != this.PreviousTime) + TimeEvents.InvokeTimeOfDayChanged(this.Monitor, this.PreviousTime, Game1.timeOfDay); + if (Game1.dayOfMonth != this.PreviousDay) + TimeEvents.InvokeDayOfMonthChanged(this.Monitor, this.PreviousDay, Game1.dayOfMonth); + if (Game1.currentSeason != this.PreviousSeason) + TimeEvents.InvokeSeasonOfYearChanged(this.Monitor, this.PreviousSeason, Game1.currentSeason); + if (Game1.year != this.PreviousYear) + TimeEvents.InvokeYearOfGameChanged(this.Monitor, this.PreviousYear, Game1.year); + + // raise mine level changed + if (Game1.mine != null && Game1.mine.mineLevel != this.PreviousMineLevel) + MineEvents.InvokeMineLevelChanged(this.Monitor, this.PreviousMineLevel, Game1.mine.mineLevel); } + + // update state + this.PreviousGameLocations = this.GetHash(Game1.locations); + this.PreviousGameLocation = Game1.currentLocation; + this.PreviousFarmer = Game1.player; + this.PreviousCombatLevel = Game1.player.combatLevel; + this.PreviousFarmingLevel = Game1.player.farmingLevel; + this.PreviousFishingLevel = Game1.player.fishingLevel; + this.PreviousForagingLevel = Game1.player.foragingLevel; + this.PreviousMiningLevel = Game1.player.miningLevel; + this.PreviousLuckLevel = Game1.player.luckLevel; + this.PreviousItems = Game1.player.items.Where(n => n != null).ToDictionary(n => n, n => n.Stack); + this.PreviousLocationObjects = this.GetHash(Game1.currentLocation.objects); + this.PreviousTime = Game1.timeOfDay; + this.PreviousDay = Game1.dayOfMonth; + this.PreviousSeason = Game1.currentSeason; + this.PreviousYear = Game1.year; + this.PreviousMineLevel = Game1.mine.mineLevel; + this.PreviousSaveID = Game1.uniqueIDForThisGame; } /********* diff --git a/src/StardewModdingAPI/Mod.cs b/src/StardewModdingAPI/Mod.cs index a65b135c..171088cf 100644 --- a/src/StardewModdingAPI/Mod.cs +++ b/src/StardewModdingAPI/Mod.cs @@ -116,7 +116,7 @@ namespace StardewModdingAPI return Path.Combine(this.PathOnDisk, "psconfigs"); } - /// <summary>Release or reset unmanaged resources.</summary> + /// <summary>Release or reset unmanaged resources when the game exits. There's no guarantee this will be called on every exit.</summary> /// <param name="disposing">Whether the instance is being disposed explicitly rather than finalised. If this is false, the instance shouldn't dispose other objects since they may already be finalised.</param> protected virtual void Dispose(bool disposing) { } diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 743de050..228071ce 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -324,9 +324,20 @@ namespace StardewModdingAPI IList<Action> deprecationWarnings = new List<Action>(); foreach (IModMetadata mod in mods) { - // missing unique ID - if (string.IsNullOrWhiteSpace(mod.Manifest.UniqueID)) - deprecationWarnings.Add(() => this.Monitor.Log($"{mod.DisplayName} doesn't have specify a {nameof(IManifest.UniqueID)} field in its manifest. This will be required in an upcoming SMAPI release.", LogLevel.Warn)); + // missing fields that will be required in SMAPI 2.0 + { + List<string> missingFields = new List<string>(3); + + if (string.IsNullOrWhiteSpace(mod.Manifest.Name)) + missingFields.Add(nameof(IManifest.Name)); + if (mod.Manifest.Version.ToString() == "0.0") + missingFields.Add(nameof(IManifest.Version)); + if (string.IsNullOrWhiteSpace(mod.Manifest.UniqueID)) + missingFields.Add(nameof(IManifest.UniqueID)); + + if (missingFields.Any()) + deprecationWarnings.Add(() => this.Monitor.Log($"{mod.Manifest.Name} is missing some manifest fields ({string.Join(", ", missingFields)}) which will be required in an upcoming SMAPI version.", LogLevel.Warn)); + } // per-save directories if ((mod.Manifest as Manifest)?.PerSaveConfigs == true) diff --git a/src/StardewModdingAPI/StardewModdingAPI.config.json b/src/StardewModdingAPI/StardewModdingAPI.config.json index f42a4dfc..08bd3cff 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.config.json +++ b/src/StardewModdingAPI/StardewModdingAPI.config.json @@ -34,251 +34,384 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ModCompatibility": [ { "Name": "AccessChestAnywhere", - "ID": "AccessChestAnywhere", + "ID": [ "AccessChestAnywhere" ], "UpperVersion": "1.1", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/257", "UnofficialUpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", - "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'." + "Notes": "Needs update for SDV 1.1." }, { "Name": "Almighty Tool", - "ID": "AlmightyTool.dll", + "ID": [ "AlmightyTool.dll" ], "UpperVersion": "1.1.1", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/439", - "Notes": "Uses obsolete StardewModdingAPI.Extensions." + "Notes": "Needs update for SDV 1.2." }, { "Name": "Better Sprinklers", - "ID": "SPDSprinklersMod", + "ID": [ "SPDSprinklersMod", /*since 2.3*/ "Speeder.BetterSprinklers" ], "UpperVersion": "2.3", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/41", - "Notes": "Uses obsolete StardewModdingAPI.Extensions." + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "Notes": "Needs update for SDV 1.2." }, { - "Name": "Better Sprinklers", - "ID": "Speeder.BetterSprinklers", - "UpperVersion": "2.3", + "Name": "Birthday Mail", + "ID": [ "005e02dc-d900-425c-9c68-1ff55c5a295d" ], + "UpperVersion": "1.2.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/41", - "Notes": "ID changed in 2.3. Uses obsolete StardewModdingAPI.Extensions." + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/276", + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Chest Label System", - "ID": "SPDChestLabel", - "UpperVersion": "1.5", + "ID": [ "SPDChestLabel" ], + "UpperVersion": "1.6", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/242", - "Notes": "Not compatible with Stardew Valley 1.1+" + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "Notes": "Needs update for SDV 1.1." }, { - "Name": "Chests Anywhere", - "ID": "ChestsAnywhere", - "UpperVersion": "1.8.2", + "Name": "Chest Pooling", + "ID": [ "ChestPooling.dll" ], + "UpperVersion": "1.2", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", - "Notes": "Crashes with 'Method not found: Void StardewValley.Menus.TextBox.set_Highlighted(Boolean)'." + "UpdateUrl": "http://community.playstarbound.com/threads/111988", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Chests Anywhere", - "ID": "Pathoschild.ChestsAnywhere", + "ID": [ "ChestsAnywhere", /*since 1.9*/ "Pathoschild.ChestsAnywhere" ], "UpperVersion": "1.9-beta", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/518", - "Notes": "ID changed in 1.9. Crashes with InvalidOperationException: 'The menu doesn't seem to have a player inventory'." + "Notes": "Needs update for SDV 1.2." }, { "Name": "CJB Automation", - "ID": "CJBAutomation", + "ID": [ "CJBAutomation" ], "UpperVersion": "1.4", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/211", - "Notes": "Crashes with 'Method not found: Void StardewValley.Item.set_Name(System.String)'." + "UnofficialUpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/1063", + "Notes": "Needs update for SDV 1.2." }, { "Name": "CJB Cheats Menu", - "ID": "CJBCheatsMenu", + "ID": [ "CJBCheatsMenu" ], "UpperVersion": "1.12", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/4", - "Notes": "Not compatible with Stardew Valley 1.1+" + "Notes": "Needs update for SDV 1.1." }, { "Name": "CJB Item Spawner", - "ID": "CJBItemSpawner", + "ID": [ "CJBItemSpawner" ], "UpperVersion": "1.5", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/93", - "Notes": "Not compatible with Stardew Valley 1.1+" + "Notes": "Needs update for SDV 1.1." }, { "Name": "CJB Show Item Sell Price", - "ID": "CJBShowItemSellPrice", + "ID": [ "CJBShowItemSellPrice" ], "UpperVersion": "1.6", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/93", - "Notes": "Uses SMAPI's internal SGame class." + "Notes": "Needs update for SDV 1.2." }, { "Name": "Cooking Skill", - "ID": "CookingSkill", + "ID": [ "CookingSkill" ], "UpperVersion": "1.0.3", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/522", - "Notes": "Crashes with 'Method not found: Void StardewValley.Buff..ctor(Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, System.String)'." + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "Cooking Skill Prestige Adapter", + "ID": [ "20d6b8a3-b6e7-460b-a6e4-07c2b0cb6c63" ], + "UpperVersion": "1.0.4", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/569", + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Enemy Health Bars", - "ID": "SPDHealthBar", + "ID": [ "SPDHealthBar" ], "UpperVersion": "1.7", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/193", - "Notes": "Uses obsolete GraphicsEvents.DrawTick." + "UnofficialUrl": "http://community.playstarbound.com/threads/132096", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Entoarox Framework", - "ID": "eacdb74b-4080-4452-b16b-93773cda5cf9", - "UpperVersion": "1.6.5", + "ID": [ "eacdb74b-4080-4452-b16b-93773cda5cf9", /*since ???*/ "Entoarox.EntoaroxFramework" ], + "UpperVersion": "1.7.5", "Compatibility": "AssumeBroken", "UpdateUrl": "http://community.playstarbound.com/resources/4228", - "Notes": "Uses obsolete StardewModdingAPI.Inheritance.SObject until 1.6.1; then crashes until 1.6.4 ('Entoarox Framework requested an immediate game shutdown: Fatal error attempting to update player tick properties System.NullReferenceException: Object reference not set to an instance of an object. at Entoarox.Framework.PlayerHelper.Update(Object s, EventArgs e)')." + "Notes": "Needs update for SDV 1.2." }, { "Name": "Extended Fridge", - "ID": "Mystra007ExtendedFridge", + "ID": [ "Mystra007ExtendedFridge" ], "UpperVersion": "1.0", + "UpperVersionLabel": "0.94", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/485", - "Notes": "Actual upper version is 0.94, but mod incorrectly sets it to 1.0 in the manifest. Crashes with 'Field not found: StardewValley.Game1.mouseCursorTransparency'." + "Notes": "Needs update for SDV 1.2. Actual upper version is 0.94, but mod incorrectly sets it to 1.0 in the manifest." + }, + { + "Name": "FarmAutomation.ItemCollector", + "ID": [ "FarmAutomation.ItemCollector.dll", /*since 0.4*/ "Maddy99.FarmAutomation.ItemCollector" ], + "UpperVersion": "0.4", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/threads/125172", + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "Instant Geode", + "ID": [ "InstantGeode" ], + "UpperVersion": "1.12", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/threads/109038", + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "Gate Opener", + "ID": [ "GateOpener.dll", /*since 1.1*/ "mralbobo.GateOpener" ], + "UpperVersion": "1.0.1", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/threads/111988", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Get Dressed", - "ID": "GetDressed.dll", - "UpperVersion": "3.2", + "ID": [ "GetDressed.dll", /*since 3.3*/ "Advize.GetDressed" ], + "UpperVersion": "3.3", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/331", - "Notes": "Crashes with NullReferenceException in GameEvents.UpdateTick." + "Notes": "Needs update for SDV 1.2." }, { - "Name": "Lookup Anything", - "ID": "LookupAnything", - "UpperVersion": "1.10", + "Name": "Gift Taste Helper", + "ID": [ "8008db57-fa67-4730-978e-34b37ef191d6" ], + "UpperVersion": "2.3.1", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", - "Notes": "Crashes with FormatException when looking up NPCs." + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/229", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Lookup Anything", - "ID": "Pathoschild.LookupAnything", + "ID": [ "LookupAnything", /*since 1.10.1*/ "Pathoschild.LookupAnything" ], "UpperVersion": "1.10.1", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/541", - "Notes": "ID changed in 1.10.1. Crashes with FormatException when looking up NPCs." + "Notes": "Needs update for SDV 1.2." }, { "Name": "Makeshift Multiplayer", - "ID": "StardewValleyMP", + "ID": [ "StardewValleyMP", /*since 0.3*/ "spacechase0.StardewValleyMP" ], "Compatibility": "AssumeBroken", - "UpperVersion": "0.2.10", + "UpperVersion": "0.3.3", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/501", - "Notes": "Uses obsolete GraphicsEvents.OnPreRenderHudEventNoCheck." + "Notes": "Needs update for SDV 1.2." }, { "Name": "NoSoilDecay", - "ID": "289dee03-5f38-4d8e-8ffc-e440198e8610", + "ID": [ "289dee03-5f38-4d8e-8ffc-e440198e8610" ], "UpperVersion": "0.5", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/237", - "Notes": "Uses obsolete StardewModdingAPI.Extensions and Assembly.GetExecutingAssembly().Location." + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "Notes": "Needs update for SDV 1.2, and uses Assembly.GetExecutingAssembly().Location." }, { "Name": "NPC Map Locations", - "ID": "NPCMapLocationsMod", + "ID": [ "NPCMapLocationsMod" ], "LowerVersion": "1.42", "UpperVersion": "1.43", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/239", - "ReasonPhrase": "this version has an update check error which crashes the game" + "ReasonPhrase": "These versions have an update check error which crash the game." + }, + { + "Name": "Part of the Community", + "ID": [ "SB_PotC" ], + "UpperVersion": "1.0.8", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/923", + "ReasonPhrase": "Needs update for SDV 1.2." }, { "Name": "Point-and-Plant", - "ID": "PointAndPlant.dll", + "ID": [ "PointAndPlant.dll" ], "UpperVersion": "1.0.2", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/572", - "Notes": "Uses obsolete StardewModdingAPI.Extensions." + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "PrairieKingMadeEasy", + "ID": [ "PrairieKingMadeEasy.dll" ], + "UpperVersion": "1.0.0", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/resources/3594", + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "Rush Orders", + "ID": [ "RushOrders", /*since 1.1*/ "spacechase0.RushOrders" ], + "UpperVersion": "1.1", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/605", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Save Anywhere", - "ID": "SaveAnywhere", - "UpperVersion": "2.0", + "ID": [ "SaveAnywhere" ], + "UpperVersion": "2.3", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/444", - "Notes": "Depends on StarDustCore." + "Notes": "Needs update for SDV 1.2." }, { - "Name": "StackSplitX", - "ID": "StackSplitX.dll", + "Name": "Simple Sprinklers", + "ID": [ "SimpleSprinkler.dll" ], + "UpperVersion": "1.4", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/76", + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "Sprint and Dash", + "ID": [ "SPDSprintAndDash" ], "UpperVersion": "1.0", "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/resources/3531", + "UnofficialUpdateUrl": "http://community.playstarbound.com/resources/4201", + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "Sprint and Dash Redux", + "ID": [ "SPDSprintAndDash" ], + "UpperVersion": "1.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/resources/4201", + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "StackSplitX", + "ID": [ "StackSplitX.dll" ], + "UpperVersion": "1.2", + "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/798", - "Notes": "Uses SMAPI's internal SGame class." + "Notes": "Needs update for SDV 1.2." }, { "Name": "StarDustCore", - "ID": "StarDustCore", + "ID": [ "StarDustCore" ], "UpperVersion": "1.0", "Compatibility": "AssumeBroken", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/683", - "Notes": "Crashes with 'Method not found: Void StardewModdingAPI.Command.CallCommand(System.String)'." + "Notes": "Obsolete (originally needed by Save Anywhere); broken in SDV 1.2." }, { "Name": "Teleporter", - "ID": "Teleporter", + "ID": [ "Teleporter" ], "UpperVersion": "1.0.2", "Compatibility": "AssumeBroken", "UpdateUrl": "http://community.playstarbound.com/resources/4374", - "Notes": "Crashes with 'InvalidOperationException: The StardewValley.Menus.MapPage object doesn't have a private 'points' instance field'." + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "UiModSuite", + "ID": [ "Demiacle.UiModSuite" ], + "UpperVersion": "0.5", + "UpperVersionLabel": "1.0", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/1023", + "Notes": "Needs update for SDV 1.2. Actual upper version is 1.0, but mod incorrectly sets it to 0.5 in the manifest." + }, + { + "Name": "Weather Controller", + "ID": [ "WeatherController.dll" ], + "UpperVersion": "1.0.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/threads/111526", + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/132096", + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "zDailyIncrease", + "ID": [ "zdailyincrease" ], + "UpperVersion": "1.2", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/resources/4247", + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "Zoom Out Extreme", + "ID": [ "ZoomMod" ], + "UpperVersion": "0.1", + "Compatibility": "AssumeBroken", + "UpdateUrl": "http://community.playstarbound.com/threads/115028", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Zoryn's Better RNG", - "ID": "76b6d1e1-f7ba-4d72-8c32-5a1e6d2716f6", - "UpperVersion": "1.5", + "ID": [ "76b6d1e1-f7ba-4d72-8c32-5a1e6d2716f6", /*since 1.6*/ "Zoryn.BetterRNG" ], + "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/108756", - "Notes": "Uses SMAPI's internal SGame class." + "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Zoryn's Calendar Anywhere", - "ID": "a41c01cd-0437-43eb-944f-78cb5a53002a", - "UpperVersion": "1.5", + "ID": [ "a41c01cd-0437-43eb-944f-78cb5a53002a", /*since 1.6*/ "Zoryn.CalendarAnywhere" ], + "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/108756", - "Notes": "Uses SMAPI's internal SGame class." + "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Zoryn's Health Bars", - "ID": "HealthBars.dll", - "UpperVersion": "1.5", + "ID": [ "HealthBars.dll", /*since 1.6*/ "Zoryn.HealthBars" ], + "UpperVersion": "1.6", + "Compatibility": "AssumeBroken", + "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "Notes": "Needs update for SDV 1.2." + }, + { + "Name": "Zoryn's Junimo Deposit Anywhere", + "ID": [ "f93a4fe8-cade-4146-9335-b5f82fbbf7bc", /*since 1.6*/ "Zoryn.JunimoDepositAnywhere" ], + "UpperVersion": "1.7", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/108756", - "Notes": "Uses SMAPI's internal SGame class." + "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Zoryn's Movement Mod", - "ID": "8a632929-8335-484f-87dd-c29d2ba3215d", - "UpperVersion": "1.5", + "ID": [ "8a632929-8335-484f-87dd-c29d2ba3215d", /*since 1.6*/ "Zoryn.MovementModifier" ], + "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/108756", - "Notes": "Uses SMAPI's internal SGame class." + "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "Notes": "Needs update for SDV 1.2." }, { "Name": "Zoryn's Regen Mod", - "ID": "dfac4383-1b6b-4f33-ae4e-37fc23e5252e", - "UpperVersion": "1.5", + "ID": [ "dfac4383-1b6b-4f33-ae4e-37fc23e5252e", /*since 1.6*/ "Zoryn.RegenMod" ], + "UpperVersion": "1.6", "Compatibility": "AssumeBroken", - "UpdateUrl": "http://community.playstarbound.com/threads/108756", - "Notes": "Uses SMAPI's internal SGame class." + "UpdateUrl": "https://github.com/Zoryn4163/SMAPI-Mods/releases", + "Notes": "Needs update for SDV 1.2." } ] } |