diff options
Diffstat (limited to 'src/SMAPI/Framework/Content')
-rw-r--r-- | src/SMAPI/Framework/Content/AssetData.cs | 7 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetDataForDictionary.cs | 4 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetDataForImage.cs | 4 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetDataForMap.cs | 75 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetDataForObject.cs | 25 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetEditOperation.cs | 6 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetInfo.cs | 16 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetInterceptorChange.cs | 7 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetLoadOperation.cs | 6 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetName.cs | 21 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/AssetOperationGroup.cs | 2 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/ContentCache.cs | 17 | ||||
-rw-r--r-- | src/SMAPI/Framework/Content/TilesheetReference.cs | 2 |
13 files changed, 117 insertions, 75 deletions
diff --git a/src/SMAPI/Framework/Content/AssetData.cs b/src/SMAPI/Framework/Content/AssetData.cs index be4a7ce6..0367e999 100644 --- a/src/SMAPI/Framework/Content/AssetData.cs +++ b/src/SMAPI/Framework/Content/AssetData.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; namespace StardewModdingAPI.Framework.Content @@ -7,12 +5,13 @@ namespace StardewModdingAPI.Framework.Content /// <summary>Base implementation for a content helper which encapsulates access and changes to content being read from a data file.</summary> /// <typeparam name="TValue">The interface value type.</typeparam> internal class AssetData<TValue> : AssetInfo, IAssetData<TValue> + where TValue : notnull { /********* ** Fields *********/ /// <summary>A callback to invoke when the data is replaced (if any).</summary> - private readonly Action<TValue> OnDataReplaced; + private readonly Action<TValue>? OnDataReplaced; /********* @@ -31,7 +30,7 @@ namespace StardewModdingAPI.Framework.Content /// <param name="data">The content data being read.</param> /// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param> /// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param> - public AssetData(string locale, IAssetName assetName, TValue data, Func<string, string> getNormalizedPath, Action<TValue> onDataReplaced) + public AssetData(string? locale, IAssetName assetName, TValue data, Func<string, string> getNormalizedPath, Action<TValue>? onDataReplaced) : base(locale, assetName, data.GetType(), getNormalizedPath) { this.Data = data; diff --git a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs index 06dbe259..d9bfa7bf 100644 --- a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs +++ b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; @@ -17,7 +15,7 @@ namespace StardewModdingAPI.Framework.Content /// <param name="data">The content data being read.</param> /// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param> /// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param> - public AssetDataForDictionary(string locale, IAssetName assetName, IDictionary<TKey, TValue> data, Func<string, string> getNormalizedPath, Action<IDictionary<TKey, TValue>> onDataReplaced) + public AssetDataForDictionary(string? locale, IAssetName assetName, IDictionary<TKey, TValue> data, Func<string, string> getNormalizedPath, Action<IDictionary<TKey, TValue>> onDataReplaced) : base(locale, assetName, data, getNormalizedPath, onDataReplaced) { } } } diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs index 8e59cd27..97729c95 100644 --- a/src/SMAPI/Framework/Content/AssetDataForImage.cs +++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -27,7 +25,7 @@ namespace StardewModdingAPI.Framework.Content /// <param name="data">The content data being read.</param> /// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param> /// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param> - public AssetDataForImage(string locale, IAssetName assetName, Texture2D data, Func<string, string> getNormalizedPath, Action<Texture2D> onDataReplaced) + public AssetDataForImage(string? locale, IAssetName assetName, Texture2D data, Func<string, string> getNormalizedPath, Action<Texture2D> onDataReplaced) : base(locale, assetName, data, getNormalizedPath, onDataReplaced) { } /// <inheritdoc /> diff --git a/src/SMAPI/Framework/Content/AssetDataForMap.cs b/src/SMAPI/Framework/Content/AssetDataForMap.cs index 0425e195..133dcc6c 100644 --- a/src/SMAPI/Framework/Content/AssetDataForMap.cs +++ b/src/SMAPI/Framework/Content/AssetDataForMap.cs @@ -1,14 +1,15 @@ -#nullable disable - using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; +using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Toolkit.Utilities; using StardewValley; using xTile; +using xTile.Dimensions; using xTile.Layers; using xTile.Tiles; +using Rectangle = Microsoft.Xna.Framework.Rectangle; namespace StardewModdingAPI.Framework.Content { @@ -16,6 +17,13 @@ namespace StardewModdingAPI.Framework.Content internal class AssetDataForMap : AssetData<Map>, IAssetDataForMap { /********* + ** Fields + *********/ + /// <summary>Simplifies access to private code.</summary> + private readonly Reflector Reflection; + + + /********* ** Public methods *********/ /// <summary>Construct an instance.</summary> @@ -24,8 +32,12 @@ namespace StardewModdingAPI.Framework.Content /// <param name="data">The content data being read.</param> /// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param> /// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param> - public AssetDataForMap(string locale, IAssetName assetName, Map data, Func<string, string> getNormalizedPath, Action<Map> onDataReplaced) - : base(locale, assetName, data, getNormalizedPath, onDataReplaced) { } + /// <param name="reflection">Simplifies access to private code.</param> + public AssetDataForMap(string? locale, IAssetName assetName, Map data, Func<string, string> getNormalizedPath, Action<Map> onDataReplaced, Reflector reflection) + : base(locale, assetName, data, getNormalizedPath, onDataReplaced) + { + this.Reflection = reflection; + } /// <inheritdoc /> /// <remarks>Derived from <see cref="GameLocation.ApplyMapOverride(Map,string,Rectangle?,Rectangle?)"/> with a few changes: @@ -112,8 +124,7 @@ namespace StardewModdingAPI.Framework.Content foreach (Layer sourceLayer in source.Layers) { // get layer - Layer targetLayer = sourceToTargetLayers[sourceLayer]; - if (targetLayer == null) + if (!sourceToTargetLayers.TryGetValue(sourceLayer, out Layer? targetLayer)) { target.AddLayer(targetLayer = new Layer(sourceLayer.Id, target, target.Layers[0].LayerSize, Layer.m_tileSize)); sourceToTargetLayers[sourceLayer] = target.GetLayer(sourceLayer.Id); @@ -123,11 +134,13 @@ namespace StardewModdingAPI.Framework.Content targetLayer.Properties.CopyFrom(sourceLayer.Properties); // create new tile - Tile sourceTile = sourceLayer.Tiles[sourcePos.X, sourcePos.Y]; - Tile newTile = sourceTile != null - ? this.CreateTile(sourceTile, targetLayer, tilesheetMap[sourceTile.TileSheet]) - : null; - newTile?.Properties.CopyFrom(sourceTile.Properties); + Tile? sourceTile = sourceLayer.Tiles[sourcePos.X, sourcePos.Y]; + Tile? newTile = null; + if (sourceTile != null) + { + newTile = this.CreateTile(sourceTile, targetLayer, tilesheetMap[sourceTile.TileSheet]); + newTile?.Properties.CopyFrom(sourceTile.Properties); + } // replace tile if (newTile != null || replaceByLayer || replaceAll) @@ -137,6 +150,42 @@ namespace StardewModdingAPI.Framework.Content } } + /// <inheritdoc /> + public bool ExtendMap(Map map, int minWidth, int minHeight) + { + bool resized = false; + + // resize layers + foreach (Layer layer in map.Layers) + { + // check if resize needed + if (layer.LayerWidth >= minWidth && layer.LayerHeight >= minHeight) + continue; + resized = true; + + // build new tile matrix + int width = Math.Max(minWidth, layer.LayerWidth); + int height = Math.Max(minHeight, layer.LayerHeight); + Tile[,] tiles = new Tile[width, height]; + for (int x = 0; x < layer.LayerWidth; x++) + { + for (int y = 0; y < layer.LayerHeight; y++) + tiles[x, y] = layer.Tiles[x, y]; + } + + // update fields + this.Reflection.GetField<Tile[,]>(layer, "m_tiles").SetValue(tiles); + this.Reflection.GetField<TileArray>(layer, "m_tileArray").SetValue(new TileArray(layer, tiles)); + this.Reflection.GetField<Size>(layer, "m_layerSize").SetValue(new Size(width, height)); + } + + // resize map + if (resized) + this.Reflection.GetMethod(map, "UpdateDisplaySize").Invoke(); + + return resized; + } + /********* ** Private methods @@ -145,7 +194,7 @@ namespace StardewModdingAPI.Framework.Content /// <param name="sourceTile">The source tile to copy.</param> /// <param name="targetLayer">The target layer.</param> /// <param name="targetSheet">The target tilesheet.</param> - private Tile CreateTile(Tile sourceTile, Layer targetLayer, TileSheet targetSheet) + private Tile? CreateTile(Tile sourceTile, Layer targetLayer, TileSheet targetSheet) { switch (sourceTile) { @@ -170,7 +219,7 @@ namespace StardewModdingAPI.Framework.Content } /// <summary>Normalize a map tilesheet path for comparison. This value should *not* be used as the actual tilesheet path.</summary> /// <param name="path">The path to normalize.</param> - private string NormalizeTilesheetPathForComparison(string path) + private string NormalizeTilesheetPathForComparison(string? path) { if (string.IsNullOrWhiteSpace(path)) return string.Empty; diff --git a/src/SMAPI/Framework/Content/AssetDataForObject.cs b/src/SMAPI/Framework/Content/AssetDataForObject.cs index 4a6df64b..e508ca30 100644 --- a/src/SMAPI/Framework/Content/AssetDataForObject.cs +++ b/src/SMAPI/Framework/Content/AssetDataForObject.cs @@ -1,8 +1,7 @@ -#nullable disable - using System; using System.Collections.Generic; using Microsoft.Xna.Framework.Graphics; +using StardewModdingAPI.Framework.Reflection; using xTile; namespace StardewModdingAPI.Framework.Content @@ -11,6 +10,13 @@ namespace StardewModdingAPI.Framework.Content internal class AssetDataForObject : AssetData<object>, IAssetData { /********* + ** Fields + *********/ + /// <summary>Simplifies access to private code.</summary> + private readonly Reflector Reflection; + + + /********* ** Public methods *********/ /// <summary>Construct an instance.</summary> @@ -18,15 +24,20 @@ namespace StardewModdingAPI.Framework.Content /// <param name="assetName">The asset name being read.</param> /// <param name="data">The content data being read.</param> /// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param> - public AssetDataForObject(string locale, IAssetName assetName, object data, Func<string, string> getNormalizedPath) - : base(locale, assetName, data, getNormalizedPath, onDataReplaced: null) { } + /// <param name="reflection">Simplifies access to private code.</param> + public AssetDataForObject(string? locale, IAssetName assetName, object data, Func<string, string> getNormalizedPath, Reflector reflection) + : base(locale, assetName, data, getNormalizedPath, onDataReplaced: null) + { + this.Reflection = reflection; + } /// <summary>Construct an instance.</summary> /// <param name="info">The asset metadata.</param> /// <param name="data">The content data being read.</param> /// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param> - public AssetDataForObject(IAssetInfo info, object data, Func<string, string> getNormalizedPath) - : this(info.Locale, info.Name, data, getNormalizedPath) { } + /// <param name="reflection">Simplifies access to private code.</param> + public AssetDataForObject(IAssetInfo info, object data, Func<string, string> getNormalizedPath, Reflector reflection) + : this(info.Locale, info.Name, data, getNormalizedPath, reflection) { } /// <inheritdoc /> public IAssetDataForDictionary<TKey, TValue> AsDictionary<TKey, TValue>() @@ -43,7 +54,7 @@ namespace StardewModdingAPI.Framework.Content /// <inheritdoc /> public IAssetDataForMap AsMap() { - return new AssetDataForMap(this.Locale, this.Name, this.GetData<Map>(), this.GetNormalizedPath, this.ReplaceWith); + return new AssetDataForMap(this.Locale, this.Name, this.GetData<Map>(), this.GetNormalizedPath, this.ReplaceWith, this.Reflection); } /// <inheritdoc /> diff --git a/src/SMAPI/Framework/Content/AssetEditOperation.cs b/src/SMAPI/Framework/Content/AssetEditOperation.cs index 1b7d0c93..464948b0 100644 --- a/src/SMAPI/Framework/Content/AssetEditOperation.cs +++ b/src/SMAPI/Framework/Content/AssetEditOperation.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using StardewModdingAPI.Events; @@ -18,7 +16,7 @@ namespace StardewModdingAPI.Framework.Content public AssetEditPriority Priority { get; } /// <summary>The content pack on whose behalf the edit is being applied, if any.</summary> - public IModMetadata OnBehalfOf { get; } + public IModMetadata? OnBehalfOf { get; } /// <summary>Apply the edit to an asset.</summary> public Action<IAssetData> ApplyEdit { get; } @@ -32,7 +30,7 @@ namespace StardewModdingAPI.Framework.Content /// <param name="priority">If there are multiple edits that apply to the same asset, the priority with which this one should be applied.</param> /// <param name="onBehalfOf">The content pack on whose behalf the edit is being applied, if any.</param> /// <param name="applyEdit">Apply the edit to an asset.</param> - public AssetEditOperation(IModMetadata mod, AssetEditPriority priority, IModMetadata onBehalfOf, Action<IAssetData> applyEdit) + public AssetEditOperation(IModMetadata mod, AssetEditPriority priority, IModMetadata? onBehalfOf, Action<IAssetData> applyEdit) { this.Mod = mod; this.Priority = priority; diff --git a/src/SMAPI/Framework/Content/AssetInfo.cs b/src/SMAPI/Framework/Content/AssetInfo.cs index 51dcc61f..16b71487 100644 --- a/src/SMAPI/Framework/Content/AssetInfo.cs +++ b/src/SMAPI/Framework/Content/AssetInfo.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; using Microsoft.Xna.Framework.Graphics; @@ -19,7 +17,7 @@ namespace StardewModdingAPI.Framework.Content ** Accessors *********/ /// <inheritdoc /> - public string Locale { get; } + public string? Locale { get; } /// <inheritdoc /> public IAssetName Name { get; } @@ -28,13 +26,13 @@ namespace StardewModdingAPI.Framework.Content public IAssetName NameWithoutLocale { get; } /// <inheritdoc /> - [Obsolete($"Use {nameof(Name)} or {nameof(NameWithoutLocale)} instead. This property will be removed in SMAPI 4.0.0.")] + [Obsolete($"Use {nameof(AssetInfo.Name)} or {nameof(AssetInfo.NameWithoutLocale)} instead. This property will be removed in SMAPI 4.0.0.")] public string AssetName { get { SCore.DeprecationManager.Warn( - source: SCore.DeprecationManager.GetSourceNameFromStack(), + source: SCore.DeprecationManager.GetModFromStack(), nounPhrase: $"{nameof(IAssetInfo)}.{nameof(IAssetInfo.AssetName)}", version: "3.14.0", severity: DeprecationLevel.Notice @@ -56,7 +54,7 @@ namespace StardewModdingAPI.Framework.Content /// <param name="assetName">The asset name being read.</param> /// <param name="type">The content type being read.</param> /// <param name="getNormalizedPath">Normalizes an asset key to match the cache key.</param> - public AssetInfo(string locale, IAssetName assetName, Type type, Func<string, string> getNormalizedPath) + public AssetInfo(string? locale, IAssetName assetName, Type type, Func<string, string> getNormalizedPath) { this.Locale = locale; this.Name = assetName; @@ -66,11 +64,11 @@ namespace StardewModdingAPI.Framework.Content } /// <inheritdoc /> - [Obsolete($"Use {nameof(Name)}.{nameof(IAssetName.IsEquivalentTo)} or {nameof(NameWithoutLocale)}.{nameof(IAssetName.IsEquivalentTo)} instead. This method will be removed in SMAPI 4.0.0.")] + [Obsolete($"Use {nameof(Name)}.{nameof(IAssetName.IsEquivalentTo)} or {nameof(AssetInfo.NameWithoutLocale)}.{nameof(IAssetName.IsEquivalentTo)} instead. This method will be removed in SMAPI 4.0.0.")] public bool AssetNameEquals(string path) { SCore.DeprecationManager.Warn( - source: SCore.DeprecationManager.GetSourceNameFromStack(), + source: SCore.DeprecationManager.GetModFromStack(), nounPhrase: $"{nameof(IAssetInfo)}.{nameof(IAssetInfo.AssetNameEquals)}", version: "3.14.0", severity: DeprecationLevel.Notice @@ -106,7 +104,7 @@ namespace StardewModdingAPI.Framework.Content return "string"; // default - return type.FullName; + return type.FullName!; } } } diff --git a/src/SMAPI/Framework/Content/AssetInterceptorChange.cs b/src/SMAPI/Framework/Content/AssetInterceptorChange.cs index 7f53db9b..fc8199e8 100644 --- a/src/SMAPI/Framework/Content/AssetInterceptorChange.cs +++ b/src/SMAPI/Framework/Content/AssetInterceptorChange.cs @@ -1,9 +1,8 @@ -#nullable disable - using System; using System.Reflection; using StardewModdingAPI.Internal; +#pragma warning disable CS0618 // obsolete asset interceptors deliberately supported here namespace StardewModdingAPI.Framework.Content { /// <summary>A wrapper for <see cref="IAssetEditor"/> and <see cref="IAssetLoader"/> for internal cache invalidation.</summary> @@ -46,11 +45,11 @@ namespace StardewModdingAPI.Framework.Content /// <param name="asset">Basic metadata about the asset being loaded.</param> public bool CanIntercept(IAssetInfo asset) { - MethodInfo canIntercept = this.GetType().GetMethod(nameof(this.CanInterceptImpl), BindingFlags.Instance | BindingFlags.NonPublic); + MethodInfo? canIntercept = this.GetType().GetMethod(nameof(this.CanInterceptImpl), BindingFlags.Instance | BindingFlags.NonPublic); if (canIntercept == null) throw new InvalidOperationException($"SMAPI couldn't access the {nameof(AssetInterceptorChange)}.{nameof(this.CanInterceptImpl)} implementation."); - return (bool)canIntercept.MakeGenericMethod(asset.DataType).Invoke(this, new object[] { asset }); + return (bool)canIntercept.MakeGenericMethod(asset.DataType).Invoke(this, new object[] { asset })!; } diff --git a/src/SMAPI/Framework/Content/AssetLoadOperation.cs b/src/SMAPI/Framework/Content/AssetLoadOperation.cs index 73e60e24..b6cdec27 100644 --- a/src/SMAPI/Framework/Content/AssetLoadOperation.cs +++ b/src/SMAPI/Framework/Content/AssetLoadOperation.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using StardewModdingAPI.Events; @@ -15,7 +13,7 @@ namespace StardewModdingAPI.Framework.Content public IModMetadata Mod { get; } /// <summary>The content pack on whose behalf the asset is being loaded, if any.</summary> - public IModMetadata OnBehalfOf { get; } + public IModMetadata? OnBehalfOf { get; } /// <summary>If there are multiple loads that apply to the same asset, the priority with which this one should be applied.</summary> public AssetLoadPriority Priority { get; } @@ -32,7 +30,7 @@ namespace StardewModdingAPI.Framework.Content /// <param name="priority">If there are multiple loads that apply to the same asset, the priority with which this one should be applied.</param> /// <param name="onBehalfOf">The content pack on whose behalf the asset is being loaded, if any.</param> /// <param name="getData">Load the initial value for an asset.</param> - public AssetLoadOperation(IModMetadata mod, AssetLoadPriority priority, IModMetadata onBehalfOf, Func<IAssetInfo, object> getData) + public AssetLoadOperation(IModMetadata mod, AssetLoadPriority priority, IModMetadata? onBehalfOf, Func<IAssetInfo, object> getData) { this.Mod = mod; this.Priority = priority; diff --git a/src/SMAPI/Framework/Content/AssetName.cs b/src/SMAPI/Framework/Content/AssetName.cs index 4d583d82..4c691b9a 100644 --- a/src/SMAPI/Framework/Content/AssetName.cs +++ b/src/SMAPI/Framework/Content/AssetName.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using StardewModdingAPI.Toolkit.Utilities; using StardewValley; @@ -26,7 +24,7 @@ namespace StardewModdingAPI.Framework.Content public string BaseName { get; } /// <inheritdoc /> - public string LocaleCode { get; } + public string? LocaleCode { get; } /// <inheritdoc /> public LocalizedContentManager.LanguageCode? LanguageCode { get; } @@ -39,7 +37,7 @@ namespace StardewModdingAPI.Framework.Content /// <param name="baseName">The base asset name without the locale code.</param> /// <param name="localeCode">The locale code specified in the <see cref="Name"/>, if it's a valid code recognized by the game content.</param> /// <param name="languageCode">The language code matching the <see cref="LocaleCode"/>, if applicable.</param> - public AssetName(string baseName, string localeCode, LocalizedContentManager.LanguageCode? languageCode) + public AssetName(string baseName, string? localeCode, LocalizedContentManager.LanguageCode? languageCode) { // validate if (string.IsNullOrWhiteSpace(baseName)) @@ -69,7 +67,7 @@ namespace StardewModdingAPI.Framework.Content throw new ArgumentException("The asset name can't be null or empty.", nameof(rawName)); string baseName = rawName; - string localeCode = null; + string? localeCode = null; LocalizedContentManager.LanguageCode? languageCode = null; int lastPeriodIndex = rawName.LastIndexOf('.'); @@ -90,7 +88,7 @@ namespace StardewModdingAPI.Framework.Content } /// <inheritdoc /> - public bool IsEquivalentTo(string assetName, bool useBaseName = false) + public bool IsEquivalentTo(string? assetName, bool useBaseName = false) { // empty asset key is never equivalent if (string.IsNullOrWhiteSpace(assetName)) @@ -103,7 +101,7 @@ namespace StardewModdingAPI.Framework.Content } /// <inheritdoc /> - public bool IsEquivalentTo(IAssetName assetName, bool useBaseName = false) + public bool IsEquivalentTo(IAssetName? assetName, bool useBaseName = false) { if (useBaseName) return this.BaseName.Equals(assetName?.BaseName, StringComparison.OrdinalIgnoreCase); @@ -115,7 +113,7 @@ namespace StardewModdingAPI.Framework.Content } /// <inheritdoc /> - public bool StartsWith(string prefix, bool allowPartialWord = true, bool allowSubfolder = true) + public bool StartsWith(string? prefix, bool allowPartialWord = true, bool allowSubfolder = true) { // asset keys never start with null if (prefix is null) @@ -157,8 +155,11 @@ namespace StardewModdingAPI.Framework.Content /// <inheritdoc /> - public bool IsDirectlyUnderPath(string assetFolder) + public bool IsDirectlyUnderPath(string? assetFolder) { + if (assetFolder is null) + return false; + return this.StartsWith(assetFolder + "/", allowPartialWord: false, allowSubfolder: false); } @@ -171,7 +172,7 @@ namespace StardewModdingAPI.Framework.Content } /// <inheritdoc /> - public bool Equals(IAssetName other) + public bool Equals(IAssetName? other) { return other switch { diff --git a/src/SMAPI/Framework/Content/AssetOperationGroup.cs b/src/SMAPI/Framework/Content/AssetOperationGroup.cs index e3c3f92c..a2fcb722 100644 --- a/src/SMAPI/Framework/Content/AssetOperationGroup.cs +++ b/src/SMAPI/Framework/Content/AssetOperationGroup.cs @@ -1,5 +1,3 @@ -#nullable disable - namespace StardewModdingAPI.Framework.Content { /// <summary>A set of operations to apply to an asset for a given <see cref="IAssetEditor"/> or <see cref="IAssetLoader"/> implementation.</summary> diff --git a/src/SMAPI/Framework/Content/ContentCache.cs b/src/SMAPI/Framework/Content/ContentCache.cs index 4e620d28..cbb6c1e9 100644 --- a/src/SMAPI/Framework/Content/ContentCache.cs +++ b/src/SMAPI/Framework/Content/ContentCache.cs @@ -1,12 +1,9 @@ -#nullable disable - using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Linq; -using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Toolkit.Utilities; -using StardewValley; namespace StardewModdingAPI.Framework.Content { @@ -42,11 +39,10 @@ namespace StardewModdingAPI.Framework.Content ** Constructor ****/ /// <summary>Construct an instance.</summary> - /// <param name="contentManager">The underlying content manager whose cache to manage.</param> - /// <param name="reflection">Simplifies access to private game code.</param> - public ContentCache(LocalizedContentManager contentManager, Reflector reflection) + /// <param name="loadedAssets">The asset cache for the underlying content manager.</param> + public ContentCache(Dictionary<string, object> loadedAssets) { - this.Cache = reflection.GetField<Dictionary<string, object>>(contentManager, "loadedAssets").GetValue(); + this.Cache = loadedAssets; } /**** @@ -66,7 +62,8 @@ namespace StardewModdingAPI.Framework.Content /// <summary>Normalize path separators in an asset name.</summary> /// <param name="path">The file path to normalize.</param> [Pure] - public string NormalizePathSeparators(string path) + [return: NotNullIfNotNull("path")] + public string? NormalizePathSeparators(string? path) { return PathUtilities.NormalizeAssetName(path); } @@ -93,7 +90,7 @@ namespace StardewModdingAPI.Framework.Content public bool Remove(string key, bool dispose) { // get entry - if (!this.Cache.TryGetValue(key, out object value)) + if (!this.Cache.TryGetValue(key, out object? value)) return false; // dispose & remove entry diff --git a/src/SMAPI/Framework/Content/TilesheetReference.cs b/src/SMAPI/Framework/Content/TilesheetReference.cs index cdc4bc62..0339b802 100644 --- a/src/SMAPI/Framework/Content/TilesheetReference.cs +++ b/src/SMAPI/Framework/Content/TilesheetReference.cs @@ -1,5 +1,3 @@ -#nullable disable - using xTile.Dimensions; namespace StardewModdingAPI.Framework.Content |