summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2018-06-05 20:22:46 -0400
committerJesse Plamondon-Willard <github@jplamondonw.com>2018-06-05 20:22:46 -0400
commit625c538f244519700f3942b2b2969845db9a99b0 (patch)
treed13596220a62616838310cbcf0f0004e2f843da3 /src/SMAPI/Framework
parent265ce35fd1db677230ddb16483b4d92e7c13a777 (diff)
downloadSMAPI-625c538f244519700f3942b2b2969845db9a99b0.tar.gz
SMAPI-625c538f244519700f3942b2b2969845db9a99b0.tar.bz2
SMAPI-625c538f244519700f3942b2b2969845db9a99b0.zip
move manifest parsing into toolkit (#532)
Diffstat (limited to 'src/SMAPI/Framework')
-rw-r--r--src/SMAPI/Framework/ContentPack.cs2
-rw-r--r--src/SMAPI/Framework/Exceptions/SParseException.cs17
-rw-r--r--src/SMAPI/Framework/InternalExtensions.cs16
-rw-r--r--src/SMAPI/Framework/LegacyManifestVersion.cs26
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModHelper.cs20
-rw-r--r--src/SMAPI/Framework/ModLoading/ModResolver.cs37
-rw-r--r--src/SMAPI/Framework/Models/Manifest.cs74
-rw-r--r--src/SMAPI/Framework/Models/ManifestContentPackFor.cs25
-rw-r--r--src/SMAPI/Framework/Models/ManifestDependency.cs11
-rw-r--r--src/SMAPI/Framework/Serialisation/ColorConverter.cs (renamed from src/SMAPI/Framework/Serialisation/CrossplatformConverters/ColorConverter.cs)5
-rw-r--r--src/SMAPI/Framework/Serialisation/JsonHelper.cs139
-rw-r--r--src/SMAPI/Framework/Serialisation/PointConverter.cs (renamed from src/SMAPI/Framework/Serialisation/CrossplatformConverters/PointConverter.cs)5
-rw-r--r--src/SMAPI/Framework/Serialisation/RectangleConverter.cs (renamed from src/SMAPI/Framework/Serialisation/CrossplatformConverters/RectangleConverter.cs)5
-rw-r--r--src/SMAPI/Framework/Serialisation/SimpleReadOnlyConverter.cs77
-rw-r--r--src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestContentPackForConverter.cs50
-rw-r--r--src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestDependencyArrayConverter.cs60
-rw-r--r--src/SMAPI/Framework/Serialisation/SmapiConverters/SemanticVersionConverter.cs36
-rw-r--r--src/SMAPI/Framework/Serialisation/SmapiConverters/StringEnumConverter.cs22
18 files changed, 131 insertions, 496 deletions
diff --git a/src/SMAPI/Framework/ContentPack.cs b/src/SMAPI/Framework/ContentPack.cs
index ee6df1ec..4a4adb90 100644
--- a/src/SMAPI/Framework/ContentPack.cs
+++ b/src/SMAPI/Framework/ContentPack.cs
@@ -2,7 +2,7 @@ using System;
using System.IO;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
-using StardewModdingAPI.Framework.Serialisation;
+using StardewModdingAPI.Toolkit.Serialisation;
using StardewModdingAPI.Toolkit.Utilities;
using xTile;
diff --git a/src/SMAPI/Framework/Exceptions/SParseException.cs b/src/SMAPI/Framework/Exceptions/SParseException.cs
deleted file mode 100644
index f7133ee7..00000000
--- a/src/SMAPI/Framework/Exceptions/SParseException.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-
-namespace StardewModdingAPI.Framework.Exceptions
-{
- /// <summary>A format exception which provides a user-facing error message.</summary>
- internal class SParseException : FormatException
- {
- /*********
- ** Public methods
- *********/
- /// <summary>Construct an instance.</summary>
- /// <param name="message">The error message.</param>
- /// <param name="ex">The underlying exception, if any.</param>
- public SParseException(string message, Exception ex = null)
- : base(message, ex) { }
- }
-}
diff --git a/src/SMAPI/Framework/InternalExtensions.cs b/src/SMAPI/Framework/InternalExtensions.cs
index bff4807c..ff3925fb 100644
--- a/src/SMAPI/Framework/InternalExtensions.cs
+++ b/src/SMAPI/Framework/InternalExtensions.cs
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Xna.Framework.Graphics;
-using Newtonsoft.Json.Linq;
using StardewModdingAPI.Framework.Reflection;
using StardewValley;
@@ -91,20 +90,5 @@ namespace StardewModdingAPI.Framework
// get result
return reflection.GetField<bool>(Game1.spriteBatch, fieldName).GetValue();
}
-
- /****
- ** Json.NET
- ****/
- /// <summary>Get a JSON field value from a case-insensitive field name. This will check for an exact match first, then search without case sensitivity.</summary>
- /// <typeparam name="T">The value type.</typeparam>
- /// <param name="obj">The JSON object to search.</param>
- /// <param name="fieldName">The field name.</param>
- public static T ValueIgnoreCase<T>(this JObject obj, string fieldName)
- {
- JToken token = obj.GetValue(fieldName, StringComparison.InvariantCultureIgnoreCase);
- return token != null
- ? token.Value<T>()
- : default(T);
- }
}
}
diff --git a/src/SMAPI/Framework/LegacyManifestVersion.cs b/src/SMAPI/Framework/LegacyManifestVersion.cs
deleted file mode 100644
index 454b9137..00000000
--- a/src/SMAPI/Framework/LegacyManifestVersion.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using Newtonsoft.Json;
-
-namespace StardewModdingAPI.Framework
-{
- /// <summary>An implementation of <see cref="ISemanticVersion"/> that hamdles the legacy <see cref="IManifest"/> version format.</summary>
- internal class LegacyManifestVersion : SemanticVersion
- {
- /*********
- ** Public methods
- *********/
- /// <summary>Construct an instance.</summary>
- /// <param name="majorVersion">The major version incremented for major API changes.</param>
- /// <param name="minorVersion">The minor version incremented for backwards-compatible changes.</param>
- /// <param name="patchVersion">The patch version for backwards-compatible bug fixes.</param>
- /// <param name="build">An optional build tag.</param>
- [JsonConstructor]
- public LegacyManifestVersion(int majorVersion, int minorVersion, int patchVersion, string build = null)
- : base(
- majorVersion,
- minorVersion,
- patchVersion,
- build != "0" ? build : null // '0' from incorrect examples in old SMAPI documentation
- )
- { }
- }
-}
diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs
index e8726938..18904857 100644
--- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs
@@ -5,7 +5,7 @@ using System.Linq;
using StardewModdingAPI.Events;
using StardewModdingAPI.Framework.Input;
using StardewModdingAPI.Framework.Models;
-using StardewModdingAPI.Framework.Serialisation;
+using StardewModdingAPI.Toolkit.Serialisation;
using StardewModdingAPI.Toolkit.Utilities;
namespace StardewModdingAPI.Framework.ModHelpers
@@ -179,16 +179,14 @@ namespace StardewModdingAPI.Framework.ModHelpers
throw new ArgumentException($"Can't create content pack for directory path '{directoryPath}' because no such directory exists.");
// create manifest
- IManifest manifest = new Manifest
- {
- Name = name,
- Author = author,
- Description = description,
- Version = version,
- UniqueID = id,
- UpdateKeys = new string[0],
- ContentPackFor = new ManifestContentPackFor { UniqueID = this.ModID }
- };
+ IManifest manifest = new Manifest(
+ uniqueID: id,
+ name: name,
+ author: author,
+ description: description,
+ version: version,
+ contentPackFor: new ManifestContentPackFor(this.ModID)
+ );
// create content pack
return this.CreateContentPack(directoryPath, manifest);
diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs
index d46caa55..ddc8650c 100644
--- a/src/SMAPI/Framework/ModLoading/ModResolver.cs
+++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs
@@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
-using StardewModdingAPI.Framework.Exceptions;
using StardewModdingAPI.Framework.ModData;
using StardewModdingAPI.Framework.Models;
-using StardewModdingAPI.Framework.Serialisation;
+using StardewModdingAPI.Toolkit.Serialisation;
using StardewModdingAPI.Toolkit.Utilities;
+using ToolkitManifest = StardewModdingAPI.Toolkit.Serialisation.Models.Manifest;
namespace StardewModdingAPI.Framework.ModLoading
{
@@ -28,25 +28,28 @@ namespace StardewModdingAPI.Framework.ModLoading
{
// read file
Manifest manifest = null;
- string path = Path.Combine(modDir.FullName, "manifest.json");
string error = null;
- try
{
- manifest = jsonHelper.ReadJsonFile<Manifest>(path);
- if (manifest == null)
+ string path = Path.Combine(modDir.FullName, "manifest.json");
+ try
{
- error = File.Exists(path)
- ? "its manifest is invalid."
- : "it doesn't have a manifest.";
+ ToolkitManifest rawManifest = jsonHelper.ReadJsonFile<ToolkitManifest>(path);
+ if (rawManifest == null)
+ {
+ error = File.Exists(path)
+ ? "its manifest is invalid."
+ : "it doesn't have a manifest.";
+ }
+ manifest = new Manifest(rawManifest);
+ }
+ catch (SParseException ex)
+ {
+ error = $"parsing its manifest failed: {ex.Message}";
+ }
+ catch (Exception ex)
+ {
+ error = $"parsing its manifest failed:\n{ex.GetLogSummary()}";
}
- }
- catch (SParseException ex)
- {
- error = $"parsing its manifest failed: {ex.Message}";
- }
- catch (Exception ex)
- {
- error = $"parsing its manifest failed:\n{ex.GetLogSummary()}";
}
// parse internal data record (if any)
diff --git a/src/SMAPI/Framework/Models/Manifest.cs b/src/SMAPI/Framework/Models/Manifest.cs
index f5867cf3..92ffe0dc 100644
--- a/src/SMAPI/Framework/Models/Manifest.cs
+++ b/src/SMAPI/Framework/Models/Manifest.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
+using System.Linq;
using Newtonsoft.Json;
-using StardewModdingAPI.Framework.Serialisation.SmapiConverters;
namespace StardewModdingAPI.Framework.Models
{
@@ -11,39 +11,87 @@ namespace StardewModdingAPI.Framework.Models
** Accessors
*********/
/// <summary>The mod name.</summary>
- public string Name { get; set; }
+ public string Name { get; }
/// <summary>A brief description of the mod.</summary>
- public string Description { get; set; }
+ public string Description { get; }
/// <summary>The mod author's name.</summary>
- public string Author { get; set; }
+ public string Author { get; }
/// <summary>The mod version.</summary>
- public ISemanticVersion Version { get; set; }
+ public ISemanticVersion Version { get; }
/// <summary>The minimum SMAPI version required by this mod, if any.</summary>
- public ISemanticVersion MinimumApiVersion { get; set; }
+ public ISemanticVersion MinimumApiVersion { get; }
/// <summary>The name of the DLL in the directory that has the <see cref="IMod.Entry"/> method. Mutually exclusive with <see cref="ContentPackFor"/>.</summary>
- public string EntryDll { get; set; }
+ public string EntryDll { get; }
/// <summary>The mod which will read this as a content pack. Mutually exclusive with <see cref="IManifest.EntryDll"/>.</summary>
- [JsonConverter(typeof(ManifestContentPackForConverter))]
- public IManifestContentPackFor ContentPackFor { get; set; }
+ public IManifestContentPackFor ContentPackFor { get; }
/// <summary>The other mods that must be loaded before this mod.</summary>
- [JsonConverter(typeof(ManifestDependencyArrayConverter))]
- public IManifestDependency[] Dependencies { get; set; }
+ public IManifestDependency[] Dependencies { get; }
/// <summary>The namespaced mod IDs to query for updates (like <c>Nexus:541</c>).</summary>
public string[] UpdateKeys { get; set; }
/// <summary>The unique mod ID.</summary>
- public string UniqueID { get; set; }
+ public string UniqueID { get; }
/// <summary>Any manifest fields which didn't match a valid field.</summary>
[JsonExtensionData]
- public IDictionary<string, object> ExtraFields { get; set; }
+ public IDictionary<string, object> ExtraFields { get; }
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="manifest">The toolkit manifest.</param>
+ public Manifest(Toolkit.Serialisation.Models.Manifest manifest)
+ : this(
+ uniqueID: manifest.UniqueID,
+ name: manifest.Name,
+ author: manifest.Author,
+ description: manifest.Description,
+ version: manifest.Version != null ? new SemanticVersion(manifest.Version) : null,
+ entryDll: manifest.EntryDll,
+ minimumApiVersion: manifest.MinimumApiVersion != null ? new SemanticVersion(manifest.MinimumApiVersion) : null,
+ contentPackFor: manifest.ContentPackFor != null ? new ManifestContentPackFor(manifest.ContentPackFor) : null,
+ dependencies: manifest.Dependencies?.Select(p => p != null ? (IManifestDependency)new ManifestDependency(p) : null).ToArray(),
+ updateKeys: manifest.UpdateKeys,
+ extraFields: manifest.ExtraFields
+ )
+ { }
+
+ /// <summary>Construct an instance for a transitional content pack.</summary>
+ /// <param name="uniqueID">The unique mod ID.</param>
+ /// <param name="name">The mod name.</param>
+ /// <param name="author">The mod author's name.</param>
+ /// <param name="description">A brief description of the mod.</param>
+ /// <param name="version">The mod version.</param>
+ /// <param name="entryDll">The name of the DLL in the directory that has the <see cref="IMod.Entry"/> method. Mutually exclusive with <paramref name="contentPackFor"/>.</param>
+ /// <param name="minimumApiVersion">The minimum SMAPI version required by this mod, if any.</param>
+ /// <param name="contentPackFor">The modID which will read this as a content pack. Mutually exclusive with <paramref name="entryDll"/>.</param>
+ /// <param name="dependencies">The other mods that must be loaded before this mod.</param>
+ /// <param name="updateKeys">The namespaced mod IDs to query for updates (like <c>Nexus:541</c>).</param>
+ /// <param name="extraFields">Any manifest fields which didn't match a valid field.</param>
+ public Manifest(string uniqueID, string name, string author, string description, ISemanticVersion version, string entryDll = null, ISemanticVersion minimumApiVersion = null, IManifestContentPackFor contentPackFor = null, IManifestDependency[] dependencies = null, string[] updateKeys = null, IDictionary<string, object> extraFields = null)
+ {
+ this.Name = name;
+ this.Author = author;
+ this.Description = description;
+ this.Version = version;
+ this.UniqueID = uniqueID;
+ this.UpdateKeys = new string[0];
+ this.EntryDll = entryDll;
+ this.ContentPackFor = contentPackFor;
+ this.MinimumApiVersion = minimumApiVersion;
+ this.Dependencies = dependencies ?? new IManifestDependency[0];
+ this.UpdateKeys = updateKeys ?? new string[0];
+ this.ExtraFields = extraFields;
+ }
}
}
diff --git a/src/SMAPI/Framework/Models/ManifestContentPackFor.cs b/src/SMAPI/Framework/Models/ManifestContentPackFor.cs
index 7836bbcc..cdad8893 100644
--- a/src/SMAPI/Framework/Models/ManifestContentPackFor.cs
+++ b/src/SMAPI/Framework/Models/ManifestContentPackFor.cs
@@ -7,9 +7,30 @@ namespace StardewModdingAPI.Framework.Models
** Accessors
*********/
/// <summary>The unique ID of the mod which can read this content pack.</summary>
- public string UniqueID { get; set; }
+ public string UniqueID { get; }
/// <summary>The minimum required version (if any).</summary>
- public ISemanticVersion MinimumVersion { get; set; }
+ public ISemanticVersion MinimumVersion { get; }
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="contentPackFor">The toolkit instance.</param>
+ public ManifestContentPackFor(Toolkit.Serialisation.Models.ManifestContentPackFor contentPackFor)
+ {
+ this.UniqueID = contentPackFor.UniqueID;
+ this.MinimumVersion = new SemanticVersion(contentPackFor.MinimumVersion);
+ }
+
+ /// <summary>Construct an instance.</summary>
+ /// <param name="uniqueID">The unique ID of the mod which can read this content pack.</param>
+ /// <param name="minimumVersion">The minimum required version (if any).</param>
+ public ManifestContentPackFor(string uniqueID, ISemanticVersion minimumVersion = null)
+ {
+ this.UniqueID = uniqueID;
+ this.MinimumVersion = minimumVersion;
+ }
}
}
diff --git a/src/SMAPI/Framework/Models/ManifestDependency.cs b/src/SMAPI/Framework/Models/ManifestDependency.cs
index 97f0775a..e92597f3 100644
--- a/src/SMAPI/Framework/Models/ManifestDependency.cs
+++ b/src/SMAPI/Framework/Models/ManifestDependency.cs
@@ -7,19 +7,24 @@ namespace StardewModdingAPI.Framework.Models
** Accessors
*********/
/// <summary>The unique mod ID to require.</summary>
- public string UniqueID { get; set; }
+ public string UniqueID { get; }
/// <summary>The minimum required version (if any).</summary>
- public ISemanticVersion MinimumVersion { get; set; }
+ public ISemanticVersion MinimumVersion { get; }
/// <summary>Whether the dependency must be installed to use the mod.</summary>
- public bool IsRequired { get; set; }
+ public bool IsRequired { get; }
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
+ /// <param name="dependency">The toolkit instance.</param>
+ public ManifestDependency(Toolkit.Serialisation.Models.ManifestDependency dependency)
+ : this(dependency.UniqueID, dependency.MinimumVersion?.ToString(), dependency.IsRequired) { }
+
+ /// <summary>Construct an instance.</summary>
/// <param name="uniqueID">The unique mod ID to require.</param>
/// <param name="minimumVersion">The minimum required version (if any).</param>
/// <param name="required">Whether the dependency must be installed to use the mod.</param>
diff --git a/src/SMAPI/Framework/Serialisation/CrossplatformConverters/ColorConverter.cs b/src/SMAPI/Framework/Serialisation/ColorConverter.cs
index f1b2f04f..c27065bf 100644
--- a/src/SMAPI/Framework/Serialisation/CrossplatformConverters/ColorConverter.cs
+++ b/src/SMAPI/Framework/Serialisation/ColorConverter.cs
@@ -1,9 +1,10 @@
using System;
using Microsoft.Xna.Framework;
using Newtonsoft.Json.Linq;
-using StardewModdingAPI.Framework.Exceptions;
+using StardewModdingAPI.Toolkit.Serialisation;
+using StardewModdingAPI.Toolkit.Serialisation.Converters;
-namespace StardewModdingAPI.Framework.Serialisation.CrossplatformConverters
+namespace StardewModdingAPI.Framework.Serialisation
{
/// <summary>Handles deserialisation of <see cref="Color"/> for crossplatform compatibility.</summary>
/// <remarks>
diff --git a/src/SMAPI/Framework/Serialisation/JsonHelper.cs b/src/SMAPI/Framework/Serialisation/JsonHelper.cs
deleted file mode 100644
index 6cba343e..00000000
--- a/src/SMAPI/Framework/Serialisation/JsonHelper.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using Microsoft.Xna.Framework.Input;
-using Newtonsoft.Json;
-using StardewModdingAPI.Framework.Serialisation.CrossplatformConverters;
-using StardewModdingAPI.Framework.Serialisation.SmapiConverters;
-
-namespace StardewModdingAPI.Framework.Serialisation
-{
- /// <summary>Encapsulates SMAPI's JSON file parsing.</summary>
- internal class JsonHelper
- {
- /*********
- ** Accessors
- *********/
- /// <summary>The JSON settings to use when serialising and deserialising files.</summary>
- private readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings
- {
- Formatting = Formatting.Indented,
- ObjectCreationHandling = ObjectCreationHandling.Replace, // avoid issue where default ICollection<T> values are duplicated each time the config is loaded
- Converters = new List<JsonConverter>
- {
- // SMAPI types
- new SemanticVersionConverter(),
-
- // enums
- new StringEnumConverter<Buttons>(),
- new StringEnumConverter<Keys>(),
- new StringEnumConverter<SButton>(),
-
- // crossplatform compatibility
- new ColorConverter(),
- new PointConverter(),
- new RectangleConverter()
- }
- };
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Read a JSON file.</summary>
- /// <typeparam name="TModel">The model type.</typeparam>
- /// <param name="fullPath">The absolete file path.</param>
- /// <returns>Returns the deserialised model, or <c>null</c> if the file doesn't exist or is empty.</returns>
- /// <exception cref="InvalidOperationException">The given path is empty or invalid.</exception>
- public TModel ReadJsonFile<TModel>(string fullPath)
- where TModel : class
- {
- // validate
- if (string.IsNullOrWhiteSpace(fullPath))
- throw new ArgumentException("The file path is empty or invalid.", nameof(fullPath));
-
- // read file
- string json;
- try
- {
- json = File.ReadAllText(fullPath);
- }
- catch (Exception ex) when (ex is DirectoryNotFoundException || ex is FileNotFoundException)
- {
- return null;
- }
-
- // deserialise model
- try
- {
- return this.Deserialise<TModel>(json);
- }
- catch (Exception ex)
- {
- string error = $"Can't parse JSON file at {fullPath}.";
-
- if (ex is JsonReaderException)
- {
- error += " This doesn't seem to be valid JSON.";
- if (json.Contains("“") || json.Contains("”"))
- error += " Found curly quotes in the text; note that only straight quotes are allowed in JSON.";
- }
- error += $"\nTechnical details: {ex.Message}";
- throw new JsonReaderException(error);
- }
- }
-
- /// <summary>Save to a JSON file.</summary>
- /// <typeparam name="TModel">The model type.</typeparam>
- /// <param name="fullPath">The absolete file path.</param>
- /// <param name="model">The model to save.</param>
- /// <exception cref="InvalidOperationException">The given path is empty or invalid.</exception>
- public void WriteJsonFile<TModel>(string fullPath, TModel model)
- where TModel : class
- {
- // validate
- if (string.IsNullOrWhiteSpace(fullPath))
- throw new ArgumentException("The file path is empty or invalid.", nameof(fullPath));
-
- // create directory if needed
- string dir = Path.GetDirectoryName(fullPath);
- if (dir == null)
- throw new ArgumentException("The file path is invalid.", nameof(fullPath));
- if (!Directory.Exists(dir))
- Directory.CreateDirectory(dir);
-
- // write file
- string json = JsonConvert.SerializeObject(model, this.JsonSettings);
- File.WriteAllText(fullPath, json);
- }
-
-
- /*********
- ** Private methods
- *********/
- /// <summary>Deserialize JSON text if possible.</summary>
- /// <typeparam name="TModel">The model type.</typeparam>
- /// <param name="json">The raw JSON text.</param>
- private TModel Deserialise<TModel>(string json)
- {
- try
- {
- return JsonConvert.DeserializeObject<TModel>(json, this.JsonSettings);
- }
- catch (JsonReaderException)
- {
- // try replacing curly quotes
- if (json.Contains("“") || json.Contains("”"))
- {
- try
- {
- return JsonConvert.DeserializeObject<TModel>(json.Replace('“', '"').Replace('”', '"'), this.JsonSettings);
- }
- catch { /* rethrow original error */ }
- }
-
- throw;
- }
- }
- }
-}
diff --git a/src/SMAPI/Framework/Serialisation/CrossplatformConverters/PointConverter.cs b/src/SMAPI/Framework/Serialisation/PointConverter.cs
index 434b7ea5..fbc857d2 100644
--- a/src/SMAPI/Framework/Serialisation/CrossplatformConverters/PointConverter.cs
+++ b/src/SMAPI/Framework/Serialisation/PointConverter.cs
@@ -1,9 +1,10 @@
using System;
using Microsoft.Xna.Framework;
using Newtonsoft.Json.Linq;
-using StardewModdingAPI.Framework.Exceptions;
+using StardewModdingAPI.Toolkit.Serialisation;
+using StardewModdingAPI.Toolkit.Serialisation.Converters;
-namespace StardewModdingAPI.Framework.Serialisation.CrossplatformConverters
+namespace StardewModdingAPI.Framework.Serialisation
{
/// <summary>Handles deserialisation of <see cref="PointConverter"/> for crossplatform compatibility.</summary>
/// <remarks>
diff --git a/src/SMAPI/Framework/Serialisation/CrossplatformConverters/RectangleConverter.cs b/src/SMAPI/Framework/Serialisation/RectangleConverter.cs
index 62bc8637..4f55cc32 100644
--- a/src/SMAPI/Framework/Serialisation/CrossplatformConverters/RectangleConverter.cs
+++ b/src/SMAPI/Framework/Serialisation/RectangleConverter.cs
@@ -2,9 +2,10 @@ using System;
using System.Text.RegularExpressions;
using Microsoft.Xna.Framework;
using Newtonsoft.Json.Linq;
-using StardewModdingAPI.Framework.Exceptions;
+using StardewModdingAPI.Toolkit.Serialisation;
+using StardewModdingAPI.Toolkit.Serialisation.Converters;
-namespace StardewModdingAPI.Framework.Serialisation.CrossplatformConverters
+namespace StardewModdingAPI.Framework.Serialisation
{
/// <summary>Handles deserialisation of <see cref="Rectangle"/> for crossplatform compatibility.</summary>
/// <remarks>
diff --git a/src/SMAPI/Framework/Serialisation/SimpleReadOnlyConverter.cs b/src/SMAPI/Framework/Serialisation/SimpleReadOnlyConverter.cs
deleted file mode 100644
index 5765ad96..00000000
--- a/src/SMAPI/Framework/Serialisation/SimpleReadOnlyConverter.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using StardewModdingAPI.Framework.Exceptions;
-
-namespace StardewModdingAPI.Framework.Serialisation
-{
- /// <summary>The base implementation for simplified converters which deserialise <typeparamref name="T"/> without overriding serialisation.</summary>
- /// <typeparam name="T">The type to deserialise.</typeparam>
- internal abstract class SimpleReadOnlyConverter<T> : JsonConverter
- {
- /*********
- ** Accessors
- *********/
- /// <summary>Whether this converter can write JSON.</summary>
- public override bool CanWrite => false;
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Get whether this instance can convert the specified object type.</summary>
- /// <param name="objectType">The object type.</param>
- public override bool CanConvert(Type objectType)
- {
- return objectType == typeof(T);
- }
-
- /// <summary>Writes the JSON representation of the object.</summary>
- /// <param name="writer">The JSON writer.</param>
- /// <param name="value">The value.</param>
- /// <param name="serializer">The calling serializer.</param>
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
- {
- throw new InvalidOperationException("This converter does not write JSON.");
- }
-
- /// <summary>Reads the JSON representation of the object.</summary>
- /// <param name="reader">The JSON reader.</param>
- /// <param name="objectType">The object type.</param>
- /// <param name="existingValue">The object being read.</param>
- /// <param name="serializer">The calling serializer.</param>
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
- {
- string path = reader.Path;
- switch (reader.TokenType)
- {
- case JsonToken.StartObject:
- return this.ReadObject(JObject.Load(reader), path);
- case JsonToken.String:
- return this.ReadString(JToken.Load(reader).Value<string>(), path);
- default:
- throw new SParseException($"Can't parse {typeof(T).Name} from {reader.TokenType} node (path: {reader.Path}).");
- }
- }
-
-
- /*********
- ** Protected methods
- *********/
- /// <summary>Read a JSON object.</summary>
- /// <param name="obj">The JSON object to read.</param>
- /// <param name="path">The path to the current JSON node.</param>
- protected virtual T ReadObject(JObject obj, string path)
- {
- throw new SParseException($"Can't parse {typeof(T).Name} from object node (path: {path}).");
- }
-
- /// <summary>Read a JSON string.</summary>
- /// <param name="str">The JSON string value.</param>
- /// <param name="path">The path to the current JSON node.</param>
- protected virtual T ReadString(string str, string path)
- {
- throw new SParseException($"Can't parse {typeof(T).Name} from string node (path: {path}).");
- }
- }
-}
diff --git a/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestContentPackForConverter.cs b/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestContentPackForConverter.cs
deleted file mode 100644
index af7558f6..00000000
--- a/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestContentPackForConverter.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System;
-using Newtonsoft.Json;
-using StardewModdingAPI.Framework.Models;
-
-namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
-{
- /// <summary>Handles deserialisation of <see cref="IManifestContentPackFor"/> arrays.</summary>
- internal class ManifestContentPackForConverter : JsonConverter
- {
- /*********
- ** Accessors
- *********/
- /// <summary>Whether this converter can write JSON.</summary>
- public override bool CanWrite => false;
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Get whether this instance can convert the specified object type.</summary>
- /// <param name="objectType">The object type.</param>
- public override bool CanConvert(Type objectType)
- {
- return objectType == typeof(IManifestContentPackFor[]);
- }
-
-
- /*********
- ** Protected methods
- *********/
- /// <summary>Read the JSON representation of the object.</summary>
- /// <param name="reader">The JSON reader.</param>
- /// <param name="objectType">The object type.</param>
- /// <param name="existingValue">The object being read.</param>
- /// <param name="serializer">The calling serializer.</param>
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
- {
- return serializer.Deserialize<ManifestContentPackFor>(reader);
- }
-
- /// <summary>Writes the JSON representation of the object.</summary>
- /// <param name="writer">The JSON writer.</param>
- /// <param name="value">The value.</param>
- /// <param name="serializer">The calling serializer.</param>
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
- {
- throw new InvalidOperationException("This converter does not write JSON.");
- }
- }
-}
diff --git a/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestDependencyArrayConverter.cs b/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestDependencyArrayConverter.cs
deleted file mode 100644
index 4150d5fb..00000000
--- a/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestDependencyArrayConverter.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using StardewModdingAPI.Framework.Models;
-
-namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
-{
- /// <summary>Handles deserialisation of <see cref="IManifestDependency"/> arrays.</summary>
- internal class ManifestDependencyArrayConverter : JsonConverter
- {
- /*********
- ** Accessors
- *********/
- /// <summary>Whether this converter can write JSON.</summary>
- public override bool CanWrite => false;
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Get whether this instance can convert the specified object type.</summary>
- /// <param name="objectType">The object type.</param>
- public override bool CanConvert(Type objectType)
- {
- return objectType == typeof(IManifestDependency[]);
- }
-
-
- /*********
- ** Protected methods
- *********/
- /// <summary>Read the JSON representation of the object.</summary>
- /// <param name="reader">The JSON reader.</param>
- /// <param name="objectType">The object type.</param>
- /// <param name="existingValue">The object being read.</param>
- /// <param name="serializer">The calling serializer.</param>
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
- {
- List<IManifestDependency> result = new List<IManifestDependency>();
- foreach (JObject obj in JArray.Load(reader).Children<JObject>())
- {
- string uniqueID = obj.ValueIgnoreCase<string>(nameof(IManifestDependency.UniqueID));
- string minVersion = obj.ValueIgnoreCase<string>(nameof(IManifestDependency.MinimumVersion));
- bool required = obj.ValueIgnoreCase<bool?>(nameof(IManifestDependency.IsRequired)) ?? true;
- result.Add(new ManifestDependency(uniqueID, minVersion, required));
- }
- return result.ToArray();
- }
-
- /// <summary>Writes the JSON representation of the object.</summary>
- /// <param name="writer">The JSON writer.</param>
- /// <param name="value">The value.</param>
- /// <param name="serializer">The calling serializer.</param>
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
- {
- throw new InvalidOperationException("This converter does not write JSON.");
- }
- }
-}
diff --git a/src/SMAPI/Framework/Serialisation/SmapiConverters/SemanticVersionConverter.cs b/src/SMAPI/Framework/Serialisation/SmapiConverters/SemanticVersionConverter.cs
deleted file mode 100644
index 7ee7e29b..00000000
--- a/src/SMAPI/Framework/Serialisation/SmapiConverters/SemanticVersionConverter.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using Newtonsoft.Json.Linq;
-using StardewModdingAPI.Framework.Exceptions;
-
-namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
-{
- /// <summary>Handles deserialisation of <see cref="SemanticVersion"/>.</summary>
- internal class SemanticVersionConverter : SimpleReadOnlyConverter<ISemanticVersion>
- {
- /*********
- ** Protected methods
- *********/
- /// <summary>Read a JSON object.</summary>
- /// <param name="obj">The JSON object to read.</param>
- /// <param name="path">The path to the current JSON node.</param>
- protected override ISemanticVersion ReadObject(JObject obj, string path)
- {
- int major = obj.ValueIgnoreCase<int>(nameof(ISemanticVersion.MajorVersion));
- int minor = obj.ValueIgnoreCase<int>(nameof(ISemanticVersion.MinorVersion));
- int patch = obj.ValueIgnoreCase<int>(nameof(ISemanticVersion.PatchVersion));
- string build = obj.ValueIgnoreCase<string>(nameof(ISemanticVersion.Build));
- return new LegacyManifestVersion(major, minor, patch, build);
- }
-
- /// <summary>Read a JSON string.</summary>
- /// <param name="str">The JSON string value.</param>
- /// <param name="path">The path to the current JSON node.</param>
- protected override ISemanticVersion ReadString(string str, string path)
- {
- if (string.IsNullOrWhiteSpace(str))
- return null;
- if (!SemanticVersion.TryParse(str, out ISemanticVersion version))
- throw new SParseException($"Can't parse semantic version from invalid value '{str}', should be formatted like 1.2, 1.2.30, or 1.2.30-beta (path: {path}).");
- return version;
- }
- }
-}
diff --git a/src/SMAPI/Framework/Serialisation/SmapiConverters/StringEnumConverter.cs b/src/SMAPI/Framework/Serialisation/SmapiConverters/StringEnumConverter.cs
deleted file mode 100644
index c88ac834..00000000
--- a/src/SMAPI/Framework/Serialisation/SmapiConverters/StringEnumConverter.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-using Newtonsoft.Json.Converters;
-
-namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
-{
- /// <summary>A variant of <see cref="StringEnumConverter"/> which only converts a specified enum.</summary>
- /// <typeparam name="T">The enum type.</typeparam>
- internal class StringEnumConverter<T> : StringEnumConverter
- {
- /*********
- ** Public methods
- *********/
- /// <summary>Get whether this instance can convert the specified object type.</summary>
- /// <param name="type">The object type.</param>
- public override bool CanConvert(Type type)
- {
- return
- base.CanConvert(type)
- && (Nullable.GetUnderlyingType(type) ?? type) == typeof(T);
- }
- }
-}