diff options
| author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2018-03-13 20:25:06 -0400 |
|---|---|---|
| committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2018-03-13 20:25:06 -0400 |
| commit | afb3c49bbaab07f3148f70d54f5140cdd83f8c20 (patch) | |
| tree | dd60902c878c38617f97644b912afb38c568755e /src/SMAPI/Framework | |
| parent | 833d98f49136325edfc4463097710cf2391dd5b2 (diff) | |
| parent | 76445dc3589265ba259070300120e96a17957e50 (diff) | |
| download | SMAPI-afb3c49bbaab07f3148f70d54f5140cdd83f8c20.tar.gz SMAPI-afb3c49bbaab07f3148f70d54f5140cdd83f8c20.tar.bz2 SMAPI-afb3c49bbaab07f3148f70d54f5140cdd83f8c20.zip | |
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI/Framework')
21 files changed, 1277 insertions, 135 deletions
diff --git a/src/SMAPI/Framework/SContentManager.cs b/src/SMAPI/Framework/ContentCore.cs index fa51bd53..85b8db8f 100644 --- a/src/SMAPI/Framework/SContentManager.cs +++ b/src/SMAPI/Framework/ContentCore.cs @@ -19,9 +19,9 @@ using StardewValley; namespace StardewModdingAPI.Framework { - /// <summary>A thread-safe content manager which intercepts assets being loaded to let SMAPI mods inject or edit them.</summary> + /// <summary>A thread-safe content handler which loads assets with support for mod injection and editing.</summary> /// <remarks> - /// This is the centralised content manager which manages all game assets. The game and mods don't use this class + /// This is the centralised content logic which manages all game assets. The game and mods don't use this class /// directly; instead they use one of several <see cref="ContentManagerShim"/> instances, which proxy requests to /// this class. That ensures that when the game disposes one content manager, the others can continue unaffected. /// That notably requires this class to be thread-safe, since the content managers can be disposed asynchronously. @@ -30,22 +30,25 @@ namespace StardewModdingAPI.Framework /// For English and non-translatable assets, these have the same value. The underlying cache only knows about asset /// keys, and the game and mods only know about asset names. The content manager handles resolving them. /// </remarks> - internal class SContentManager : LocalizedContentManager + internal class ContentCore : IDisposable { /********* ** Properties *********/ + /// <summary>The underlying content manager.</summary> + private readonly LocalizedContentManager Content; + /// <summary>Encapsulates monitoring and logging.</summary> private readonly IMonitor Monitor; /// <summary>The underlying asset cache.</summary> private readonly ContentCache Cache; - /// <summary>The private <see cref="LocalizedContentManager"/> method which generates the locale portion of an asset name.</summary> - private readonly IReflectedMethod GetKeyLocale; + /// <summary>The locale codes used in asset keys indexed by enum value.</summary> + private readonly IDictionary<LocalizedContentManager.LanguageCode, string> Locales; - /// <summary>The language codes used in asset keys.</summary> - private readonly IDictionary<string, LanguageCode> KeyLocales; + /// <summary>The language enum values indexed by locale code.</summary> + private readonly IDictionary<string, LocalizedContentManager.LanguageCode> LanguageCodes; /// <summary>Provides metadata for core game assets.</summary> private readonly CoreAssets CoreAssets; @@ -66,15 +69,17 @@ namespace StardewModdingAPI.Framework /********* ** Accessors *********/ + /// <summary>The current language as a constant.</summary> + public LocalizedContentManager.LanguageCode Language => this.Content.GetCurrentLanguage(); + /// <summary>Interceptors which provide the initial versions of matching assets.</summary> - internal IDictionary<IModMetadata, IList<IAssetLoader>> Loaders { get; } = new Dictionary<IModMetadata, IList<IAssetLoader>>(); + public IDictionary<IModMetadata, IList<IAssetLoader>> Loaders { get; } = new Dictionary<IModMetadata, IList<IAssetLoader>>(); /// <summary>Interceptors which edit matching assets after they're loaded.</summary> - internal IDictionary<IModMetadata, IList<IAssetEditor>> Editors { get; } = new Dictionary<IModMetadata, IList<IAssetEditor>>(); + public IDictionary<IModMetadata, IList<IAssetEditor>> Editors { get; } = new Dictionary<IModMetadata, IList<IAssetEditor>>(); /// <summary>The absolute path to the <see cref="ContentManager.RootDirectory"/>.</summary> - internal string FullRootDirectory => Path.Combine(Constants.ExecutionPath, this.RootDirectory); - + public string FullRootDirectory => Path.Combine(Constants.ExecutionPath, this.Content.RootDirectory); /********* ** Public methods @@ -89,18 +94,26 @@ namespace StardewModdingAPI.Framework /// <param name="languageCodeOverride">The current language code for which to localise content.</param> /// <param name="monitor">Encapsulates monitoring and logging.</param> /// <param name="reflection">Simplifies access to private code.</param> - public SContentManager(IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, string languageCodeOverride, IMonitor monitor, Reflector reflection) - : base(serviceProvider, rootDirectory, currentCulture, languageCodeOverride) + public ContentCore(IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, string languageCodeOverride, IMonitor monitor, Reflector reflection) { // init this.Monitor = monitor ?? throw new ArgumentNullException(nameof(monitor)); - this.Cache = new ContentCache(this, reflection); - this.GetKeyLocale = reflection.GetMethod(this, "languageCode"); + this.Content = new LocalizedContentManager(serviceProvider, rootDirectory, currentCulture, languageCodeOverride); + this.Cache = new ContentCache(this.Content, reflection); this.ModContentPrefix = this.GetAssetNameFromFilePath(Constants.ModPath); // get asset data - this.CoreAssets = new CoreAssets(this.NormaliseAssetName); - this.KeyLocales = this.GetKeyLocales(reflection); + this.CoreAssets = new CoreAssets(this.NormaliseAssetName, reflection); + this.Locales = this.GetKeyLocales(reflection); + this.LanguageCodes = this.Locales.ToDictionary(p => p.Value, p => p.Key, StringComparer.InvariantCultureIgnoreCase); + } + + /// <summary>Get a new content manager which defers loading to the content core.</summary> + /// <param name="name">The content manager's name for logs (if any).</param> + /// <param name="rootDirectory">The root directory to search for content (or <c>null</c>. for the default)</param> + public ContentManagerShim CreateContentManager(string name, string rootDirectory = null) + { + return new ContentManagerShim(this, name, this.Content.ServiceProvider, rootDirectory ?? this.Content.RootDirectory, this.Content.CurrentCulture, this.Content.LanguageCodeOverride); } /**** @@ -153,7 +166,14 @@ namespace StardewModdingAPI.Framework /// <summary>Get the current content locale.</summary> public string GetLocale() { - return this.GetKeyLocale.Invoke<string>(); + return this.GetLocale(this.Content.GetCurrentLanguage()); + } + + /// <summary>The locale for a language.</summary> + /// <param name="language">The language.</param> + public string GetLocale(LocalizedContentManager.LanguageCode language) + { + return this.Locales[language]; } /// <summary>Get whether the content manager has already loaded and cached the given asset.</summary> @@ -177,18 +197,15 @@ namespace StardewModdingAPI.Framework /// <summary>Load an asset through the content pipeline. When loading a <c>.png</c> file, this must be called outside the game's draw loop.</summary> /// <typeparam name="T">The expected asset type.</typeparam> /// <param name="assetName">The asset path relative to the content directory.</param> - public override T Load<T>(string assetName) - { - return this.LoadFor<T>(assetName, this); - } - - /// <summary>Load an asset through the content pipeline. When loading a <c>.png</c> file, this must be called outside the game's draw loop.</summary> - /// <typeparam name="T">The expected asset type.</typeparam> - /// <param name="assetName">The asset path relative to the content directory.</param> /// <param name="instance">The content manager instance for which to load the asset.</param> + /// <param name="language">The language code for which to load content.</param> /// <exception cref="ArgumentException">The <paramref name="assetName"/> is empty or contains invalid characters.</exception> /// <exception cref="ContentLoadException">The content asset couldn't be loaded (e.g. because it doesn't exist).</exception> - public T LoadFor<T>(string assetName, ContentManager instance) + public T Load<T>(string assetName, ContentManager instance +#if STARDEW_VALLEY_1_3 + , LocalizedContentManager.LanguageCode language +#endif + ) { // normalise asset key this.AssertValidAssetKeyFormat(assetName); @@ -196,7 +213,11 @@ namespace StardewModdingAPI.Framework // load game content if (!assetName.StartsWith(this.ModContentPrefix)) +#if STARDEW_VALLEY_1_3 + return this.LoadImpl<T>(assetName, instance, language); +#else return this.LoadImpl<T>(assetName, instance); +#endif // load mod content SContentLoadException GetContentError(string reasonPhrase) => new SContentLoadException($"Failed loading content asset '{assetName}': {reasonPhrase}"); @@ -206,7 +227,11 @@ namespace StardewModdingAPI.Framework { // try cache if (this.IsLoaded(assetName)) +#if STARDEW_VALLEY_1_3 + return this.LoadImpl<T>(assetName, instance, language); +#else return this.LoadImpl<T>(assetName, instance); +#endif // get file FileInfo file = this.GetModFile(assetName); @@ -218,7 +243,11 @@ namespace StardewModdingAPI.Framework { // XNB file case ".xnb": +#if STARDEW_VALLEY_1_3 + return this.LoadImpl<T>(assetName, instance, language); +#else return this.LoadImpl<T>(assetName, instance); +#endif // unpacked map case ".tbin": @@ -339,7 +368,7 @@ namespace StardewModdingAPI.Framework int reloaded = 0; foreach (string key in removeAssetNames) { - if (this.CoreAssets.ReloadForKey(this, key)) + if (this.CoreAssets.ReloadForKey(Game1.content, key)) // use an intercepted content manager reloaded++; } @@ -379,11 +408,10 @@ namespace StardewModdingAPI.Framework ** Disposal ****/ /// <summary>Dispose held resources.</summary> - /// <param name="disposing">Whether the content manager is disposing (rather than finalising).</param> - protected override void Dispose(bool disposing) + public void Dispose() { this.Monitor.Log("Disposing SMAPI's main content manager. It will no longer be usable after this point.", LogLevel.Trace); - base.Dispose(disposing); + this.Content.Dispose(); } /**** @@ -398,29 +426,48 @@ namespace StardewModdingAPI.Framework /// <summary>Get the locale codes (like <c>ja-JP</c>) used in asset keys.</summary> /// <param name="reflection">Simplifies access to private game code.</param> - private IDictionary<string, LanguageCode> GetKeyLocales(Reflector reflection) + private IDictionary<LocalizedContentManager.LanguageCode, string> GetKeyLocales(Reflector reflection) { - // get the private code field directly to avoid changed-code logic - IReflectedField<LanguageCode> codeField = reflection.GetField<LanguageCode>(typeof(LocalizedContentManager), "_currentLangCode"); - - // remember previous settings - LanguageCode previousCode = codeField.GetValue(); - string previousOverride = this.LanguageCodeOverride; +#if !STARDEW_VALLEY_1_3 + IReflectedField<LocalizedContentManager.LanguageCode> codeField = reflection.GetField<LocalizedContentManager.LanguageCode>(typeof(LocalizedContentManager), "_currentLangCode"); + LocalizedContentManager.LanguageCode previousCode = codeField.GetValue(); +#endif + string previousOverride = this.Content.LanguageCodeOverride; - // create locale => code map - IDictionary<string, LanguageCode> map = new Dictionary<string, LanguageCode>(StringComparer.InvariantCultureIgnoreCase); - this.LanguageCodeOverride = null; - foreach (LanguageCode code in Enum.GetValues(typeof(LanguageCode))) + try { - codeField.SetValue(code); - map[this.GetKeyLocale.Invoke<string>()] = code; - } + // temporarily disable language override + this.Content.LanguageCodeOverride = null; + + // create locale => code map + IReflectedMethod languageCodeString = reflection +#if STARDEW_VALLEY_1_3 + .GetMethod(this.Content, "languageCodeString"); +#else + .GetMethod(this.Content, "languageCode"); +#endif + IDictionary<LocalizedContentManager.LanguageCode, string> map = new Dictionary<LocalizedContentManager.LanguageCode, string>(); + foreach (LocalizedContentManager.LanguageCode code in Enum.GetValues(typeof(LocalizedContentManager.LanguageCode))) + { +#if STARDEW_VALLEY_1_3 + map[code] = languageCodeString.Invoke<string>(code); +#else + codeField.SetValue(code); + map[code] = languageCodeString.Invoke<string>(); +#endif + } - // restore previous settings - codeField.SetValue(previousCode); - this.LanguageCodeOverride = previousOverride; + return map; + } + finally + { + // restore previous settings + this.Content.LanguageCodeOverride = previousOverride; +#if !STARDEW_VALLEY_1_3 + codeField.SetValue(previousCode); +#endif - return map; + } } /// <summary>Get the asset name from a cache key.</summary> @@ -444,7 +491,7 @@ namespace StardewModdingAPI.Framework if (lastSepIndex >= 0) { string suffix = cacheKey.Substring(lastSepIndex + 1, cacheKey.Length - lastSepIndex - 1); - if (this.KeyLocales.ContainsKey(suffix)) + if (this.LanguageCodes.ContainsKey(suffix)) { assetName = cacheKey.Substring(0, lastSepIndex); localeCode = cacheKey.Substring(lastSepIndex + 1, cacheKey.Length - lastSepIndex - 1); @@ -466,7 +513,7 @@ namespace StardewModdingAPI.Framework private bool IsNormalisedKeyLoaded(string normalisedAssetName) { return this.Cache.ContainsKey(normalisedAssetName) - || this.Cache.ContainsKey($"{normalisedAssetName}.{this.GetKeyLocale.Invoke<string>()}"); // translated asset + || this.Cache.ContainsKey($"{normalisedAssetName}.{this.Locales[this.Content.GetCurrentLanguage()]}"); // translated asset } /// <summary>Track that a content manager loaded an asset.</summary> @@ -486,7 +533,12 @@ namespace StardewModdingAPI.Framework /// <typeparam name="T">The type of asset to load.</typeparam> /// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param> /// <param name="instance">The content manager instance for which to load the asset.</param> - private T LoadImpl<T>(string assetName, ContentManager instance) + /// <param name="language">The language code for which to load content.</param> + private T LoadImpl<T>(string assetName, ContentManager instance +#if STARDEW_VALLEY_1_3 + , LocalizedContentManager.LanguageCode language +#endif + ) { return this.WithWriteLock(() => { @@ -494,7 +546,13 @@ namespace StardewModdingAPI.Framework if (this.IsNormalisedKeyLoaded(assetName)) { this.TrackAssetLoader(assetName, instance); - return base.Load<T>(assetName); + return this.Content + +#if STARDEW_VALLEY_1_3 + .Load<T>(assetName, language); +#else + .Load<T>(assetName); +#endif } // load asset @@ -503,14 +561,30 @@ namespace StardewModdingAPI.Framework { this.Monitor.Log($"Broke loop while loading asset '{assetName}'.", LogLevel.Warn); this.Monitor.Log($"Bypassing mod loaders for this asset. Stack trace:\n{Environment.StackTrace}", LogLevel.Trace); - data = base.Load<T>(assetName); + data = this.Content +#if STARDEW_VALLEY_1_3 + .Load<T>(assetName, language); +#else + .Load<T>(assetName); +#endif } else { data = this.AssetsBeingLoaded.Track(assetName, () => { - IAssetInfo info = new AssetInfo(this.GetLocale(), assetName, typeof(T), this.NormaliseAssetName); - IAssetData asset = this.ApplyLoader<T>(info) ?? new AssetDataForObject(info, base.Load<T>(assetName), this.NormaliseAssetName); + string locale = +#if STARDEW_VALLEY_1_3 + this.GetLocale(language); +#else + this.GetLocale(); +#endif + IAssetInfo info = new AssetInfo(locale, assetName, typeof(T), this.NormaliseAssetName); + IAssetData asset = this.ApplyLoader<T>(info) +#if STARDEW_VALLEY_1_3 + ?? new AssetDataForObject(info, this.Content.Load<T>(assetName, language), this.NormaliseAssetName); +#else + ?? new AssetDataForObject(info, this.Content.Load<T>(assetName), this.NormaliseAssetName); +#endif asset = this.ApplyEditors<T>(info, asset); return (T)asset.Data; }); diff --git a/src/SMAPI/Framework/ContentManagerShim.cs b/src/SMAPI/Framework/ContentManagerShim.cs index d46f23a3..8f88fc2d 100644 --- a/src/SMAPI/Framework/ContentManagerShim.cs +++ b/src/SMAPI/Framework/ContentManagerShim.cs @@ -1,15 +1,17 @@ +using System; +using System.Globalization; using StardewValley; namespace StardewModdingAPI.Framework { - /// <summary>A minimal content manager which defers to SMAPI's main content manager.</summary> + /// <summary>A minimal content manager which defers to SMAPI's core content logic.</summary> internal class ContentManagerShim : LocalizedContentManager { /********* ** Properties *********/ - /// <summary>SMAPI's underlying content manager.</summary> - private readonly SContentManager ContentManager; + /// <summary>SMAPI's core content logic.</summary> + private readonly ContentCore ContentCore; /********* @@ -23,12 +25,16 @@ namespace StardewModdingAPI.Framework ** Public methods *********/ /// <summary>Construct an instance.</summary> - /// <param name="contentManager">SMAPI's underlying content manager.</param> + /// <param name="contentCore">SMAPI's core content logic.</param> /// <param name="name">The content manager's name for logs (if any).</param> - public ContentManagerShim(SContentManager contentManager, string name) - : base(contentManager.ServiceProvider, contentManager.RootDirectory, contentManager.CurrentCulture, contentManager.LanguageCodeOverride) + /// <param name="serviceProvider">The service provider to use to locate services.</param> + /// <param name="rootDirectory">The root directory to search for content.</param> + /// <param name="currentCulture">The current culture for which to localise content.</param> + /// <param name="languageCodeOverride">The current language code for which to localise content.</param> + public ContentManagerShim(ContentCore contentCore, string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, string languageCodeOverride) + : base(serviceProvider, rootDirectory, currentCulture, languageCodeOverride) { - this.ContentManager = contentManager; + this.ContentCore = contentCore; this.Name = name; } @@ -37,14 +43,58 @@ namespace StardewModdingAPI.Framework /// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param> public override T Load<T>(string assetName) { - return this.ContentManager.LoadFor<T>(assetName, this); +#if STARDEW_VALLEY_1_3 + return this.Load<T>(assetName, LocalizedContentManager.CurrentLanguageCode); +#else + return this.ContentCore.Load<T>(assetName, this); +#endif } +#if STARDEW_VALLEY_1_3 + /// <summary>Load an asset that has been processed by the content pipeline.</summary> + /// <typeparam name="T">The type of asset to load.</typeparam> + /// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param> + /// <param name="language">The language code for which to load content.</param> + public override T Load<T>(string assetName, LanguageCode language) + { + return this.ContentCore.Load<T>(assetName, this, language); + } + + /// <summary>Load the base asset without localisation.</summary> + /// <typeparam name="T">The type of asset to load.</typeparam> + /// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param> + public override T LoadBase<T>(string assetName) + { + return this.Load<T>(assetName, LanguageCode.en); + } +#endif + + /// <summary>Inject an asset into the cache.</summary> + /// <typeparam name="T">The type of asset to inject.</typeparam> + /// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param> + /// <param name="value">The asset value.</param> + public void Inject<T>(string assetName, T value) + { + this.ContentCore.Inject<T>(assetName, value, this); + } + +#if STARDEW_VALLEY_1_3 + /// <summary>Create a new content manager for temporary use.</summary> + public override LocalizedContentManager CreateTemporary() + { + return this.ContentCore.CreateContentManager("(temporary)"); + } +#endif + + + /********* + ** Protected methods + *********/ /// <summary>Dispose held resources.</summary> /// <param name="disposing">Whether the content manager is disposing (rather than finalising).</param> protected override void Dispose(bool disposing) { - this.ContentManager.DisposeFor(this); + this.ContentCore.DisposeFor(this); } } } diff --git a/src/SMAPI/Framework/GameVersion.cs b/src/SMAPI/Framework/GameVersion.cs index 1884afe9..e5022212 100644 --- a/src/SMAPI/Framework/GameVersion.cs +++ b/src/SMAPI/Framework/GameVersion.cs @@ -49,21 +49,31 @@ namespace StardewModdingAPI.Framework /// <param name="gameVersion">The game version string.</param> private static string GetSemanticVersionString(string gameVersion) { +#if STARDEW_VALLEY_1_3 + if(gameVersion.StartsWith("1.3.0.")) + return new SemanticVersion(1, 3, 0, "alpha." + gameVersion.Substring("1.3.0.".Length)).ToString(); +#endif + return GameVersion.VersionMap.TryGetValue(gameVersion, out string semanticVersion) ? semanticVersion : gameVersion; } - /// <summary>Convert a game version string to a semantic version string.</summary> - /// <param name="gameVersion">The game version string.</param> - private static string GetGameVersionString(string gameVersion) + /// <summary>Convert a semantic version string to the equivalent game version string.</summary> + /// <param name="semanticVersion">The semantic version string.</param> + private static string GetGameVersionString(string semanticVersion) { + #if STARDEW_VALLEY_1_3 + if(semanticVersion.StartsWith("1.3-alpha.")) + return "1.3.0." + semanticVersion.Substring("1.3-alpha.".Length); + #endif + foreach (var mapping in GameVersion.VersionMap) { - if (mapping.Value.Equals(gameVersion, StringComparison.InvariantCultureIgnoreCase)) + if (mapping.Value.Equals(semanticVersion, StringComparison.InvariantCultureIgnoreCase)) return mapping.Key; } - return gameVersion; + return semanticVersion; } } } diff --git a/src/SMAPI/Framework/ModData/ModDataField.cs b/src/SMAPI/Framework/ModData/ModDataField.cs index fa8dd6d0..df906103 100644 --- a/src/SMAPI/Framework/ModData/ModDataField.cs +++ b/src/SMAPI/Framework/ModData/ModDataField.cs @@ -66,7 +66,7 @@ namespace StardewModdingAPI.Framework.ModData { // update key case ModDataFieldKey.UpdateKey: - return manifest.UpdateKeys != null && manifest.UpdateKeys.Any(); + return manifest.UpdateKeys != null && manifest.UpdateKeys.Any(p => !string.IsNullOrWhiteSpace(p)); // non-manifest fields case ModDataFieldKey.AlternativeUrl: diff --git a/src/SMAPI/Framework/ModData/ModDataRecord.cs b/src/SMAPI/Framework/ModData/ModDataRecord.cs index 79a954f7..56275f53 100644 --- a/src/SMAPI/Framework/ModData/ModDataRecord.cs +++ b/src/SMAPI/Framework/ModData/ModDataRecord.cs @@ -106,10 +106,10 @@ namespace StardewModdingAPI.Framework.ModData /// <summary>Get a semantic local version for update checks.</summary> /// <param name="version">The remote version to normalise.</param> - public string GetLocalVersionForUpdateChecks(string version) + public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) { - return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version, out string newVersion) - ? newVersion + return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version.ToString(), out string newVersion) + ? new SemanticVersion(newVersion) : version; } @@ -117,6 +117,11 @@ namespace StardewModdingAPI.Framework.ModData /// <param name="version">The remote version to normalise.</param> public string GetRemoteVersionForUpdateChecks(string version) { + // normalise version if possible + if (SemanticVersion.TryParse(version, out ISemanticVersion parsed)) + version = parsed.ToString(); + + // fetch remote version return this.MapRemoteVersions != null && this.MapRemoteVersions.TryGetValue(version, out string newVersion) ? newVersion : version; diff --git a/src/SMAPI/Framework/ModData/ModDatabase.cs b/src/SMAPI/Framework/ModData/ModDatabase.cs index 332c5c48..3fd68440 100644 --- a/src/SMAPI/Framework/ModData/ModDatabase.cs +++ b/src/SMAPI/Framework/ModData/ModDatabase.cs @@ -157,7 +157,7 @@ namespace StardewModdingAPI.Framework.ModData && ( snapshot.Author == null || snapshot.Author.Equals(manifest.Author, StringComparison.InvariantCultureIgnoreCase) - || (manifest.ExtraFields.ContainsKey("Authour") && snapshot.Author.Equals(manifest.ExtraFields["Authour"].ToString(), StringComparison.InvariantCultureIgnoreCase)) + || (manifest.ExtraFields != null && manifest.ExtraFields.ContainsKey("Authour") && snapshot.Author.Equals(manifest.ExtraFields["Authour"].ToString(), StringComparison.InvariantCultureIgnoreCase)) ) && (snapshot.Name == null || snapshot.Name.Equals(manifest.Name, StringComparison.InvariantCultureIgnoreCase)); diff --git a/src/SMAPI/Framework/ModData/ParsedModDataRecord.cs b/src/SMAPI/Framework/ModData/ParsedModDataRecord.cs index 7f49790d..deb12bdc 100644 --- a/src/SMAPI/Framework/ModData/ParsedModDataRecord.cs +++ b/src/SMAPI/Framework/ModData/ParsedModDataRecord.cs @@ -33,7 +33,7 @@ namespace StardewModdingAPI.Framework.ModData *********/ /// <summary>Get a semantic local version for update checks.</summary> /// <param name="version">The remote version to normalise.</param> - public string GetLocalVersionForUpdateChecks(string version) + public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) { return this.DataRecord.GetLocalVersionForUpdateChecks(version); } diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs index 7d8bec1e..c7d4c39e 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs @@ -22,8 +22,11 @@ namespace StardewModdingAPI.Framework.ModHelpers /********* ** Properties *********/ - /// <summary>SMAPI's underlying content manager.</summary> - private readonly SContentManager ContentManager; + /// <summary>SMAPI's core content logic.</summary> + private readonly ContentCore ContentCore; + + /// <summary>The content manager for this mod.</summary> + private readonly ContentManagerShim ContentManager; /// <summary>The absolute path to the mod folder.</summary> private readonly string ModFolderPath; @@ -39,10 +42,10 @@ namespace StardewModdingAPI.Framework.ModHelpers ** Accessors *********/ /// <summary>The game's current locale code (like <c>pt-BR</c>).</summary> - public string CurrentLocale => this.ContentManager.GetLocale(); + public string CurrentLocale => this.ContentCore.GetLocale(); /// <summary>The game's current locale as an enum value.</summary> - public LocalizedContentManager.LanguageCode CurrentLocaleConstant => this.ContentManager.GetCurrentLanguage(); + public LocalizedContentManager.LanguageCode CurrentLocaleConstant => this.ContentCore.Language; /// <summary>The observable implementation of <see cref="AssetEditors"/>.</summary> internal ObservableCollection<IAssetEditor> ObservableAssetEditors { get; } = new ObservableCollection<IAssetEditor>(); @@ -61,14 +64,16 @@ namespace StardewModdingAPI.Framework.ModHelpers ** Public methods *********/ /// <summary>Construct an instance.</summary> - /// <param name="contentManager">SMAPI's underlying |
