From dcfae980bf74386c624b0d059a83e95ec1aedc0b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 16 Nov 2018 21:29:28 -0500 Subject: fix content packs always failing to load if they declare a dependency on a SMAPI mod --- src/SMAPI/Framework/ModHelpers/ModHelper.cs | 9 ++++---- src/SMAPI/Framework/ModRegistry.cs | 3 +++ src/SMAPI/Framework/SCore.cs | 32 +++++++++++++++-------------- 3 files changed, 24 insertions(+), 20 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs index ae0368f0..5e190e55 100644 --- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs @@ -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 *********/ /// The content packs loaded for this mod. - private readonly IContentPack[] ContentPacks; + private readonly Lazy ContentPacks; /// Create a transitional content pack. private readonly Func CreateContentPack; @@ -84,7 +83,7 @@ namespace StardewModdingAPI.Framework.ModHelpers /// Manages deprecation warnings. /// An argument is null or empty. /// The path does not exist on disk. - 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 contentPacks, Func 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 contentPacks, Func 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(contentPacks); this.CreateContentPack = createContentPack; this.DeprecationManager = deprecationManager; this.Events = events; @@ -204,7 +203,7 @@ namespace StardewModdingAPI.Framework.ModHelpers /// Get all content packs loaded for this mod. public IEnumerable GetContentPacks() { - return this.ContentPacks; + return this.ContentPacks.Value; } /**** diff --git a/src/SMAPI/Framework/ModRegistry.cs b/src/SMAPI/Framework/ModRegistry.cs index da68fce3..8ce3172c 100644 --- a/src/SMAPI/Framework/ModRegistry.cs +++ b/src/SMAPI/Framework/ModRegistry.cs @@ -18,6 +18,9 @@ namespace StardewModdingAPI.Framework /// An assembly full name => mod lookup. private readonly IDictionary ModNamesByAssembly = new Dictionary(); + /// Whether all mod assemblies have been loaded. + public bool AreAllModsLoaded { get; set; } + /// Whether all mods have been initialised and their method called. public bool AreAllModsInitialised { get; set; } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 128659c7..4b95917b 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -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 -- cgit