summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/GlobalAssemblyInfo.cs4
-rw-r--r--src/StardewModdingAPI.Tests/Core/ModResolverTests.cs70
-rw-r--r--src/StardewModdingAPI/Command.cs2
-rw-r--r--src/StardewModdingAPI/Config.cs2
-rw-r--r--src/StardewModdingAPI/Constants.cs8
-rw-r--r--src/StardewModdingAPI/Events/EventArgsCommand.cs2
-rw-r--r--src/StardewModdingAPI/Events/EventArgsFarmerChanged.cs2
-rw-r--r--src/StardewModdingAPI/Events/EventArgsInput.cs2
-rw-r--r--src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs2
-rw-r--r--src/StardewModdingAPI/Events/EventArgsNewDay.cs2
-rw-r--r--src/StardewModdingAPI/Events/EventArgsStringChanged.cs2
-rw-r--r--src/StardewModdingAPI/Events/GameEvents.cs20
-rw-r--r--src/StardewModdingAPI/Events/InputEvents.cs2
-rw-r--r--src/StardewModdingAPI/Events/PlayerEvents.cs6
-rw-r--r--src/StardewModdingAPI/Events/TimeEvents.cs8
-rw-r--r--src/StardewModdingAPI/Framework/CursorPosition.cs2
-rw-r--r--src/StardewModdingAPI/Framework/DeprecationManager.cs2
-rw-r--r--src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs29
-rw-r--r--src/StardewModdingAPI/Framework/ModRegistry.cs14
-rw-r--r--src/StardewModdingAPI/Framework/Models/Manifest.cs2
-rw-r--r--src/StardewModdingAPI/Framework/Models/ManifestDependency.cs6
-rw-r--r--src/StardewModdingAPI/Framework/Monitor.cs8
-rw-r--r--src/StardewModdingAPI/Framework/SGame.cs22
-rw-r--r--src/StardewModdingAPI/Framework/Serialisation/ManifestFieldConverter.cs6
-rw-r--r--src/StardewModdingAPI/ICursorPosition.cs2
-rw-r--r--src/StardewModdingAPI/IManifestDependency.cs2
-rw-r--r--src/StardewModdingAPI/Log.cs2
-rw-r--r--src/StardewModdingAPI/Mod.cs8
-rw-r--r--src/StardewModdingAPI/Program.cs60
-rw-r--r--src/StardewModdingAPI/Utilities/SButton.cs18
-rw-r--r--src/TrainerMod/TrainerMod.csproj2
-rw-r--r--src/TrainerMod/manifest.json2
-rw-r--r--src/crossplatform.targets3
33 files changed, 196 insertions, 128 deletions
diff --git a/src/GlobalAssemblyInfo.cs b/src/GlobalAssemblyInfo.cs
index d2f2597f..d9a01635 100644
--- a/src/GlobalAssemblyInfo.cs
+++ b/src/GlobalAssemblyInfo.cs
@@ -2,5 +2,5 @@
using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("1.15.0.0")]
-[assembly: AssemblyFileVersion("1.15.0.0")] \ No newline at end of file
+[assembly: AssemblyVersion("1.15.1.0")]
+[assembly: AssemblyFileVersion("1.15.1.0")]
diff --git a/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs b/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs
index b451465e..eda3a425 100644
--- a/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs
+++ b/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs
@@ -126,7 +126,7 @@ namespace StardewModdingAPI.Tests.Core
public void ValidateManifests_Skips_Failed()
{
// arrange
- Mock<IModMetadata> mock = new Mock<IModMetadata>(MockBehavior.Strict);
+ Mock<IModMetadata> mock = this.GetMetadata("Mod A");
mock.Setup(p => p.Status).Returns(ModMetadataStatus.Failed);
// act
@@ -140,10 +140,8 @@ namespace StardewModdingAPI.Tests.Core
public void ValidateManifests_ModCompatibility_AssumeBroken_Fails()
{
// arrange
- Mock<IModMetadata> mock = new Mock<IModMetadata>(MockBehavior.Strict);
- mock.Setup(p => p.Status).Returns(ModMetadataStatus.Found);
- mock.Setup(p => p.Compatibility).Returns(new ModCompatibility { Compatibility = ModCompatibilityType.AssumeBroken });
- mock.Setup(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny<string>())).Returns(() => mock.Object);
+ Mock<IModMetadata> mock = this.GetMetadata("Mod A", new string[0], allowStatusChange: true);
+ this.SetupMetadataForValidation(mock, new ModCompatibility { Compatibility = ModCompatibilityType.AssumeBroken });
// act
new ModResolver().ValidateManifests(new[] { mock.Object }, apiVersion: new SemanticVersion("1.0"));
@@ -156,11 +154,9 @@ namespace StardewModdingAPI.Tests.Core
public void ValidateManifests_MinimumApiVersion_Fails()
{
// arrange
- Mock<IModMetadata> mock = new Mock<IModMetadata>(MockBehavior.Strict);
- mock.Setup(p => p.Status).Returns(ModMetadataStatus.Found);
- mock.Setup(p => p.Compatibility).Returns(() => null);
+ 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.SetStatus(ModMetadataStatus.Failed, It.IsAny<string>())).Returns(() => mock.Object);
+ this.SetupMetadataForValidation(mock);
// act
new ModResolver().ValidateManifests(new[] { mock.Object }, apiVersion: new SemanticVersion("1.0"));
@@ -173,12 +169,8 @@ namespace StardewModdingAPI.Tests.Core
public void ValidateManifests_MissingEntryDLL_Fails()
{
// arrange
- Mock<IModMetadata> mock = new Mock<IModMetadata>(MockBehavior.Strict);
- mock.Setup(p => p.Status).Returns(ModMetadataStatus.Found);
- mock.Setup(p => p.Compatibility).Returns(() => null);
- mock.Setup(p => p.Manifest).Returns(this.GetManifest());
- mock.Setup(p => p.DirectoryPath).Returns(Path.GetTempPath());
- mock.Setup(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny<string>())).Returns(() => mock.Object);
+ Mock<IModMetadata> mock = this.GetMetadata(this.GetManifest("Mod A", "1.0", manifest => manifest.EntryDll = "Missing.dll"), allowStatusChange: true);
+ this.SetupMetadataForValidation(mock);
// act
new ModResolver().ValidateManifests(new[] { mock.Object }, apiVersion: new SemanticVersion("1.0"));
@@ -187,6 +179,26 @@ namespace StardewModdingAPI.Tests.Core
mock.Verify(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny<string>()), Times.Once, "The validation did not fail the metadata.");
}
+#if !SMAPI_1_x
+ [Test(Description = "Assert that validation fails when multiple mods have the same unique ID.")]
+ public void ValidateManifests_DuplicateUniqueID_Fails()
+ {
+ // 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> modC = this.GetMetadata("Mod C", new string[0], allowStatusChange: false);
+ foreach (Mock<IModMetadata> mod in new[] { modA, modB, modC })
+ this.SetupMetadataForValidation(mod);
+
+ // act
+ new ModResolver().ValidateManifests(new[] { modA.Object, modB.Object }, apiVersion: new SemanticVersion("1.0"));
+
+ // assert
+ modA.Verify(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny<string>()), Times.Once, "The validation did not fail the first mod with a unique ID.");
+ modB.Verify(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny<string>()), Times.Once, "The validation did not fail the second mod with a unique ID.");
+ }
+#endif
+
[Test(Description = "Assert that validation fails when the manifest references a DLL that does not exist.")]
public void ValidateManifests_Valid_Passes()
{
@@ -411,7 +423,7 @@ namespace StardewModdingAPI.Tests.Core
Assert.AreSame(modB.Object, mods[1], "The load order is incorrect: mod B should be second since it needs mod A.");
}
-#if SMAPI_2_0
+#if !SMAPI_1_x
[Test(Description = "Assert that optional dependencies are sorted correctly if present.")]
public void ProcessDependencies_IfOptional()
{
@@ -469,8 +481,9 @@ namespace StardewModdingAPI.Tests.Core
/// <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, params IManifestDependency[] dependencies)
+ private IManifest GetManifest(string uniqueID, string version, Action<Manifest> adjust, params IManifestDependency[] dependencies)
{
return this.GetManifest(manifest =>
{
@@ -478,11 +491,21 @@ namespace StardewModdingAPI.Tests.Core
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)
+ {
+ return this.GetManifest(uniqueID, version, null, dependencies);
+ }
+
+ /// <summary>Get a randomised basic manifest.</summary>
+ /// <param name="uniqueID">The mod's name and unique ID.</param>
private Mock<IModMetadata> GetMetadata(string uniqueID)
{
return this.GetMetadata(this.GetManifest(uniqueID, "1.0"));
@@ -504,6 +527,7 @@ namespace StardewModdingAPI.Tests.Core
private Mock<IModMetadata> GetMetadata(IManifest manifest, bool allowStatusChange = false)
{
Mock<IModMetadata> mod = new Mock<IModMetadata>(MockBehavior.Strict);
+ mod.Setup(p => p.Compatibility).Returns(() => null);
mod.Setup(p => p.Status).Returns(ModMetadataStatus.Found);
mod.Setup(p => p.DisplayName).Returns(manifest.UniqueID);
mod.Setup(p => p.Manifest).Returns(manifest);
@@ -516,5 +540,17 @@ namespace StardewModdingAPI.Tests.Core
}
return mod;
}
+
+ /// <summary>Set up a mock mod metadata for <see cref="ModResolver.ValidateManifests"/>.</summary>
+ /// <param name="mod">The mock mod metadata.</param>
+ /// <param name="compatibility">The compatibility record to set.</param>
+ private void SetupMetadataForValidation(Mock<IModMetadata> mod, ModCompatibility compatibility = null)
+ {
+ mod.Setup(p => p.Status).Returns(ModMetadataStatus.Found);
+ mod.Setup(p => p.Compatibility).Returns(() => null);
+ mod.Setup(p => p.Manifest).Returns(this.GetManifest());
+ mod.Setup(p => p.DirectoryPath).Returns(Path.GetTempPath());
+ mod.Setup(p => p.Compatibility).Returns(compatibility);
+ }
}
}
diff --git a/src/StardewModdingAPI/Command.cs b/src/StardewModdingAPI/Command.cs
index 689bb18b..76c85287 100644
--- a/src/StardewModdingAPI/Command.cs
+++ b/src/StardewModdingAPI/Command.cs
@@ -1,4 +1,4 @@
-#if !SMAPI_2_0
+#if SMAPI_1_x
using System;
using System.Collections.Generic;
using StardewModdingAPI.Events;
diff --git a/src/StardewModdingAPI/Config.cs b/src/StardewModdingAPI/Config.cs
index e166f414..734c04e8 100644
--- a/src/StardewModdingAPI/Config.cs
+++ b/src/StardewModdingAPI/Config.cs
@@ -1,4 +1,4 @@
-#if !SMAPI_2_0
+#if SMAPI_1_x
using System;
using System.IO;
using System.Linq;
diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs
index 586cadeb..3bd31c2d 100644
--- a/src/StardewModdingAPI/Constants.cs
+++ b/src/StardewModdingAPI/Constants.cs
@@ -34,10 +34,10 @@ namespace StardewModdingAPI
****/
/// <summary>SMAPI's current semantic version.</summary>
public static ISemanticVersion ApiVersion { get; } =
-#if SMAPI_2_0
- new SemanticVersion(2, 0, 0, $"alpha-{DateTime.UtcNow:yyyyMMddHHmm}");
+#if SMAPI_1_x
+ new SemanticVersion(1, 15, 1); // alpha-{DateTime.UtcNow:yyyyMMddHHmm}
#else
- new SemanticVersion(1, 15, 0); // alpha-{DateTime.UtcNow:yyyyMMddHHmm}
+ new SemanticVersion(2, 0, 0, $"alpha-{DateTime.UtcNow:yyyyMMddHHmm}");
#endif
/// <summary>The minimum supported version of Stardew Valley.</summary>
@@ -175,7 +175,7 @@ namespace StardewModdingAPI
new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPreRenderGuiEventNoCheck"),
// APIs removed in SMAPI 2.0
-#if SMAPI_2_0
+#if !SMAPI_1_x
new TypeFinder("StardewModdingAPI.Command"),
new TypeFinder("StardewModdingAPI.Config"),
new TypeFinder("StardewModdingAPI.Log"),
diff --git a/src/StardewModdingAPI/Events/EventArgsCommand.cs b/src/StardewModdingAPI/Events/EventArgsCommand.cs
index f0435904..35370139 100644
--- a/src/StardewModdingAPI/Events/EventArgsCommand.cs
+++ b/src/StardewModdingAPI/Events/EventArgsCommand.cs
@@ -1,4 +1,4 @@
-#if !SMAPI_2_0
+#if SMAPI_1_x
using System;
namespace StardewModdingAPI.Events
diff --git a/src/StardewModdingAPI/Events/EventArgsFarmerChanged.cs b/src/StardewModdingAPI/Events/EventArgsFarmerChanged.cs
index c34fc4ab..4c359939 100644
--- a/src/StardewModdingAPI/Events/EventArgsFarmerChanged.cs
+++ b/src/StardewModdingAPI/Events/EventArgsFarmerChanged.cs
@@ -1,4 +1,4 @@
-#if !SMAPI_2_0
+#if SMAPI_1_x
using System;
using SFarmer = StardewValley.Farmer;
diff --git a/src/StardewModdingAPI/Events/EventArgsInput.cs b/src/StardewModdingAPI/Events/EventArgsInput.cs
index e5eb7372..31368555 100644
--- a/src/StardewModdingAPI/Events/EventArgsInput.cs
+++ b/src/StardewModdingAPI/Events/EventArgsInput.cs
@@ -1,4 +1,4 @@
-#if SMAPI_2_0
+#if !SMAPI_1_x
using System;
using System.Linq;
using Microsoft.Xna.Framework;
diff --git a/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs b/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs
index d6fc4594..688b4b3d 100644
--- a/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs
+++ b/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs
@@ -1,4 +1,4 @@
-#if !SMAPI_2_0
+#if SMAPI_1_x
using System;
namespace StardewModdingAPI.Events
diff --git a/src/StardewModdingAPI/Events/EventArgsNewDay.cs b/src/StardewModdingAPI/Events/EventArgsNewDay.cs
index 5bd2ba66..b8cbe9e3 100644
--- a/src/StardewModdingAPI/Events/EventArgsNewDay.cs
+++ b/src/StardewModdingAPI/Events/EventArgsNewDay.cs
@@ -1,4 +1,4 @@
-#if !SMAPI_2_0
+#if SMAPI_1_x
using System;
namespace StardewModdingAPI.Events
diff --git a/src/StardewModdingAPI/Events/EventArgsStringChanged.cs b/src/StardewModdingAPI/Events/EventArgsStringChanged.cs
index 1498cb71..f580a2ce 100644
--- a/src/StardewModdingAPI/Events/EventArgsStringChanged.cs
+++ b/src/StardewModdingAPI/Events/EventArgsStringChanged.cs
@@ -1,4 +1,4 @@
-#if !SMAPI_2_0
+#if SMAPI_1_x
using System;
namespace StardewModdingAPI.Events
diff --git a/src/StardewModdingAPI/Events/GameEvents.cs b/src/StardewModdingAPI/Events/GameEvents.cs
index 557b451f..5610e67a 100644
--- a/src/StardewModdingAPI/Events/GameEvents.cs
+++ b/src/StardewModdingAPI/Events/GameEvents.cs
@@ -11,7 +11,7 @@ namespace StardewModdingAPI.Events
/*********
** Properties
*********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Manages deprecation warnings.</summary>
private static DeprecationManager DeprecationManager;
@@ -42,7 +42,7 @@ namespace StardewModdingAPI.Events
/// <summary>Raised during launch after configuring Stardew Valley, loading it into memory, and opening the game window. The window is still blank by this point.</summary>
internal static event EventHandler GameLoadedInternal;
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Raised during launch after configuring XNA or MonoGame. The game window hasn't been opened by this point. Called after <see cref="Microsoft.Xna.Framework.Game.Initialize"/>.</summary>
[Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(GameEvents.Initialize) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")]
public static event EventHandler Initialize
@@ -117,7 +117,7 @@ namespace StardewModdingAPI.Events
/*********
** Internal methods
*********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Injects types required for backwards compatibility.</summary>
/// <param name="deprecationManager">Manages deprecation warnings.</param>
internal static void Shim(DeprecationManager deprecationManager)
@@ -126,17 +126,17 @@ namespace StardewModdingAPI.Events
}
#endif
- /// <summary>Raise an <see cref="InitializeInternal"/> event.</summary>
- /// <param name="monitor">Encapsulates logging and monitoring.</param>
- internal static void InvokeInitialize(IMonitor monitor)
+ /// <summary>Raise an <see cref="InitializeInternal"/> event.</summary>
+ /// <param name="monitor">Encapsulates logging and monitoring.</param>
+ internal static void InvokeInitialize(IMonitor monitor)
{
monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.InitializeInternal)}", GameEvents.InitializeInternal?.GetInvocationList());
-#if !SMAPI_2_0
+#if SMAPI_1_x
monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.Initialize)}", GameEvents._Initialize?.GetInvocationList());
#endif
}
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Raise a <see cref="LoadContent"/> event.</summary>
/// <param name="monitor">Encapsulates logging and monitoring.</param>
internal static void InvokeLoadContent(IMonitor monitor)
@@ -150,12 +150,12 @@ namespace StardewModdingAPI.Events
internal static void InvokeGameLoaded(IMonitor monitor)
{
monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.GameLoadedInternal)}", GameEvents.GameLoadedInternal?.GetInvocationList());
-#if !SMAPI_2_0
+#if SMAPI_1_x
monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.GameLoaded)}", GameEvents._GameLoaded?.GetInvocationList());
#endif
}
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Raise a <see cref="FirstUpdateTick"/> event.</summary>
/// <param name="monitor">Encapsulates monitoring and logging.</param>
internal static void InvokeFirstUpdateTick(IMonitor monitor)
diff --git a/src/StardewModdingAPI/Events/InputEvents.cs b/src/StardewModdingAPI/Events/InputEvents.cs
index 285487af..b99b49e0 100644
--- a/src/StardewModdingAPI/Events/InputEvents.cs
+++ b/src/StardewModdingAPI/Events/InputEvents.cs
@@ -1,4 +1,4 @@
-#if SMAPI_2_0
+#if !SMAPI_1_x
using System;
using StardewModdingAPI.Framework;
using StardewModdingAPI.Utilities;
diff --git a/src/StardewModdingAPI/Events/PlayerEvents.cs b/src/StardewModdingAPI/Events/PlayerEvents.cs
index acbdc562..72826330 100644
--- a/src/StardewModdingAPI/Events/PlayerEvents.cs
+++ b/src/StardewModdingAPI/Events/PlayerEvents.cs
@@ -15,7 +15,7 @@ namespace StardewModdingAPI.Events
/*********
** Properties
*********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Manages deprecation warnings.</summary>
private static DeprecationManager DeprecationManager;
@@ -32,7 +32,7 @@ namespace StardewModdingAPI.Events
/*********
** Events
*********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Raised after the player loads a saved game.</summary>
[Obsolete("Use " + nameof(SaveEvents) + "." + nameof(SaveEvents.AfterLoad) + " instead")]
public static event EventHandler<EventArgsLoadedGameChanged> LoadedGame
@@ -68,7 +68,7 @@ namespace StardewModdingAPI.Events
/*********
** Internal methods
*********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Injects types required for backwards compatibility.</summary>
/// <param name="deprecationManager">Manages deprecation warnings.</param>
internal static void Shim(DeprecationManager deprecationManager)
diff --git a/src/StardewModdingAPI/Events/TimeEvents.cs b/src/StardewModdingAPI/Events/TimeEvents.cs
index f0fdb4f2..d5ab9fb7 100644
--- a/src/StardewModdingAPI/Events/TimeEvents.cs
+++ b/src/StardewModdingAPI/Events/TimeEvents.cs
@@ -11,7 +11,7 @@ namespace StardewModdingAPI.Events
/*********
** Properties
*********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Manages deprecation warnings.</summary>
private static DeprecationManager DeprecationManager;
@@ -42,7 +42,7 @@ namespace StardewModdingAPI.Events
/// <summary>Raised after the in-game clock changes.</summary>
public static event EventHandler<EventArgsIntChanged> TimeOfDayChanged;
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Raised after the day-of-month value changes, including when loading a save. This may happen before save; in most cases you should use <see cref="AfterDayStarted"/> instead.</summary>
[Obsolete("Use " + nameof(TimeEvents) + "." + nameof(TimeEvents.AfterDayStarted) + " or " + nameof(SaveEvents) + " instead")]
public static event EventHandler<EventArgsIntChanged> DayOfMonthChanged
@@ -96,7 +96,7 @@ namespace StardewModdingAPI.Events
/*********
** Internal methods
*********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Injects types required for backwards compatibility.</summary>
/// <param name="deprecationManager">Manages deprecation warnings.</param>
internal static void Shim(DeprecationManager deprecationManager)
@@ -121,7 +121,7 @@ namespace StardewModdingAPI.Events
monitor.SafelyRaiseGenericEvent($"{nameof(TimeEvents)}.{nameof(TimeEvents.TimeOfDayChanged)}", TimeEvents.TimeOfDayChanged?.GetInvocationList(), null, new EventArgsIntChanged(priorTime, newTime));
}
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Raise a <see cref="DayOfMonthChanged"/> event.</summary>
/// <param name="monitor">Encapsulates monitoring and logging.</param>
/// <param name="priorDay">The previous day value.</param>
diff --git a/src/StardewModdingAPI/Framework/CursorPosition.cs b/src/StardewModdingAPI/Framework/CursorPosition.cs
index 4f256da5..0fb2309b 100644
--- a/src/StardewModdingAPI/Framework/CursorPosition.cs
+++ b/src/StardewModdingAPI/Framework/CursorPosition.cs
@@ -1,4 +1,4 @@
-#if SMAPI_2_0
+#if !SMAPI_1_x
using Microsoft.Xna.Framework;
namespace StardewModdingAPI.Framework
diff --git a/src/StardewModdingAPI/Framework/DeprecationManager.cs b/src/StardewModdingAPI/Framework/DeprecationManager.cs
index 153d8829..43e82d74 100644
--- a/src/StardewModdingAPI/Framework/DeprecationManager.cs
+++ b/src/StardewModdingAPI/Framework/DeprecationManager.cs
@@ -54,7 +54,7 @@ namespace StardewModdingAPI.Framework
// show SMAPI 2.0 meta-warning
if(this.MarkWarned("SMAPI", "SMAPI 2.0 meta-warning", "2.0"))
- this.Monitor.Log("Some mods may stop working in SMAPI 2.0 (but they'll work fine for now). Try updating mods with 'deprecated code' warnings; if that doesn't remove the warnings, let the mod authors know about this message or see http://community.playstarbound.com/threads/135000 for details.", LogLevel.Warn);
+ this.Monitor.Log("Some mods may stop working in SMAPI 2.0 (but they'll work fine for now). Try updating mods with 'deprecated code' warnings; if that doesn't remove the warnings, let the mod authors know about this message or see http://stardewvalleywiki.com/Modding:SMAPI_2.0 for details.", LogLevel.Warn);
// build message
string message = $"{source ?? "An unknown mod"} uses deprecated code ({nounPhrase}).";
diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
index 38dddce7..b75453b7 100644
--- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
+++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
@@ -95,6 +95,9 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <param name="apiVersion">The current SMAPI version.</param>
public void ValidateManifests(IEnumerable<IModMetadata> mods, ISemanticVersion apiVersion)
{
+ mods = mods.ToArray();
+
+ // validate each manifest
foreach (IModMetadata mod in mods)
{
// skip if already failed
@@ -137,7 +140,7 @@ namespace StardewModdingAPI.Framework.ModLoading
}
// validate required fields
-#if SMAPI_2_0
+#if !SMAPI_1_x
{
List<string> missingFields = new List<string>(3);
@@ -153,6 +156,24 @@ namespace StardewModdingAPI.Framework.ModLoading
}
#endif
}
+
+ // validate IDs are unique
+#if !SMAPI_1_x
+ {
+ var duplicatesByID = mods
+ .GroupBy(mod => mod.Manifest.UniqueID?.Trim(), mod => mod, StringComparer.InvariantCultureIgnoreCase)
+ .Where(p => p.Count() > 1);
+ foreach (var group in duplicatesByID)
+ {
+ foreach (IModMetadata mod in group)
+ {
+ if (mod.Status == ModMetadataStatus.Failed)
+ continue; // don't replace metadata error
+ mod.SetStatus(ModMetadataStatus.Failed, $"its unique ID '{mod.Manifest.UniqueID}' is used by multiple mods ({string.Join(", ", group.Select(p => p.DisplayName))}).");
+ }
+ }
+ }
+#endif
}
/// <summary>Sort the given mods by the order they should be loaded.</summary>
@@ -234,10 +255,10 @@ namespace StardewModdingAPI.Framework.ModLoading
MinVersion = entry.MinimumVersion,
Mod = dependencyMod,
IsRequired =
-#if SMAPI_2_0
- entry.IsRequired
-#else
+#if SMAPI_1_x
true
+#else
+ entry.IsRequired
#endif
}
)
diff --git a/src/StardewModdingAPI/Framework/ModRegistry.cs b/src/StardewModdingAPI/Framework/ModRegistry.cs
index a427bdb7..8f30d813 100644
--- a/src/StardewModdingAPI/Framework/ModRegistry.cs
+++ b/src/StardewModdingAPI/Framework/ModRegistry.cs
@@ -36,14 +36,24 @@ namespace StardewModdingAPI.Framework
/// <returns>Returns the matching mod's metadata, or <c>null</c> if not found.</returns>
public IManifest Get(string uniqueID)
{
- return this.GetAll().FirstOrDefault(p => p.UniqueID == uniqueID);
+ // normalise search ID
+ if (string.IsNullOrWhiteSpace(uniqueID))
+ return null;
+ uniqueID = uniqueID.Trim();
+
+ // find match
+ return this.GetAll().FirstOrDefault(p =>
+#if SMAPI_1_x
+ p.UniqueID != null &&
+#endif
+ p.UniqueID.Trim().Equals(uniqueID, StringComparison.InvariantCultureIgnoreCase));
}
/// <summary>Get whether a mod has been loaded.</summary>
/// <param name="uniqueID">The mod's unique ID.</param>
public bool IsLoaded(string uniqueID)
{
- return this.GetAll().Any(p => p.UniqueID == uniqueID);
+ return this.Get(uniqueID) != null;
}
/****
diff --git a/src/StardewModdingAPI/Framework/Models/Manifest.cs b/src/StardewModdingAPI/Framework/Models/Manifest.cs
index 08b88025..1b5c2646 100644
--- a/src/StardewModdingAPI/Framework/Models/Manifest.cs
+++ b/src/StardewModdingAPI/Framework/Models/Manifest.cs
@@ -38,7 +38,7 @@ namespace StardewModdingAPI.Framework.Models
/// <summary>The unique mod ID.</summary>
public string UniqueID { get; set; }
-#if !SMAPI_2_0
+#if SMAPI_1_x
/// <summary>Whether the mod uses per-save config files.</summary>
[Obsolete("Use " + nameof(Mod) + "." + nameof(Mod.Helper) + "." + nameof(IModHelper.ReadConfig) + " instead")]
public bool PerSaveConfigs { get; set; }
diff --git a/src/StardewModdingAPI/Framework/Models/ManifestDependency.cs b/src/StardewModdingAPI/Framework/Models/ManifestDependency.cs
index 25d92a29..67f906e3 100644
--- a/src/StardewModdingAPI/Framework/Models/ManifestDependency.cs
+++ b/src/StardewModdingAPI/Framework/Models/ManifestDependency.cs
@@ -12,7 +12,7 @@
/// <summary>The minimum required version (if any).</summary>
public ISemanticVersion MinimumVersion { get; set; }
-#if SMAPI_2_0
+#if !SMAPI_1_x
/// <summary>Whether the dependency must be installed to use the mod.</summary>
public bool IsRequired { get; set; }
#endif
@@ -25,7 +25,7 @@
/// <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
-#if SMAPI_2_0
+#if !SMAPI_1_x
, bool required = true
#endif
)
@@ -34,7 +34,7 @@
this.MinimumVersion = !string.IsNullOrWhiteSpace(minimumVersion)
? new SemanticVersion(minimumVersion)
: null;
-#if SMAPI_2_0
+#if !SMAPI_1_x
this.IsRequired = required;
#endif
}
diff --git a/src/StardewModdingAPI/Framework/Monitor.cs b/src/StardewModdingAPI/Framework/Monitor.c