summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/SMAPI.Tests/Core/ModResolverTests.cs84
-rw-r--r--src/SMAPI.Tests/Utilities/SemanticVersionTests.cs1
-rw-r--r--src/SMAPI/Framework/ContentPack.cs2
-rw-r--r--src/SMAPI/Framework/InternalExtensions.cs16
-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/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/IManifest.cs2
-rw-r--r--src/SMAPI/Program.cs18
-rw-r--r--src/SMAPI/StardewModdingAPI.csproj20
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/Converters/ManifestContentPackForConverter.cs (renamed from src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestContentPackForConverter.cs)10
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/Converters/ManifestDependencyArrayConverter.cs (renamed from src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestDependencyArrayConverter.cs)16
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs (renamed from src/SMAPI/Framework/Serialisation/SmapiConverters/SemanticVersionConverter.cs)20
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/Converters/SimpleReadOnlyConverter.cs (renamed from src/SMAPI/Framework/Serialisation/SimpleReadOnlyConverter.cs)3
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/Converters/StringEnumConverter.cs (renamed from src/SMAPI/Framework/Serialisation/SmapiConverters/StringEnumConverter.cs)2
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/InternalExtensions.cs21
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/JsonHelper.cs (renamed from src/SMAPI/Framework/Serialisation/JsonHelper.cs)26
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/Models/LegacyManifestVersion.cs (renamed from src/SMAPI/Framework/LegacyManifestVersion.cs)6
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/Models/Manifest.cs49
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/Models/ManifestContentPackFor.cs15
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/Models/ManifestDependency.cs35
-rw-r--r--src/StardewModdingAPI.Toolkit/Serialisation/SParseException.cs (renamed from src/SMAPI/Framework/Exceptions/SParseException.cs)4
27 files changed, 343 insertions, 189 deletions
diff --git a/src/SMAPI.Tests/Core/ModResolverTests.cs b/src/SMAPI.Tests/Core/ModResolverTests.cs
index d63eb1a2..2fbeb9b6 100644
--- a/src/SMAPI.Tests/Core/ModResolverTests.cs
+++ b/src/SMAPI.Tests/Core/ModResolverTests.cs
@@ -9,7 +9,7 @@ using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.ModData;
using StardewModdingAPI.Framework.Models;
using StardewModdingAPI.Framework.ModLoading;
-using StardewModdingAPI.Framework.Serialisation;
+using StardewModdingAPI.Toolkit.Serialisation;
namespace StardewModdingAPI.Tests.Core
{
@@ -93,8 +93,8 @@ namespace StardewModdingAPI.Tests.Core
Assert.IsNotNull(mod, "The loaded manifest shouldn't be null.");
Assert.AreEqual(null, mod.DataRecord, "The data record should be null since we didn't provide one.");
Assert.AreEqual(modFolder, mod.DirectoryPath, "The directory path doesn't match.");
- Assert.AreEqual(ModMetadataStatus.Found, mod.Status, "The status doesn't match.");
Assert.AreEqual(null, mod.Error, "The error should be null since parsing should have succeeded.");
+ Assert.AreEqual(ModMetadataStatus.Found, mod.Status, "The status doesn't match.");
Assert.AreEqual(original[nameof(IManifest.Name)], mod.DisplayName, "The display name should use the manifest name.");
Assert.AreEqual(original[nameof(IManifest.Name)], mod.Manifest.Name, "The manifest's name doesn't match.");
@@ -160,7 +160,7 @@ namespace StardewModdingAPI.Tests.Core
{
// arrange
Mock<IModMetadata> mock = this.GetMetadata("Mod A", new string[0], allowStatusChange: true);
- mock.Setup(p => p.Manifest).Returns(this.GetManifest(m => m.MinimumApiVersion = new SemanticVersion("1.1")));
+ mock.Setup(p => p.Manifest).Returns(this.GetManifest(minimumApiVersion: "1.1"));
this.SetupMetadataForValidation(mock);
// act
@@ -174,7 +174,7 @@ namespace StardewModdingAPI.Tests.Core
public void ValidateManifests_MissingEntryDLL_Fails()
{
// arrange
- Mock<IModMetadata> mock = this.GetMetadata(this.GetManifest("Mod A", "1.0", manifest => manifest.EntryDll = "Missing.dll"), allowStatusChange: true);
+ Mock<IModMetadata> mock = this.GetMetadata(this.GetManifest(id: "Mod A", version: "1.0", entryDll: "Missing.dll"), allowStatusChange: true);
this.SetupMetadataForValidation(mock);
// act
@@ -189,7 +189,7 @@ namespace StardewModdingAPI.Tests.Core
{
// arrange
Mock<IModMetadata> modA = this.GetMetadata("Mod A", new string[0], allowStatusChange: true);
- Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest("Mod A", "1.0", manifest => manifest.Name = "Mod B"), allowStatusChange: true);
+ Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest(id: "Mod A", name: "Mod B", version: "1.0"), allowStatusChange: true);
Mock<IModMetadata> modC = this.GetMetadata("Mod C", new string[0], allowStatusChange: false);
foreach (Mock<IModMetadata> mod in new[] { modA, modB, modC })
this.SetupMetadataForValidation(mod);
@@ -398,8 +398,8 @@ namespace StardewModdingAPI.Tests.Core
{
// arrange
// A 1.0 ◀── B (need A 1.1)
- Mock<IModMetadata> modA = this.GetMetadata(this.GetManifest("Mod A", "1.0"));
- Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest("Mod B", "1.0", new ManifestDependency("Mod A", "1.1")), allowStatusChange: true);
+ Mock<IModMetadata> modA = this.GetMetadata(this.GetManifest(id: "Mod A", version: "1.0"));
+ Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest(id: "Mod B", version: "1.0", dependencies: new IManifestDependency[] { new ManifestDependency("Mod A", "1.1") }), allowStatusChange: true);
// act
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modA.Object, modB.Object }, new ModDatabase()).ToArray();
@@ -414,8 +414,8 @@ namespace StardewModdingAPI.Tests.Core
{
// arrange
// A 1.0 ◀── B (need A 1.0-beta)
- Mock<IModMetadata> modA = this.GetMetadata(this.GetManifest("Mod A", "1.0"));
- Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest("Mod B", "1.0", new ManifestDependency("Mod A", "1.0-beta")), allowStatusChange: false);
+ Mock<IModMetadata> modA = this.GetMetadata(this.GetManifest(id: "Mod A", version: "1.0"));
+ Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest(id: "Mod B", version: "1.0", dependencies: new IManifestDependency[] { new ManifestDependency("Mod A", "1.0-beta") }), allowStatusChange: false);
// act
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modA.Object, modB.Object }, new ModDatabase()).ToArray();
@@ -431,8 +431,8 @@ namespace StardewModdingAPI.Tests.Core
{
// arrange
// A ◀── B
- Mock<IModMetadata> modA = this.GetMetadata(this.GetManifest("Mod A", "1.0"));
- Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest("Mod B", "1.0", new ManifestDependency("Mod A", "1.0", required: false)), allowStatusChange: false);
+ Mock<IModMetadata> modA = this.GetMetadata(this.GetManifest(id: "Mod A", version: "1.0"));
+ Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest(id: "Mod B", version: "1.0", dependencies: new IManifestDependency[] { new ManifestDependency("Mod A", "1.0", required: false) }), allowStatusChange: false);
// act
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modB.Object, modA.Object }, new ModDatabase()).ToArray();
@@ -448,7 +448,7 @@ namespace StardewModdingAPI.Tests.Core
{
// arrange
// A ◀── B where A doesn't exist
- Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest("Mod B", "1.0", new ManifestDependency("Mod A", "1.0", required: false)), allowStatusChange: false);
+ Mock<IModMetadata> modB = this.GetMetadata(this.GetManifest(id: "Mod B", version: "1.0", dependencies: new IManifestDependency[] { new ManifestDependency("Mod A", "1.0", required: false) }), allowStatusChange: false);
// act
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modB.Object }, new ModDatabase()).ToArray();
@@ -463,46 +463,26 @@ namespace StardewModdingAPI.Tests.Core
** Private methods
*********/
/// <summary>Get a randomised basic manifest.</summary>
- /// <param name="adjust">Adjust the generated manifest.</param>
- private Manifest GetManifest(Action<Manifest> adjust = null)
- {
- Manifest manifest = new Manifest
- {
- Name = Sample.String(),
- Author = Sample.String(),
- Version = new SemanticVersion(Sample.Int(), Sample.Int(), Sample.Int(), Sample.String()),
- Description = Sample.String(),
- UniqueID = $"{Sample.String()}.{Sample.String()}",
- EntryDll = $"{Sample.String()}.dll"
- };
- adjust?.Invoke(manifest);
- return manifest;
- }
-
- /// <summary>Get a randomised basic manifest.</summary>
- /// <param name="uniqueID">The mod's name and unique ID.</param>
- /// <param name="version">The mod version.</param>
- /// <param name="adjust">Adjust the generated manifest.</param>
- /// <param name="dependencies">The dependencies this mod requires.</param>
- private IManifest GetManifest(string uniqueID, string version, Action<Manifest> adjust, params IManifestDependency[] dependencies)
- {
- return this.GetManifest(manifest =>
- {
- manifest.Name = uniqueID;
- manifest.UniqueID = uniqueID;
- manifest.Version = new SemanticVersion(version);
- manifest.Dependencies = dependencies;
- adjust?.Invoke(manifest);
- });
- }
-
- /// <summary>Get a randomised basic manifest.</summary>
- /// <param name="uniqueID">The mod's name and unique ID.</param>
- /// <param name="version">The mod version.</param>
- /// <param name="dependencies">The dependencies this mod requires.</param>
- private IManifest GetManifest(string uniqueID, string version, params IManifestDependency[] dependencies)
+ /// <param name="id">The <see cref="IManifest.UniqueID"/> value, or <c>null</c> for a generated value.</param>
+ /// <param name="name">The <see cref="IManifest.Name"/> value, or <c>null</c> for a generated value.</param>
+ /// <param name="version">The <see cref="IManifest.Version"/> value, or <c>null</c> for a generated value.</param>
+ /// <param name="entryDll">The <see cref="IManifest.EntryDll"/> value, or <c>null</c> for a generated value.</param>
+ /// <param name="contentPackForID">The <see cref="IManifest.ContentPackFor"/> value.</param>
+ /// <param name="minimumApiVersion">The <see cref="IManifest.MinimumApiVersion"/> value.</param>
+ /// <param name="dependencies">The <see cref="IManifest.Dependencies"/> value.</param>
+ private Manifest GetManifest(string id = null, string name = null, string version = null, string entryDll = null, string contentPackForID = null, string minimumApiVersion = null, IManifestDependency[] dependencies = null)
{
- return this.GetManifest(uniqueID, version, null, dependencies);
+ return new Manifest(
+ uniqueID: id ?? $"{Sample.String()}.{Sample.String()}",
+ name: name ?? id ?? Sample.String(),
+ author: Sample.String(),
+ description: Sample.String(),
+ version: version != null ? new SemanticVersion(version) : new SemanticVersion(Sample.Int(), Sample.Int(), Sample.Int(), Sample.String()),
+ entryDll: entryDll ?? $"{Sample.String()}.dll",
+ contentPackFor: contentPackForID != null ? new ManifestContentPackFor(contentPackForID) : null,
+ minimumApiVersion: minimumApiVersion != null ? new SemanticVersion(minimumApiVersion) : null,
+ dependencies: dependencies
+ );
}
/// <summary>Get a randomised basic manifest.</summary>
@@ -518,7 +498,7 @@ namespace StardewModdingAPI.Tests.Core
/// <param name="allowStatusChange">Whether the code being tested is allowed to change the mod status.</param>
private Mock<IModMetadata> GetMetadata(string uniqueID, string[] dependencies, bool allowStatusChange = false)
{
- IManifest manifest = this.GetManifest(uniqueID, "1.0", dependencies?.Select(dependencyID => (IManifestDependency)new ManifestDependency(dependencyID, null)).ToArray());
+ IManifest manifest = this.GetManifest(id: uniqueID, version: "1.0", dependencies: dependencies?.Select(dependencyID => (IManifestDependency)new ManifestDependency(dependencyID, null)).ToArray());
return this.GetMetadata(manifest, allowStatusChange);
}
diff --git a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs
index f1a72012..b797393b 100644
--- a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs
+++ b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs
@@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;
using NUnit.Framework;
using StardewModdingAPI.Framework;
+using StardewModdingAPI.Toolkit.Serialisation.Models;
namespace StardewModdingAPI.Tests.Utilities
{
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/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/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/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/IManifest.cs b/src/SMAPI/IManifest.cs
index 183ac105..6c07d374 100644
--- a/src/SMAPI/IManifest.cs
+++ b/src/SMAPI/IManifest.cs
@@ -36,7 +36,7 @@ namespace StardewModdingAPI
IManifestDependency[] Dependencies { get; }
/// <summary>The namespaced mod IDs to query for updates (like <c>Nexus:541</c>).</summary>
- string[] UpdateKeys { get; set; }
+ string[] UpdateKeys { get; }
/// <summary>Any manifest fields which didn't match a valid field.</summary>
IDictionary<string, object> ExtraFields { get; }
diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs
index 5c5137ef..e55a96b2 100644
--- a/src/SMAPI/Program.cs
+++ b/src/SMAPI/Program.cs
@@ -10,6 +10,7 @@ using System.Runtime.ExceptionServices;
using System.Security;
using System.Text.RegularExpressions;
using System.Threading;
+using Microsoft.Xna.Framework.Input;
#if SMAPI_FOR_WINDOWS
using System.Windows.Forms;
#endif
@@ -27,8 +28,11 @@ using StardewModdingAPI.Framework.Reflection;
using StardewModdingAPI.Framework.Serialisation;
using StardewModdingAPI.Internal;
using StardewModdingAPI.Toolkit.Framework.Clients.WebApi;
+using StardewModdingAPI.Toolkit.Serialisation;
+using StardewModdingAPI.Toolkit.Serialisation.Converters;
using StardewModdingAPI.Toolkit.Utilities;
using StardewValley;
+using Keys = System.Windows.Forms.Keys;
using Monitor = StardewModdingAPI.Framework.Monitor;
using SObject = StardewValley.Object;
using ThreadState = System.Threading.ThreadState;
@@ -148,6 +152,18 @@ namespace StardewModdingAPI
};
this.EventManager = new EventManager(this.Monitor, this.ModRegistry);
+ // init JSON parser
+ JsonConverter[] converters = {
+ new StringEnumConverter<Buttons>(),
+ new StringEnumConverter<Keys>(),
+ new StringEnumConverter<SButton>(),
+ new ColorConverter(),
+ new PointConverter(),
+ new RectangleConverter()
+ };
+ foreach (JsonConverter converter in converters)
+ this.JsonHelper.JsonSettings.Converters.Add(converter);
+
// hook up events
ContentEvents.Init(this.EventManager);
ControlEvents.Init(this.EventManager);
@@ -1093,7 +1109,7 @@ namespace StardewModdingAPI
/// <param name="mods">The mods for which to reload translations.</param>
private void ReloadTranslations(IEnumerable<IModMetadata> mods)
{
- JsonHelper jsonHelper = new JsonHelper();
+ JsonHelper jsonHelper = this.JsonHelper;
foreach (IModMetadata metadata in mods)
{
if (metadata.IsContentPack)
diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj
index a5ccc62d..3c953ec5 100644
--- a/src/SMAPI/StardewModdingAPI.csproj
+++ b/src/SMAPI/StardewModdingAPI.csproj
@@ -103,6 +103,9 @@
<Compile Include="Framework\ContentManagers\GameContentManager.cs" />
<Compile Include="Framework\ContentManagers\IContentManager.cs" />
<Compile Include="Framework\ContentManagers\ModContentManager.cs" />
+ <Compile Include="Framework\Serialisation\ColorConverter.cs" />
+ <Compile Include="Framework\Serialisation\PointConverter.cs" />
+ <Compile Include="Framework\Serialisation\RectangleConverter.cs" />
<Compile Include="Framework\Events\ModEventsBase.cs" />
<Compile Include="Framework\Events\EventManager.cs" />
<Compile Include="Events\IModEvents.cs" />
@@ -114,16 +117,17 @@
<Compile Include="Framework\Events\ModEvents.cs" />
<Compile Include="Framework\Events\ModInputEvents.cs" />
<Compile Include="Framework\Input\GamePadStateBuilder.cs" />
+ <Compile Include="Framework\Models\Manifest.cs" />
+ <Compile Include="Framework\Models\ManifestContentPackFor.cs" />
+ <Compile Include="Framework\Models\ManifestDependency.cs" />
<Compile Include="Framework\ModHelpers\InputHelper.cs" />
<Compile Include="IInputHelper.cs" />
<Compile Include="Framework\Input\SInputState.cs" />
<Compile Include="Framework\Input\InputStatus.cs" />
- <Compile Include="Framework\LegacyManifestVersion.cs" />
<Compile Include="Framework\ModData\ModDatabase.cs" />
<Compile Include="Framework\ModData\ModDataField.cs" />
<Compile Include="Framework\ModData\ModDataFieldKey.cs" />
<Compile Include="Framework\ModData\ParsedModDataRecord.cs" />
- <Compile Include="Framework\Models\ManifestContentPackFor.cs" />
<Compile Include="Framework\Models\SMetadata.cs" />
<Compile Include="Framework\ModHelpers\MultiplayerHelper.cs" />
<Compile Include="Framework\ModLoading\Finders\EventFinder.cs" />
@@ -151,13 +155,6 @@
<Compile Include="Framework\Reflection\InterfaceProxyBuilder.cs" />
<Compile Include="Framework\Reflection\InterfaceProxyFactory.cs" />
<Compile Include="Framework\RewriteFacades\SpriteBatchMethods.cs" />
- <Compile Include="Framework\Serialisation\SmapiConverters\ManifestContentPackForConverter.cs" />
- <Compile Include="Framework\Serialisation\SmapiConverters\ManifestDependencyArrayConverter.cs" />
- <Compile Include="Framework\Serialisation\SmapiConverters\SemanticVersionConverter.cs" />
- <Compile Include="Framework\Serialisation\SimpleReadOnlyConverter.cs" />
- <Compile Include="Framework\Serialisation\CrossplatformConverters\RectangleConverter.cs" />
- <Compile Include="Framework\Serialisation\CrossplatformConverters\ColorConverter.cs" />
- <Compile Include="Framework\Serialisation\CrossplatformConverters\PointConverter.cs" />
<Compile Include="Framework\SMultiplayer.cs" />
<Compile Include="Framework\StateTracking\Comparers\EquatableComparer.cs" />
<Compile Include="Framework\StateTracking\Comparers\ObjectReferenceComparer.cs" />
@@ -235,16 +232,12 @@
<Compile Include="Context.cs" />
<Compile Include="Framework\Logging\ConsoleInterceptionManager.cs" />
<Compile Include="Framework\Logging\InterceptingTextWriter.cs" />
- <Compile Include="Framework\Models\ManifestDependency.cs" />
<Compile Include="Framework\ModData\ModStatus.cs" />
<Compile Include="Framework\Models\SConfig.cs" />
<Compile Include="Framework\ModLoading\ModMetadata.cs" />
<Compile Include="Framework\Reflection\ReflectedProperty.cs" />
<Compile Include="Framework\RequestExitDelegate.cs" />
<Compile Include="Framework\ContentCoordinator.cs" />
- <Compile Include="Framework\Exceptions\SParseException.cs" />
- <Compile Include="Framework\Serialisation\JsonHelper.cs" />
- <Compile Include="Framework\Serialisation\SmapiConverters\StringEnumConverter.cs" />
<Compile Include="IAssetEditor.cs" />
<Compile Include="IAssetInfo.cs" />
<Compile Include="IAssetLoader.cs" />
@@ -283,7 +276,6 @@
<Compile Include="Events\ChangeType.cs" />
<Compile Include="Events\ItemStackChange.cs" />
<Compile Include="Framework\Monitor.cs" />
- <Compile Include="Framework\Models\Manifest.cs" />
<Compile Include="Metadata\InstructionMetadata.cs" />
<Compile Include="Mod.cs" />
<Compile Include="PatchMode.cs" />
diff --git a/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestContentPackForConverter.cs b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/ManifestContentPackForConverter.cs
index af7558f6..232c22a7 100644
--- a/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestContentPackForConverter.cs
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/ManifestContentPackForConverter.cs
@@ -1,11 +1,11 @@
using System;
using Newtonsoft.Json;
-using StardewModdingAPI.Framework.Models;
+using StardewModdingAPI.Toolkit.Serialisation.Models;
-namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
+namespace StardewModdingAPI.Toolkit.Serialisation.Converters
{
- /// <summary>Handles deserialisation of <see cref="IManifestContentPackFor"/> arrays.</summary>
- internal class ManifestContentPackForConverter : JsonConverter
+ /// <summary>Handles deserialisation of <see cref="ManifestContentPackFor"/> arrays.</summary>
+ public class ManifestContentPackForConverter : JsonConverter
{
/*********
** Accessors
@@ -21,7 +21,7 @@ namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
/// <param name="objectType">The object type.</param>
public override bool CanConvert(Type objectType)
{
- return objectType == typeof(IManifestContentPackFor[]);
+ return objectType == typeof(ManifestContentPackFor[]);
}
diff --git a/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestDependencyArrayConverter.cs b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/ManifestDependencyArrayConverter.cs
index 4150d5fb..0a304ee3 100644
--- a/src/SMAPI/Framework/Serialisation/SmapiConverters/ManifestDependencyArrayConverter.cs
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/ManifestDependencyArrayConverter.cs
@@ -2,11 +2,11 @@ using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
-using StardewModdingAPI.Framework.Models;
+using StardewModdingAPI.Toolkit.Serialisation.Models;
-namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
+namespace StardewModdingAPI.Toolkit.Serialisation.Converters
{
- /// <summary>Handles deserialisation of <see cref="IManifestDependency"/> arrays.</summary>
+ /// <summary>Handles deserialisation of <see cref="ManifestDependency"/> arrays.</summary>
internal class ManifestDependencyArrayConverter : JsonConverter
{
/*********
@@ -23,7 +23,7 @@ namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
/// <param name="objectType">The object type.</param>
public override bool CanConvert(Type objectType)
{
- return objectType == typeof(IManifestDependency[]);
+ return objectType == typeof(ManifestDependency[]);
}
@@ -37,12 +37,12 @@ namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
/// <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>();
+ List<ManifestDependency> result = new List<ManifestDependency>();
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;
+ string uniqueID = obj.ValueIgnoreCase<string>(nameof(ManifestDependency.UniqueID));
+ string minVersion = obj.ValueIgnoreCase<string>(nameof(ManifestDependency.MinimumVersion));
+ bool required = obj.ValueIgnoreCase<bool?>(nameof(ManifestDependency.IsRequired)) ?? true;
result.Add(new ManifestDependency(uniqueID, minVersion, required));
}
return result.ToArray();
diff --git a/src/SMAPI/Framework/Serialisation/SmapiConverters/SemanticVersionConverter.cs b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs
index 7ee7e29b..2075d27e 100644
--- a/src/SMAPI/Framework/Serialisation/SmapiConverters/SemanticVersionConverter.cs
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs
@@ -1,10 +1,10 @@
using Newtonsoft.Json.Linq;
-using StardewModdingAPI.Framework.Exceptions;
+using StardewModdingAPI.Toolkit.Serialisation.Models;
-namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
+namespace StardewModdingAPI.Toolkit.Serialisation.Converters
{
/// <summary>Handles deserialisation of <see cref="SemanticVersion"/>.</summary>
- internal class SemanticVersionConverter : SimpleReadOnlyConverter<ISemanticVersion>
+ internal class SemanticVersionConverter : SimpleReadOnlyConverter<SemanticVersion>
{
/*********
** Protected methods
@@ -12,25 +12,25 @@ namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
/// <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)
+ protected override SemanticVersion 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));
+ int major = obj.ValueIgnoreCase<int>("MajorVersion");
+ int minor = obj.ValueIgnoreCase<int>("MinorVersion");
+ int patch = obj.ValueIgnoreCase<int>("PatchVersion");
+ string build = obj.ValueIgnoreCase<string>("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)
+ protected override SemanticVersion 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;
+ return (SemanticVersion)version;
}
}
}
diff --git a/src/SMAPI/Framework/Serialisation/SimpleReadOnlyConverter.cs b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/SimpleReadOnlyConverter.cs
index 5765ad96..5e0b0f4a 100644
--- a/src/SMAPI/Framework/Serialisation/SimpleReadOnlyConverter.cs
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/SimpleReadOnlyConverter.cs
@@ -1,9 +1,8 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
-using StardewModdingAPI.Framework.Exceptions;
-namespace StardewModdingAPI.Framework.Serialisation
+namespace StardewModdingAPI.Toolkit.Serialisation.Converters
{
/// <summary>The base implementation for simplified converters which deserialise <typeparamref name="T"/> without overriding serialisation.</summary>
/// <typeparam name="T">The type to deserialise.</typeparam>
diff --git a/src/SMAPI/Framework/Serialisation/SmapiConverters/StringEnumConverter.cs b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/StringEnumConverter.cs
index c88ac834..13e6e3a1 100644
--- a/src/SMAPI/Framework/Serialisation/SmapiConverters/StringEnumConverter.cs
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/Converters/StringEnumConverter.cs
@@ -1,7 +1,7 @@
using System;
using Newtonsoft.Json.Converters;
-namespace StardewModdingAPI.Framework.Serialisation.SmapiConverters
+namespace StardewModdingAPI.Toolkit.Serialisation.Converters
{
/// <summary>A variant of <see cref="StringEnumConverter"/> which only converts a specified enum.</summary>
/// <typeparam name="T">The enum type.</typeparam>
diff --git a/src/StardewModdingAPI.Toolkit/Serialisation/InternalExtensions.cs b/src/StardewModdingAPI.Toolkit/Serialisation/InternalExtensions.cs
new file mode 100644
index 00000000..12b2c933
--- /dev/null
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/InternalExtensions.cs
@@ -0,0 +1,21 @@
+using System;
+using Newtonsoft.Json.Linq;
+
+namespace StardewModdingAPI.Toolkit.Serialisation
+{
+ /// <summary>Provides extension methods for parsing JSON.</summary>
+ public static class JsonExtensions
+ {
+ /// <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/Serialisation/JsonHelper.cs b/src/StardewModdingAPI.Toolkit/Serialisation/JsonHelper.cs
index 6cba343e..00f334ad 100644
--- a/src/SMAPI/Framework/Serialisation/JsonHelper.cs
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/JsonHelper.cs
@@ -1,39 +1,23 @@
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;
+using StardewModdingAPI.Toolkit.Serialisation.Converters;
-namespace StardewModdingAPI.Framework.Serialisation
+namespace StardewModdingAPI.Toolkit.Serialisation
{
/// <summary>Encapsulates SMAPI's JSON file parsing.</summary>
- internal class JsonHelper
+ public class JsonHelper
{
/*********
** Accessors
*********/
/// <summary>The JSON settings to use when serialising and deserialising files.</summary>
- private readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings
+ public JsonSerializerSettings JsonSettings { get; } = 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()
- }
+ Converters = new List<JsonConverter> { new SemanticVersionConverter() }
};
diff --git a/src/SMAPI/Framework/LegacyManifestVersion.cs b/src/StardewModdingAPI.Toolkit/Serialisation/Models/LegacyManifestVersion.cs
index 454b9137..12f6755b 100644
--- a/src/SMAPI/Framework/LegacyManifestVersion.cs
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/Models/LegacyManifestVersion.cs
@@ -1,9 +1,9 @@
using Newtonsoft.Json;
-namespace StardewModdingAPI.Framework
+namespace StardewModdingAPI.Toolkit.Serialisation.Models
{
- /// <summary>An implementation of <see cref="ISemanticVersion"/> that hamdles the legacy <see cref="IManifest"/> version format.</summary>
- internal class LegacyManifestVersion : SemanticVersion
+ /// <summary>An implementation of <see cref="ISemanticVersion"/> that hamdles the legacy <see cref="Manifest"/> version format.</summary>
+ public class LegacyManifestVersion : SemanticVersion
{
/*********
** Public methods
diff --git a/src/StardewModdingAPI.Toolkit/Serialisation/Models/Manifest.cs b/src/StardewModdingAPI.Toolkit/Serialisation/Models/Manifest.cs
new file mode 100644
index 00000000..68987dd1
--- /dev/null
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/Models/Manifest.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using StardewModdingAPI.Toolkit.Serialisation.Converters;
+
+namespace StardewModdingAPI.Toolkit.Serialisation.Models
+{
+ /// <summary>A manifest which describes a mod for SMAPI.</summary>
+ public class Manifest
+ {
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>The mod name.</summary>
+ public string Name { get; set; }
+
+ /// <summary>A brief description of the mod.</summary>
+ public string Description { get; set; }
+
+ /// <summary>The mod author's name.</summary>
+ public string Author { get; set; }
+
+ /// <summary>The mod version.</summary>
+ public SemanticVersion Version { get; set; }
+
+ /// <summary>The minimum SMAPI version required by this mod, if any.</summary>
+ public SemanticVersion MinimumApiVersion { get; set; }
+
+ /// <summary>The name of the DLL in the directory that has the <c>Entry</c> method. Mutually exclusive with <see cref="ContentPackFor"/>.</summary>
+ public string EntryDll { get; set; }
+
+ /// <summary>The mod which will read this as a content pack. Mutually exclusive with <see cref="Manifest.EntryDll"/>.</summary>
+ [JsonConverter(typeof(ManifestContentPackForConverter))]
+ public ManifestContentPackFor ContentPackFor { get; set; }
+
+ /// <summary>The other mods that must be loaded before this mod.</summary>
+ [JsonConverter(typeof(ManifestDependencyArrayConverter))]
+ public ManifestDependency[] Dependencies { get; set; }
+
+ /// <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; }
+
+ /// <summary>Any manifest fields which didn't match a valid field.</summary>
+ [JsonExtensionData]
+ public IDictionary<string, object> ExtraFields { get; set; }
+ }
+}
diff --git a/src/StardewModdingAPI.Toolkit/Serialisation/Models/ManifestContentPackFor.cs b/src/StardewModdingAPI.Toolkit/Serialisation/Models/ManifestContentPackFor.cs
new file mode 100644
index 00000000..00546533
--- /dev/null
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/Models/ManifestContentPackFor.cs
@@ -0,0 +1,15 @@
+namespace StardewModdingAPI.Toolkit.Serialisation.Models
+{
+ /// <summary>Indicates which mod can read the content pack represented by the containing manifest.</summary>
+ public class ManifestContentPackFor
+ {
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>The unique ID of the mod which can read this content pack.</summary>
+ public string UniqueID { get; set; }
+
+ /// <summary>The minimum required version (if any).</summary>
+ public SemanticVersion MinimumVersion { get; set; }
+ }
+}
diff --git a/src/StardewModdingAPI.Toolkit/Serialisation/Models/ManifestDependency.cs b/src/StardewModdingAPI.Toolkit/Serialisation/Models/ManifestDependency.cs
new file mode 100644
index 00000000..d902f9ac
--- /dev/null
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/Models/ManifestDependency.cs
@@ -0,0 +1,35 @@
+namespace StardewModdingAPI.Toolkit.Serialisation.Models
+{
+ /// <summary>A mod dependency listed in a mod manifest.</summary>
+ public class ManifestDependency
+ {
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>The unique mod ID to require.</summary>
+ public string UniqueID { get; set; }
+
+ /// <summary>The minimum required version (if any).</summary>
+ public SemanticVersion MinimumVersion { get; set; }
+
+ /// <summary>Whether the dependency must be installed to use the mod.</summary>
+ public bool IsRequired { get; set; }
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <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>
+ public ManifestDependency(string uniqueID, string minimumVersion, bool required = true)
+ {
+ this.UniqueID = uniqueID;
+ this.MinimumVersion = !string.IsNullOrWhiteSpace(minimumVersion)
+ ? new SemanticVersion(minimumVersion)
+ : null;
+ this.IsRequired = required;
+ }
+ }
+}
diff --git a/src/SMAPI/Framework/Exceptions/SParseException.cs b/src/StardewModdingAPI.Toolkit/Serialisation/SParseException.cs
index f7133ee7..61a7b305 100644
--- a/src/SMAPI/Framework/Exceptions/SParseException.cs
+++ b/src/StardewModdingAPI.Toolkit/Serialisation/SParseException.cs
@@ -1,6 +1,6 @@
-using System;
+using System;
-namespace StardewModdingAPI.Framework.Exceptions
+namespace StardewModdingAPI.Toolkit.Serialisation
{
/// <summary>A format exception which provides a user-facing error message.</summary>
internal class SParseException : FormatException