summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2018-03-13 20:25:06 -0400
committerJesse Plamondon-Willard <github@jplamondonw.com>2018-03-13 20:25:06 -0400
commitafb3c49bbaab07f3148f70d54f5140cdd83f8c20 (patch)
treedd60902c878c38617f97644b912afb38c568755e /src/SMAPI
parent833d98f49136325edfc4463097710cf2391dd5b2 (diff)
parent76445dc3589265ba259070300120e96a17957e50 (diff)
downloadSMAPI-afb3c49bbaab07f3148f70d54f5140cdd83f8c20.tar.gz
SMAPI-afb3c49bbaab07f3148f70d54f5140cdd83f8c20.tar.bz2
SMAPI-afb3c49bbaab07f3148f70d54f5140cdd83f8c20.zip
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Constants.cs28
-rw-r--r--src/SMAPI/Events/EventArgsGameLocationsChanged.cs6
-rw-r--r--src/SMAPI/Events/EventArgsInput.cs2
-rw-r--r--src/SMAPI/Events/EventArgsInventoryChanged.cs12
-rw-r--r--src/SMAPI/Events/EventArgsLocationObjectsChanged.cs19
-rw-r--r--src/SMAPI/Framework/ContentCore.cs (renamed from src/SMAPI/Framework/SContentManager.cs)186
-rw-r--r--src/SMAPI/Framework/ContentManagerShim.cs68
-rw-r--r--src/SMAPI/Framework/GameVersion.cs20
-rw-r--r--src/SMAPI/Framework/ModData/ModDataField.cs2
-rw-r--r--src/SMAPI/Framework/ModData/ModDataRecord.cs11
-rw-r--r--src/SMAPI/Framework/ModData/ModDatabase.cs2
-rw-r--r--src/SMAPI/Framework/ModData/ParsedModDataRecord.cs2
-rw-r--r--src/SMAPI/Framework/ModHelpers/ContentHelper.cs43
-rw-r--r--src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs3
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs2
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyLoader.cs32
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs157
-rw-r--r--src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs109
-rw-r--r--src/SMAPI/Framework/ModLoading/ModResolver.cs5
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/FieldToPropertyRewriter.cs18
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/StaticFieldToConstantRewriter.cs63
-rw-r--r--src/SMAPI/Framework/Reflection/ReflectedField.cs5
-rw-r--r--src/SMAPI/Framework/Reflection/ReflectedMethod.cs5
-rw-r--r--src/SMAPI/Framework/Reflection/ReflectedProperty.cs5
-rw-r--r--src/SMAPI/Framework/SGame.cs672
-rw-r--r--src/SMAPI/Framework/WebApiClient.cs2
-rw-r--r--src/SMAPI/IPrivateField.cs2
-rw-r--r--src/SMAPI/IPrivateMethod.cs2
-rw-r--r--src/SMAPI/IPrivateProperty.cs2
-rw-r--r--src/SMAPI/IReflectionHelper.cs2
-rw-r--r--src/SMAPI/Metadata/CoreAssets.cs68
-rw-r--r--src/SMAPI/Metadata/InstructionMetadata.cs74
-rw-r--r--src/SMAPI/Program.cs98
-rw-r--r--src/SMAPI/StardewModdingAPI.config.json375
-rw-r--r--src/SMAPI/StardewModdingAPI.csproj5
35 files changed, 1718 insertions, 389 deletions
diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs
index fe9fdf9b..d91fa5fb 100644
--- a/src/SMAPI/Constants.cs
+++ b/src/SMAPI/Constants.cs
@@ -37,13 +37,28 @@ namespace StardewModdingAPI
** Public
****/
/// <summary>SMAPI's current semantic version.</summary>
- public static ISemanticVersion ApiVersion { get; } = new SemanticVersion("2.5.2");
+ public static ISemanticVersion ApiVersion { get; } =
+#if STARDEW_VALLEY_1_3
+ new SemanticVersion($"2.6-alpha.{DateTime.UtcNow:yyyyMMddHHmm}");
+#else
+ new SemanticVersion($"2.5.3");
+#endif
/// <summary>The minimum supported version of Stardew Valley.</summary>
- public static ISemanticVersion MinimumGameVersion { get; } = new SemanticVersion("1.2.30");
+ public static ISemanticVersion MinimumGameVersion { get; } =
+#if STARDEW_VALLEY_1_3
+ new GameVersion("1.3.0.4");
+#else
+ new SemanticVersion("1.2.33");
+#endif
/// <summary>The maximum supported version of Stardew Valley.</summary>
- public static ISemanticVersion MaximumGameVersion { get; } = null;
+ public static ISemanticVersion MaximumGameVersion { get; } =
+#if STARDEW_VALLEY_1_3
+ null;
+#else
+ new SemanticVersion("1.2.33");
+#endif
/// <summary>The path to the game folder.</summary>
public static string ExecutionPath { get; } = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
@@ -169,7 +184,12 @@ namespace StardewModdingAPI
/// <summary>Get the name of a save directory for the current player.</summary>
private static string GetSaveFolderName()
{
- string prefix = new string(Game1.player.name.Where(char.IsLetterOrDigit).ToArray());
+ string prefix =
+#if STARDEW_VALLEY_1_3
+ new string(Game1.player.name.Value.Where(char.IsLetterOrDigit).ToArray());
+#else
+ new string(Game1.player.name.Where(char.IsLetterOrDigit).ToArray());
+#endif
return $"{prefix}_{Game1.uniqueIDForThisGame}";
}
diff --git a/src/SMAPI/Events/EventArgsGameLocationsChanged.cs b/src/SMAPI/Events/EventArgsGameLocationsChanged.cs
index fb8c821e..78ba38fa 100644
--- a/src/SMAPI/Events/EventArgsGameLocationsChanged.cs
+++ b/src/SMAPI/Events/EventArgsGameLocationsChanged.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using StardewValley;
@@ -11,7 +11,7 @@ namespace StardewModdingAPI.Events
** Accessors
*********/
/// <summary>The current list of game locations.</summary>
- public List<GameLocation> NewLocations { get; }
+ public IList<GameLocation> NewLocations { get; }
/*********
@@ -19,7 +19,7 @@ namespace StardewModdingAPI.Events
*********/
/// <summary>Construct an instance.</summary>
/// <param name="newLocations">The current list of game locations.</param>
- public EventArgsGameLocationsChanged(List<GameLocation> newLocations)
+ public EventArgsGameLocationsChanged(IList<GameLocation> newLocations)
{
this.NewLocations = newLocations;
}
diff --git a/src/SMAPI/Events/EventArgsInput.cs b/src/SMAPI/Events/EventArgsInput.cs
index a5325b76..75b9b8cd 100644
--- a/src/SMAPI/Events/EventArgsInput.cs
+++ b/src/SMAPI/Events/EventArgsInput.cs
@@ -18,9 +18,11 @@ namespace StardewModdingAPI.Events
/// <summary>The current cursor position.</summary>
public ICursorPosition Cursor { get; }
+#if !STARDEW_VALLEY_1_3
/// <summary>Whether the input is considered a 'click' by the game for enabling action.</summary>
[Obsolete("Use " + nameof(EventArgsInput.IsActionButton) + " or " + nameof(EventArgsInput.IsUseToolButton) + " instead")] // deprecated in SMAPI 2.1
public bool IsClick => this.IsActionButton;
+#endif
/// <summary>Whether the input should trigger actions on the affected tile.</summary>
public bool IsActionButton { get; }
diff --git a/src/SMAPI/Events/EventArgsInventoryChanged.cs b/src/SMAPI/Events/EventArgsInventoryChanged.cs
index 1ee02842..b85ae9db 100644
--- a/src/SMAPI/Events/EventArgsInventoryChanged.cs
+++ b/src/SMAPI/Events/EventArgsInventoryChanged.cs
@@ -12,7 +12,11 @@ namespace StardewModdingAPI.Events
** Accessors
*********/
/// <summary>The player's inventory.</summary>
+#if STARDEW_VALLEY_1_3
+ public IList<Item> Inventory { get; }
+#else
public List<Item> Inventory { get; }
+#endif
/// <summary>The added items.</summary>
public List<ItemStackChange> Added { get; }
@@ -30,7 +34,13 @@ namespace StardewModdingAPI.Events
/// <summary>Construct an instance.</summary>
/// <param name="inventory">The player's inventory.</param>
/// <param name="changedItems">The inventory changes.</param>
- public EventArgsInventoryChanged(List<Item> inventory, List<ItemStackChange> changedItems)
+ public EventArgsInventoryChanged(
+#if STARDEW_VALLEY_1_3
+ IList<Item> inventory,
+#else
+ List<Item> inventory,
+#endif
+ List<ItemStackChange> changedItems)
{
this.Inventory = inventory;
this.Added = changedItems.Where(n => n.ChangeType == ChangeType.Added).ToList();
diff --git a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs b/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs
index 058999e9..180e9d78 100644
--- a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs
+++ b/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs
@@ -1,6 +1,11 @@
-using System;
+using System;
using Microsoft.Xna.Framework;
+#if STARDEW_VALLEY_1_3
+using System.Collections.Generic;
+using Netcode;
+#else
using StardewValley;
+#endif
using Object = StardewValley.Object;
namespace StardewModdingAPI.Events
@@ -12,7 +17,11 @@ namespace StardewModdingAPI.Events
** Accessors
*********/
/// <summary>The current list of objects in the current location.</summary>
+#if STARDEW_VALLEY_1_3
+ public IDictionary<Vector2, NetRef<Object>> NewObjects { get; }
+#else
public SerializableDictionary<Vector2, Object> NewObjects { get; }
+#endif
/*********
@@ -20,7 +29,13 @@ namespace StardewModdingAPI.Events
*********/
/// <summary>Construct an instance.</summary>
/// <param name="newObjects">The current list of objects in the current location.</param>
- public EventArgsLocationObjectsChanged(SerializableDictionary<Vector2, Object> newObjects)
+ public EventArgsLocationObjectsChanged(
+#if STARDEW_VALLEY_1_3
+ IDictionary<Vector2, NetRef<Object>> newObjects
+#else
+ SerializableDictionary<Vector2, Object> newObjects
+#endif
+ )
{
this.NewObjects = newObjects;
}
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>
+