summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/GlobalAssemblyInfo.cs4
-rw-r--r--docs/release-notes.md7
-rw-r--r--src/SMAPI.Mods.ConsoleCommands/manifest.json2
-rw-r--r--src/SMAPI.Web/Views/LogParser/Index.cshtml15
-rw-r--r--src/SMAPI/Constants.cs2
-rw-r--r--src/SMAPI/Framework/Content/AssetData.cs12
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForDictionary.cs5
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForImage.cs5
-rw-r--r--src/SMAPI/Framework/Content/AssetDataForObject.cs8
9 files changed, 43 insertions, 17 deletions
diff --git a/build/GlobalAssemblyInfo.cs b/build/GlobalAssemblyInfo.cs
index 83bf7d82..f90ab358 100644
--- a/build/GlobalAssemblyInfo.cs
+++ b/build/GlobalAssemblyInfo.cs
@@ -1,5 +1,5 @@
using System.Reflection;
[assembly: AssemblyProduct("SMAPI")]
-[assembly: AssemblyVersion("2.5.1")]
-[assembly: AssemblyFileVersion("2.5.1")]
+[assembly: AssemblyVersion("2.5.2")]
+[assembly: AssemblyFileVersion("2.5.2")]
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 35f711fb..0da5220b 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -1,4 +1,11 @@
# Release notes
+## 2.5.2
+* For modders:
+ * Fixed issue where replacing an asset through `asset.AsImage()` or `asset.AsDictionary()` didn't take effect.
+
+* For the [log parser][]:
+ * Fixed blank page after uploading a log in some cases.
+
## 2.5.1
* For players:
* Fixed event error in rare cases.
diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json
index 645f4315..f4b3884d 100644
--- a/src/SMAPI.Mods.ConsoleCommands/manifest.json
+++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json
@@ -1,7 +1,7 @@
{
"Name": "Console Commands",
"Author": "SMAPI",
- "Version": "2.5.1",
+ "Version": "2.5.2",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll"
diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml
index 20e20ee1..be9f74a0 100644
--- a/src/SMAPI.Web/Views/LogParser/Index.cshtml
+++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml
@@ -1,11 +1,18 @@
@{
ViewData["Title"] = "SMAPI log parser";
- Dictionary<string, LogModInfo[]> contentPacks = Model.ParsedLog?.Mods
+ IDictionary<string, LogModInfo[]> contentPacks = Model.ParsedLog?.Mods
?.GroupBy(mod => mod.ContentPackFor)
.Where(group => group.Key != null)
.ToDictionary(group => group.Key, group => group.ToArray());
+
+ Regex slugInvalidCharPattern = new Regex("[^a-z0-9]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ string GetSlug(string modName)
+ {
+ return slugInvalidCharPattern.Replace(modName, "");
+ }
}
+@using System.Text.RegularExpressions
@using Newtonsoft.Json
@using StardewModdingAPI.Web.Framework.LogParsing.Models
@model StardewModdingAPI.Web.ViewModels.LogParserModel
@@ -19,7 +26,7 @@
smapi.logParser({
logStarted: new Date(@Json.Serialize(Model.ParsedLog?.Timestamp)),
showPopup: @Json.Serialize(Model.ParsedLog == null),
- showMods: @Json.Serialize(Model.ParsedLog?.Mods?.ToDictionary(p => p.Name, p => true), new JsonSerializerSettings { Formatting = Formatting.None }),
+ showMods: @Json.Serialize(Model.ParsedLog?.Mods?.ToDictionary(p => GetSlug(p.Name), p => true), new JsonSerializerSettings { Formatting = Formatting.None }),
showLevels: {
trace: false,
debug: false,
@@ -76,8 +83,8 @@
</caption>
@foreach (var mod in Model.ParsedLog.Mods.Where(p => p.ContentPackFor == null))
{
- <tr v-on:click="toggleMod('@mod.Name')" class="mod-entry" v-bind:class="{ hidden: !showMods['@mod.Name'] }">
- <td><input type="checkbox" v-bind:checked="showMods['@mod.Name']" v-if="anyModsHidden" /></td>
+ <tr v-on:click="toggleMod('@GetSlug(mod.Name)')" class="mod-entry" v-bind:class="{ hidden: !showMods['@GetSlug(mod.Name)'] }">
+ <td><input type="checkbox" v-bind:checked="showMods['@GetSlug(mod.Name)']" v-if="anyModsHidden" /></td>
<td>
@mod.Name
@if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList))
diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs
index 3e57ded9..fe9fdf9b 100644
--- a/src/SMAPI/Constants.cs
+++ b/src/SMAPI/Constants.cs
@@ -37,7 +37,7 @@ namespace StardewModdingAPI
** Public
****/
/// <summary>SMAPI's current semantic version.</summary>
- public static ISemanticVersion ApiVersion { get; } = new SemanticVersion("2.5.1");
+ public static ISemanticVersion ApiVersion { get; } = new SemanticVersion("2.5.2");
/// <summary>The minimum supported version of Stardew Valley.</summary>
public static ISemanticVersion MinimumGameVersion { get; } = new SemanticVersion("1.2.30");
diff --git a/src/SMAPI/Framework/Content/AssetData.cs b/src/SMAPI/Framework/Content/AssetData.cs
index 1ab9eebd..0a86f54d 100644
--- a/src/SMAPI/Framework/Content/AssetData.cs
+++ b/src/SMAPI/Framework/Content/AssetData.cs
@@ -7,6 +7,13 @@ namespace StardewModdingAPI.Framework.Content
internal class AssetData<TValue> : AssetInfo, IAssetData<TValue>
{
/*********
+ ** Properties
+ *********/
+ /// <summary>A callback to invoke when the data is replaced (if any).</summary>
+ private readonly Action<TValue> OnDataReplaced;
+
+
+ /*********
** Accessors
*********/
/// <summary>The content data being read.</summary>
@@ -21,10 +28,12 @@ namespace StardewModdingAPI.Framework.Content
/// <param name="assetName">The normalised asset name being read.</param>
/// <param name="data">The content data being read.</param>
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
- public AssetData(string locale, string assetName, TValue data, Func<string, string> getNormalisedPath)
+ /// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param>
+ public AssetData(string locale, string assetName, TValue data, Func<string, string> getNormalisedPath, Action<TValue> onDataReplaced)
: base(locale, assetName, data.GetType(), getNormalisedPath)
{
this.Data = data;
+ this.OnDataReplaced = onDataReplaced;
}
/// <summary>Replace the entire content value with the given value. This is generally not recommended, since it may break compatibility with other mods or different versions of the game.</summary>
@@ -39,6 +48,7 @@ namespace StardewModdingAPI.Framework.Content
throw new InvalidCastException($"Can't replace loaded asset of type {this.GetFriendlyTypeName(this.DataType)} with value of type {this.GetFriendlyTypeName(value.GetType())}. The new type must be compatible to prevent game errors.");
this.Data = value;
+ this.OnDataReplaced?.Invoke(value);
}
}
}
diff --git a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs
index e9b29b12..7b80875f 100644
--- a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs
@@ -15,8 +15,9 @@ namespace StardewModdingAPI.Framework.Content
/// <param name="assetName">The normalised asset name being read.</param>
/// <param name="data">The content data being read.</param>
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
- public AssetDataForDictionary(string locale, string assetName, IDictionary<TKey, TValue> data, Func<string, string> getNormalisedPath)
- : base(locale, assetName, data, getNormalisedPath) { }
+ /// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param>
+ public AssetDataForDictionary(string locale, string assetName, IDictionary<TKey, TValue> data, Func<string, string> getNormalisedPath, Action<IDictionary<TKey, TValue>> onDataReplaced)
+ : base(locale, assetName, data, getNormalisedPath, onDataReplaced) { }
/// <summary>Add or replace an entry in the dictionary.</summary>
/// <param name="key">The entry key.</param>
diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs
index 45c5588b..c665484f 100644
--- a/src/SMAPI/Framework/Content/AssetDataForImage.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs
@@ -15,8 +15,9 @@ namespace StardewModdingAPI.Framework.Content
/// <param name="assetName">The normalised asset name being read.</param>
/// <param name="data">The content data being read.</param>
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
- public AssetDataForImage(string locale, string assetName, Texture2D data, Func<string, string> getNormalisedPath)
- : base(locale, assetName, data, getNormalisedPath) { }
+ /// <param name="onDataReplaced">A callback to invoke when the data is replaced (if any).</param>
+ public AssetDataForImage(string locale, string assetName, Texture2D data, Func<string, string> getNormalisedPath, Action<Texture2D> onDataReplaced)
+ : base(locale, assetName, data, getNormalisedPath, onDataReplaced) { }
/// <summary>Overwrite part of the image.</summary>
/// <param name="source">The image to patch into the content.</param>
diff --git a/src/SMAPI/Framework/Content/AssetDataForObject.cs b/src/SMAPI/Framework/Content/AssetDataForObject.cs
index f30003e4..90f9e2d4 100644
--- a/src/SMAPI/Framework/Content/AssetDataForObject.cs
+++ b/src/SMAPI/Framework/Content/AssetDataForObject.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
@@ -16,7 +16,7 @@ namespace StardewModdingAPI.Framework.Content
/// <param name="data">The content data being read.</param>
/// <param name="getNormalisedPath">Normalises an asset key to match the cache key.</param>
public AssetDataForObject(string locale, string assetName, object data, Func<string, string> getNormalisedPath)
- : base(locale, assetName, data, getNormalisedPath) { }
+ : base(locale, assetName, data, getNormalisedPath, onDataReplaced: null) { }
/// <summary>Construct an instance.</summary>
/// <param name="info">The asset metadata.</param>
@@ -31,14 +31,14 @@ namespace StardewModdingAPI.Framework.Content
/// <exception cref="InvalidOperationException">The content being read isn't a dictionary.</exception>
public IAssetDataForDictionary<TKey, TValue> AsDictionary<TKey, TValue>()
{
- return new AssetDataForDictionary<TKey, TValue>(this.Locale, this.AssetName, this.GetData<IDictionary<TKey, TValue>>(), this.GetNormalisedPath);
+ return new AssetDataForDictionary<TKey, TValue>(this.Locale, this.AssetName, this.GetData<IDictionary<TKey, TValue>>(), this.GetNormalisedPath, this.ReplaceWith);
}
/// <summary>Get a helper to manipulate the data as an image.</summary>
/// <exception cref="InvalidOperationException">The content being read isn't an image.</exception>
public IAssetDataForImage AsImage()
{
- return new AssetDataForImage(this.Locale, this.AssetName, this.GetData<Texture2D>(), this.GetNormalisedPath);
+ return new AssetDataForImage(this.Locale, this.AssetName, this.GetData<Texture2D>(), this.GetNormalisedPath, this.ReplaceWith);
}
/// <summary>Get the data as a given type.</summary>