fix content packs always failing to load if they declare a dependency on a SMAPI mod

This commit is contained in:
Jesse Plamondon-Willard 2018-11-16 21:29:28 -05:00
parent ba0acf89c1
commit dcfae980bf
No known key found for this signature in database
GPG Key ID: 7D7C8097B62033CE
4 changed files with 26 additions and 21 deletions

View File

@ -44,7 +44,8 @@
* added support for overlaying image assets with semi-transparency;
* mods can now load PNGs even if the game is currently drawing.
* When comparing mod versions, SMAPI now considers `-unofficial` to be lower-precedence than any other value (e.g. `1.0-beta` is now considered newer than `1.0-unofficial` regardless of normal sorting).
* Fixed `IContentPack.ReadJsonFile` allowing non-relative paths.
* Fixed content packs' `ReadJsonFile` allowing non-relative paths.
* Fixed content pack always failing to load if they declare a dependency on a SMAPI mod.
* Fixed trace logs not showing path for invalid mods.
* Fixed 'no update keys' warning not shown for mods with only invalid update keys.
* Fixed `Context.IsPlayerFree` being true before the player finishes transitioning to a new location in multiplayer.

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using StardewModdingAPI.Events;
using StardewModdingAPI.Framework.Input;
using StardewModdingAPI.Toolkit.Serialisation;
@ -17,7 +16,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
** Properties
*********/
/// <summary>The content packs loaded for this mod.</summary>
private readonly IContentPack[] ContentPacks;
private readonly Lazy<IContentPack[]> ContentPacks;
/// <summary>Create a transitional content pack.</summary>
private readonly Func<string, IManifest, IContentPack> CreateContentPack;
@ -84,7 +83,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="deprecationManager">Manages deprecation warnings.</param>
/// <exception cref="ArgumentNullException">An argument is null or empty.</exception>
/// <exception cref="InvalidOperationException">The <paramref name="modDirectory"/> path does not exist on disk.</exception>
public ModHelper(string modID, string modDirectory, JsonHelper jsonHelper, SInputState inputState, IModEvents events, IContentHelper contentHelper, ICommandHelper commandHelper, IDataHelper dataHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper, IEnumerable<IContentPack> contentPacks, Func<string, IManifest, IContentPack> createContentPack, DeprecationManager deprecationManager)
public ModHelper(string modID, string modDirectory, JsonHelper jsonHelper, SInputState inputState, IModEvents events, IContentHelper contentHelper, ICommandHelper commandHelper, IDataHelper dataHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper, Func<IContentPack[]> contentPacks, Func<string, IManifest, IContentPack> createContentPack, DeprecationManager deprecationManager)
: base(modID)
{
// validate directory
@ -104,7 +103,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
this.Reflection = reflectionHelper ?? throw new ArgumentNullException(nameof(reflectionHelper));
this.Multiplayer = multiplayer ?? throw new ArgumentNullException(nameof(multiplayer));
this.Translation = translationHelper ?? throw new ArgumentNullException(nameof(translationHelper));
this.ContentPacks = contentPacks.ToArray();
this.ContentPacks = new Lazy<IContentPack[]>(contentPacks);
this.CreateContentPack = createContentPack;
this.DeprecationManager = deprecationManager;
this.Events = events;
@ -204,7 +203,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <summary>Get all content packs loaded for this mod.</summary>
public IEnumerable<IContentPack> GetContentPacks()
{
return this.ContentPacks;
return this.ContentPacks.Value;
}
/****

View File

@ -18,6 +18,9 @@ namespace StardewModdingAPI.Framework
/// <summary>An assembly full name => mod lookup.</summary>
private readonly IDictionary<string, IModMetadata> ModNamesByAssembly = new Dictionary<string, IModMetadata>();
/// <summary>Whether all mod assemblies have been loaded.</summary>
public bool AreAllModsLoaded { get; set; }
/// <summary>Whether all mods have been initialised and their <see cref="IMod.Entry"/> method called.</summary>
public bool AreAllModsInitialised { get; set; }

View File

@ -713,15 +713,8 @@ namespace StardewModdingAPI.Framework
mod.SetStatus(ModMetadataStatus.Failed, errorPhrase);
}
// load content packs first (so they're available to mods)
foreach (IModMetadata contentPack in mods.Where(p => p.IsContentPack))
{
if (!this.TryLoadMod(contentPack, mods, modAssemblyLoader, proxyFactory, jsonHelper, contentCore, modDatabase, suppressUpdateChecks, out string errorPhrase, out string errorDetails))
LogSkip(contentPack, errorPhrase, errorDetails);
}
// load SMAPI mods
foreach (IModMetadata contentPack in mods.Where(p => !p.IsContentPack))
// load mods
foreach (IModMetadata contentPack in mods)
{
if (!this.TryLoadMod(contentPack, mods, modAssemblyLoader, proxyFactory, jsonHelper, contentCore, modDatabase, suppressUpdateChecks, out string errorPhrase, out string errorDetails))
LogSkip(contentPack, errorPhrase, errorDetails);
@ -730,6 +723,9 @@ namespace StardewModdingAPI.Framework
IModMetadata[] loadedContentPacks = this.ModRegistry.GetAll(assemblyMods: false).ToArray();
IModMetadata[] loadedMods = this.ModRegistry.GetAll(contentPacks: false).ToArray();
// unlock content packs
this.ModRegistry.AreAllModsLoaded = true;
// log loaded mods
this.Monitor.Log($"Loaded {loadedMods.Length} mods" + (loadedMods.Length > 0 ? ":" : "."), LogLevel.Info);
foreach (IModMetadata metadata in loadedMods.OrderBy(p => p.DisplayName))
@ -972,11 +968,17 @@ namespace StardewModdingAPI.Framework
return false;
// get content packs
IContentPack[] contentPacks = this.ModRegistry
.GetAll(assemblyMods: false)
.Where(p => p.IsContentPack && mod.HasID(p.Manifest.ContentPackFor.UniqueID))
.Select(p => p.ContentPack)
.ToArray();
IContentPack[] GetContentPacks()
{
if (!this.ModRegistry.AreAllModsLoaded)
throw new InvalidOperationException("Can't access content packs before SMAPI finishes loading mods.");
return this.ModRegistry
.GetAll(assemblyMods: false)
.Where(p => p.IsContentPack && mod.HasID(p.Manifest.ContentPackFor.UniqueID))
.Select(p => p.ContentPack)
.ToArray();
}
// init mod helpers
IMonitor monitor = this.GetSecondaryMonitor(mod.DisplayName);
@ -998,7 +1000,7 @@ namespace StardewModdingAPI.Framework
return new ContentPack(packDirPath, packManifest, packContentHelper, this.Toolkit.JsonHelper);
}
modHelper = new ModHelper(manifest.UniqueID, mod.DirectoryPath, this.Toolkit.JsonHelper, this.GameInstance.Input, events, contentHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper, contentPacks, CreateTransitionalContentPack, this.DeprecationManager);
modHelper = new ModHelper(manifest.UniqueID, mod.DirectoryPath, this.Toolkit.JsonHelper, this.GameInstance.Input, events, contentHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper, GetContentPacks, CreateTransitionalContentPack, this.DeprecationManager);
}
// init mod