change new fields to hash sets & simplify sorting
This makes the mod IDs case-insensitive (like the 'SuppressUpdateChecks' field), fixes a build error in unit tests, and avoids re-scanning the mod list multiple times.
This commit is contained in:
parent
9fd8c35b46
commit
0629f19698
|
@ -242,12 +242,32 @@ namespace StardewModdingAPI.Framework.ModLoading
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>Apply preliminary overrides to the load order based on the SMAPI configuration.</summary>
|
||||
/// <param name="mods">The mods to process.</param>
|
||||
/// <param name="modIdsToLoadEarly">The mod IDs SMAPI should load before any other mods (except those needed to load them).</param>
|
||||
/// <param name="modIdsToLoadLate">The mod IDs SMAPI should load after any other mods.</param>
|
||||
public IModMetadata[] ApplyLoadOrderOverrides(IModMetadata[] mods, HashSet<string> modIdsToLoadEarly, HashSet<string> modIdsToLoadLate)
|
||||
{
|
||||
if (!modIdsToLoadEarly.Any() && !modIdsToLoadLate.Any())
|
||||
return mods;
|
||||
|
||||
return mods
|
||||
.OrderBy(mod =>
|
||||
{
|
||||
string id = mod.Manifest.UniqueID;
|
||||
if (modIdsToLoadEarly.Contains(id))
|
||||
return -1;
|
||||
if (modIdsToLoadLate.Contains(id))
|
||||
return 1;
|
||||
return 0;
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>Sort the given mods by the order they should be loaded.</summary>
|
||||
/// <param name="mods">The mods to process.</param>
|
||||
/// <param name="modDatabase">Handles access to SMAPI's internal mod metadata list.</param>
|
||||
/// <param name="modIdsToLoadEarly">The mod IDs SMAPI should try to load early, before any other mods not included in this list.</param>
|
||||
/// <param name="modIdsToLoadLate">The mod IDs SMAPI should try to load late, after all other mods not included in this list.</param>
|
||||
public IEnumerable<IModMetadata> ProcessDependencies(IEnumerable<IModMetadata> mods, IReadOnlyList<string> modIdsToLoadEarly, IReadOnlyList<string> modIdsToLoadLate, ModDatabase modDatabase)
|
||||
public IEnumerable<IModMetadata> ProcessDependencies(IReadOnlyList<IModMetadata> mods, ModDatabase modDatabase)
|
||||
{
|
||||
// initialize metadata
|
||||
mods = mods.ToArray();
|
||||
|
@ -262,28 +282,8 @@ namespace StardewModdingAPI.Framework.ModLoading
|
|||
}
|
||||
|
||||
// sort mods
|
||||
IModMetadata[] allMods = mods.ToArray();
|
||||
IModMetadata[] modsToLoadEarly = modIdsToLoadEarly
|
||||
.Where(modId => !modIdsToLoadLate.Contains(modId))
|
||||
.Select(modId => allMods.FirstOrDefault(m => m.Manifest.UniqueID == modId))
|
||||
.Where(m => m != null)
|
||||
.Select(m => m!)
|
||||
.ToArray();
|
||||
IModMetadata[] modsToLoadLate = modIdsToLoadLate
|
||||
.Where(modId => !modIdsToLoadEarly.Contains(modId))
|
||||
.Select(modId => allMods.FirstOrDefault(m => m.Manifest.UniqueID == modId))
|
||||
.Where(m => m != null)
|
||||
.Select(m => m!)
|
||||
.ToArray();
|
||||
IModMetadata[] modsToLoadAsUsual = allMods.Where(m => !modsToLoadEarly.Contains(m) && !modsToLoadLate.Contains(m)).ToArray();
|
||||
|
||||
List<IModMetadata> orderSortedMods = new();
|
||||
orderSortedMods.AddRange(modsToLoadEarly);
|
||||
orderSortedMods.AddRange(modsToLoadAsUsual);
|
||||
orderSortedMods.AddRange(modsToLoadLate);
|
||||
|
||||
foreach (IModMetadata mod in orderSortedMods)
|
||||
this.ProcessDependencies(orderSortedMods, modDatabase, mod, states, sortedMods, new List<IModMetadata>());
|
||||
foreach (IModMetadata mod in mods)
|
||||
this.ProcessDependencies(mods, modDatabase, mod, states, sortedMods, new List<IModMetadata>());
|
||||
|
||||
return sortedMods.Reverse();
|
||||
}
|
||||
|
|
|
@ -82,11 +82,11 @@ namespace StardewModdingAPI.Framework.Models
|
|||
/// <summary>The mod IDs SMAPI should ignore when performing update checks or validating update keys.</summary>
|
||||
public HashSet<string> SuppressUpdateChecks { get; set; }
|
||||
|
||||
/// <summary>The mod IDs SMAPI should try to load early, before any other mods not included in this list.</summary>
|
||||
public List<string> ModsToLoadEarly { get; set; }
|
||||
/// <summary>The mod IDs SMAPI should load before any other mods (except those needed to load them).</summary>
|
||||
public HashSet<string> ModsToLoadEarly { get; set; }
|
||||
|
||||
/// <summary>The mod IDs SMAPI should try to load late, after all other mods not included in this list.</summary>
|
||||
public List<string> ModsToLoadLate { get; set; }
|
||||
/// <summary>The mod IDs SMAPI should load after any other mods.</summary>
|
||||
public HashSet<string> ModsToLoadLate { get; set; }
|
||||
|
||||
|
||||
/********
|
||||
|
@ -106,8 +106,8 @@ namespace StardewModdingAPI.Framework.Models
|
|||
/// <param name="consoleColors">The colors to use for text written to the SMAPI console.</param>
|
||||
/// <param name="suppressHarmonyDebugMode">Whether to prevent mods from enabling Harmony's debug mode, which impacts performance and creates a file on your desktop. Debug mode should never be enabled by a released mod.</param>
|
||||
/// <param name="suppressUpdateChecks">The mod IDs SMAPI should ignore when performing update checks or validating update keys.</param>
|
||||
/// <param name="modsToLoadEarly">The mod IDs SMAPI should try to load early, before any other mods not included in this list.</param>
|
||||
/// <param name="modsToLoadLate">The mod IDs SMAPI should try to load late, after all other mods not included in this list.</param>
|
||||
/// <param name="modsToLoadEarly">The mod IDs SMAPI should load before any other mods (except those needed to load them).</param>
|
||||
/// <param name="modsToLoadLate">The mod IDs SMAPI should load after any other mods.</param>
|
||||
public SConfig(bool developerMode, bool? checkForUpdates, bool? paranoidWarnings, bool? useBetaChannel, string gitHubProjectName, string webApiBaseUrl, string[]? verboseLogging, bool? rewriteMods, bool? useCaseInsensitivePaths, bool? logNetworkTraffic, ColorSchemeConfig consoleColors, bool? suppressHarmonyDebugMode, string[]? suppressUpdateChecks, string[]? modsToLoadEarly, string[]? modsToLoadLate)
|
||||
{
|
||||
this.DeveloperMode = developerMode;
|
||||
|
@ -123,8 +123,8 @@ namespace StardewModdingAPI.Framework.Models
|
|||
this.ConsoleColors = consoleColors;
|
||||
this.SuppressHarmonyDebugMode = suppressHarmonyDebugMode ?? (bool)SConfig.DefaultValues[nameof(this.SuppressHarmonyDebugMode)];
|
||||
this.SuppressUpdateChecks = new HashSet<string>(suppressUpdateChecks ?? Array.Empty<string>(), StringComparer.OrdinalIgnoreCase);
|
||||
this.ModsToLoadEarly = new List<string>(modsToLoadEarly ?? Array.Empty<string>());
|
||||
this.ModsToLoadLate = new List<string>(modsToLoadLate ?? Array.Empty<string>());
|
||||
this.ModsToLoadEarly = new HashSet<string>(modsToLoadEarly ?? Array.Empty<string>(), StringComparer.OrdinalIgnoreCase);
|
||||
this.ModsToLoadLate = new HashSet<string>(modsToLoadLate ?? Array.Empty<string>(), StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>Override the value of <see cref="DeveloperMode"/>.</summary>
|
||||
|
|
|
@ -424,19 +424,27 @@ namespace StardewModdingAPI.Framework
|
|||
mods = mods.Where(p => !p.IsIgnored).ToArray();
|
||||
|
||||
// warn about mods that should load early or late which are not found at all, or both
|
||||
foreach (string modId in this.Settings.ModsToLoadEarly)
|
||||
if (!mods.Any(m => m.Manifest.UniqueID == modId))
|
||||
this.Monitor.Log($" SMAPI configuration specifies a mod {modId} that should load early, but it could not be found or was skipped.", LogLevel.Warn);
|
||||
foreach (string modId in this.Settings.ModsToLoadLate)
|
||||
if (!mods.Any(m => m.Manifest.UniqueID == modId))
|
||||
this.Monitor.Log($" SMAPI configuration specifies a mod {modId} that should load late, but it could not be found or was skipped.", LogLevel.Warn);
|
||||
foreach (string modId in this.Settings.ModsToLoadEarly)
|
||||
if (this.Settings.ModsToLoadLate.Contains(modId))
|
||||
this.Monitor.Log($" SMAPI configuration specifies a mod {modId} that should load both early and late - this will be ignored.", LogLevel.Warn);
|
||||
{
|
||||
HashSet<string> installedIds = new HashSet<string>(mods.Select(p => p.Manifest.UniqueID), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (string modId in this.Settings.ModsToLoadEarly)
|
||||
{
|
||||
if (!installedIds.Contains(modId))
|
||||
this.Monitor.Log($" SMAPI configuration specifies a mod {modId} that should load early, but it could not be found or was skipped.", LogLevel.Warn);
|
||||
}
|
||||
foreach (string modId in this.Settings.ModsToLoadLate)
|
||||
{
|
||||
if (this.Settings.ModsToLoadEarly.Contains(modId))
|
||||
this.Monitor.Log($" SMAPI configuration specifies a mod {modId} that should load both early and late - this will be ignored.", LogLevel.Warn);
|
||||
else if (!installedIds.Contains(modId))
|
||||
this.Monitor.Log($" SMAPI configuration specifies a mod {modId} that should load late, but it could not be found or was skipped.", LogLevel.Warn);
|
||||
}
|
||||
}
|
||||
|
||||
// load mods
|
||||
resolver.ValidateManifests(mods, Constants.ApiVersion, toolkit.GetUpdateUrl, getFileLookup: this.GetFileLookup);
|
||||
mods = resolver.ProcessDependencies(mods, this.Settings.ModsToLoadEarly, this.Settings.ModsToLoadLate, modDatabase).ToArray();
|
||||
mods = resolver.ApplyLoadOrderOverrides(mods, this.Settings.ModsToLoadEarly, this.Settings.ModsToLoadLate);
|
||||
mods = resolver.ProcessDependencies(mods, modDatabase).ToArray();
|
||||
this.LoadMods(mods, this.Toolkit.JsonHelper, this.ContentCore, modDatabase);
|
||||
|
||||
// check for software likely to cause issues
|
||||
|
|
Loading…
Reference in New Issue