From 61d13d370c07bec029336890eec9501a8efc3056 Mon Sep 17 00:00:00 2001
From: Jesse Plamondon-Willard <github@jplamondonw.com>
Date: Mon, 10 Jul 2017 13:30:20 -0400
Subject: fail mods if their unique ID isn't unique (#323)

---
 .../Framework/ModLoading/ModResolver.cs             | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

(limited to 'src/StardewModdingAPI/Framework/ModLoading')

diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
index 38dddce7..69ef0b63 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
@@ -153,6 +156,24 @@ namespace StardewModdingAPI.Framework.ModLoading
                 }
 #endif
             }
+
+            // validate IDs are unique
+#if SMAPI_2_0
+            {
+                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>
-- 
cgit 


From d82e57d3060c96923ba9a8efe3c9eb839abffe59 Mon Sep 17 00:00:00 2001
From: Jesse Plamondon-Willard <github@jplamondonw.com>
Date: Mon, 10 Jul 2017 14:33:36 -0400
Subject: enable SMAPI 2.0 mode by default

This commit replaces the SMAPI_2_0 compile flag with SMAPI_1_x.
---
 README.md                                          |  2 +-
 .../Core/ModResolverTests.cs                       |  4 +-
 src/StardewModdingAPI/Command.cs                   |  2 +-
 src/StardewModdingAPI/Config.cs                    |  2 +-
 src/StardewModdingAPI/Constants.cs                 |  8 +--
 src/StardewModdingAPI/Events/EventArgsCommand.cs   |  2 +-
 .../Events/EventArgsFarmerChanged.cs               |  2 +-
 src/StardewModdingAPI/Events/EventArgsInput.cs     |  2 +-
 .../Events/EventArgsLoadedGameChanged.cs           |  2 +-
 src/StardewModdingAPI/Events/EventArgsNewDay.cs    |  2 +-
 .../Events/EventArgsStringChanged.cs               |  2 +-
 src/StardewModdingAPI/Events/GameEvents.cs         | 20 ++++----
 src/StardewModdingAPI/Events/InputEvents.cs        |  2 +-
 src/StardewModdingAPI/Events/PlayerEvents.cs       |  6 +--
 src/StardewModdingAPI/Events/TimeEvents.cs         |  8 +--
 src/StardewModdingAPI/Framework/CursorPosition.cs  |  2 +-
 .../Framework/ModLoading/ModResolver.cs            | 10 ++--
 src/StardewModdingAPI/Framework/Models/Manifest.cs |  2 +-
 .../Framework/Models/ManifestDependency.cs         |  6 +--
 src/StardewModdingAPI/Framework/Monitor.cs         |  8 +--
 src/StardewModdingAPI/Framework/SGame.cs           | 22 ++++----
 .../Serialisation/ManifestFieldConverter.cs        |  6 +--
 src/StardewModdingAPI/ICursorPosition.cs           |  2 +-
 src/StardewModdingAPI/IManifestDependency.cs       |  2 +-
 src/StardewModdingAPI/Log.cs                       |  2 +-
 src/StardewModdingAPI/Mod.cs                       |  8 +--
 src/StardewModdingAPI/Program.cs                   | 60 +++++++++++-----------
 src/StardewModdingAPI/Utilities/SButton.cs         | 16 +++---
 28 files changed, 106 insertions(+), 106 deletions(-)

(limited to 'src/StardewModdingAPI/Framework/ModLoading')

diff --git a/README.md b/README.md
index ca3128e4..bc5da52e 100644
--- a/README.md
+++ b/README.md
@@ -167,4 +167,4 @@ SMAPI uses a small number of conditional compilation constants, which you can se
 flag | purpose
 ---- | -------
 `SMAPI_FOR_WINDOWS` | Indicates that SMAPI is being compiled on Windows for players on Windows. Set automatically in `crossplatform.targets`.
-`SMAPI_2_0` | Sets SMAPI 2.0 mode, which enables features planned for SMAPI 2.0 and removes all deprecated code. This helps test how mods will work when SMAPI 2.0 is released.
+`SMAPI_1_x` | Sets legacy SMAPI 1._x_ mode, disables SMAPI 2.0 features, and enables deprecated code. This will be removed when SMAPI 2.0 is released.
diff --git a/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs b/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs
index 9b46c5d2..eda3a425 100644
--- a/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs
+++ b/src/StardewModdingAPI.Tests/Core/ModResolverTests.cs
@@ -179,7 +179,7 @@ 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_2_0
+#if !SMAPI_1_x
         [Test(Description = "Assert that validation fails when multiple mods have the same unique ID.")]
         public void ValidateManifests_DuplicateUniqueID_Fails()
         {
@@ -423,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()
         {
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..fcf49405 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}");
-#else
+#if SMAPI_1_x
             new SemanticVersion(1, 15, 0); // alpha-{DateTime.UtcNow:yyyyMMddHHmm}
+#else
+            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/ModLoading/ModResolver.cs b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
index 69ef0b63..b75453b7 100644
--- a/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
+++ b/src/StardewModdingAPI/Framework/ModLoading/ModResolver.cs
@@ -140,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);
 
@@ -158,7 +158,7 @@ namespace StardewModdingAPI.Framework.ModLoading
             }
 
             // validate IDs are unique
-#if SMAPI_2_0
+#if !SMAPI_1_x
             {
                 var duplicatesByID = mods
                     .GroupBy(mod => mod.Manifest.UniqueID?.Trim(), mod => mod, StringComparer.InvariantCultureIgnoreCase)
@@ -255,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/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.cs
index 6359b454..5ae24a73 100644
--- a/src/StardewModdingAPI/Framework/Monitor.cs
+++ b/src/StardewModdingAPI/Framework/Monitor.cs
@@ -45,7 +45,7 @@ namespace StardewModdingAPI.Framework
         /// <summary>Whether SMAPI is aborting. Mods don't need to worry about this unless they have background tasks.</summary>
         public bool IsExiting => this.ExitTokenSource.IsCancellationRequested;
 
-#if SMAPI_2_0
+#if !SMAPI_1_x
         /// <summary>Whether to show the full log stamps (with time/level/logger) in the console. If false, shows a simplified stamp with only the logger.</summary>
         internal bool ShowFullStampInConsole { get; set; }
 #endif
@@ -97,7 +97,7 @@ namespace StardewModdingAPI.Framework
             this.ExitTokenSource.Cancel();
         }
 
-#if SMAPI_2_0
+#if !SMAPI_1_x
         /// <summary>Write a newline to the console and log file.</summary>
         internal void Newline()
         {
@@ -108,7 +108,7 @@ namespace StardewModdingAPI.Framework
         }
 #endif
 
-#if !SMAPI_2_0
+#if SMAPI_1_x
         /// <summary>Log a message for the player or developer, using the specified console color.</summary>
         /// <param name="source">The name of the mod logging the message.</param>
         /// <param name="message">The message to log.</param>
@@ -144,7 +144,7 @@ namespace StardewModdingAPI.Framework
             string levelStr = level.ToString().ToUpper().PadRight(Monitor.MaxLevelLength);
 
             string fullMessage = $"[{DateTime.Now:HH:mm:ss} {levelStr} {source}] {message}";
-#if SMAPI_2_0
+#if !SMAPI_1_x
             string consoleMessage = this.ShowFullStampInConsole ? fullMessage : $"[{source}] {message}";
 #else
             string consoleMessage = fullMessage;
diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs
index c7784c60..d6f1a05b 100644
--- a/src/StardewModdingAPI/Framework/SGame.cs
+++ b/src/StardewModdingAPI/Framework/SGame.cs
@@ -118,7 +118,7 @@ namespace StardewModdingAPI.Framework
         /// <summary>The time of day (in 24-hour military format) at last check.</summary>
         private int PreviousTime;
 
-#if !SMAPI_2_0
+#if SMAPI_1_x
         /// <summary>The day of month (1–28) at last check.</summary>
         private int PreviousDay;
 
@@ -292,7 +292,7 @@ namespace StardewModdingAPI.Framework
                 if (this.FirstUpdate)
                 {
                     GameEvents.InvokeInitialize(this.Monitor);
-#if !SMAPI_2_0
+#if SMAPI_1_x
                     GameEvents.InvokeLoadContent(this.Monitor);
 #endif
                     GameEvents.InvokeGameLoaded(this.Monitor);
@@ -324,7 +324,7 @@ namespace StardewModdingAPI.Framework
                         Context.IsWorldReady = true;
 
                         SaveEvents.InvokeAfterLoad(this.Monitor);
-#if !SMAPI_2_0
+#if SMAPI_1_x
                         PlayerEvents.InvokeLoadedGame(this.Monitor, new EventArgsLoadedGameChanged(Game1.hasLoadedGame));
 #endif
                         TimeEvents.InvokeAfterDayStarted(this.Monitor);
@@ -382,7 +382,7 @@ namespace StardewModdingAPI.Framework
                     bool isClick = framePressedKeys.Contains(SButton.MouseLeft) || (framePressedKeys.Contains(SButton.ControllerA) && !currentlyPressedKeys.Contains(SButton.ControllerX));
 
                     // get cursor position
-#if SMAPI_2_0
+#if !SMAPI_1_x
                     ICursorPosition cursor;
                     {
                         // cursor position
@@ -398,7 +398,7 @@ namespace StardewModdingAPI.Framework
                     // raise button pressed
                     foreach (SButton button in framePressedKeys)
                     {
-#if SMAPI_2_0
+#if !SMAPI_1_x
                         InputEvents.InvokeButtonPressed(this.Monitor, button, cursor, isClick);
 #endif
 
@@ -420,7 +420,7 @@ namespace StardewModdingAPI.Framework
                     // raise button released
                     foreach (SButton button in frameReleasedKeys)
                     {
-#if SMAPI_2_0
+#if !SMAPI_1_x
                         bool wasClick =
                             (button == SButton.MouseLeft && previousPressedKeys.Contains(SButton.MouseLeft)) // released left click
                             || (button == SButton.ControllerA && previousPressedKeys.Contains(SButton.ControllerA) && !previousPressedKeys.Contains(SButton.ControllerX));
@@ -503,7 +503,7 @@ namespace StardewModdingAPI.Framework
                     if (this.GetHash(Game1.locations) != this.PreviousGameLocations)
                         LocationEvents.InvokeLocationsChanged(this.Monitor, Game1.locations);
 
-#if !SMAPI_2_0
+#if SMAPI_1_x
                     // raise player changed
                     if (Game1.player != this.PreviousFarmer)
                         PlayerEvents.InvokeFarmerChanged(this.Monitor, this.PreviousFarmer, Game1.player);
@@ -538,7 +538,7 @@ namespace StardewModdingAPI.Framework
                         // raise time changed
                         if (Game1.timeOfDay != this.PreviousTime)
                             TimeEvents.InvokeTimeOfDayChanged(this.Monitor, this.PreviousTime, Game1.timeOfDay);
-#if !SMAPI_2_0
+#if SMAPI_1_x
                         if (Game1.dayOfMonth != this.PreviousDay)
                             TimeEvents.InvokeDayOfMonthChanged(this.Monitor, this.PreviousDay, Game1.dayOfMonth);
                         if (Game1.currentSeason != this.PreviousSeason)
@@ -566,7 +566,7 @@ namespace StardewModdingAPI.Framework
                     this.PreviousTime = Game1.timeOfDay;
                     this.PreviousMineLevel = Game1.mine?.mineLevel ?? 0;
                     this.PreviousSaveID = Game1.uniqueIDForThisGame;
-#if !SMAPI_2_0
+#if SMAPI_1_x
                     this.PreviousFarmer = Game1.player;
                     this.PreviousDay = Game1.dayOfMonth;
                     this.PreviousSeason = Game1.currentSeason;
@@ -577,7 +577,7 @@ namespace StardewModdingAPI.Framework
                 /*********
                 ** Game day transition event (obsolete)
                 *********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
                 if (Game1.newDay != this.PreviousIsNewDay)
                 {
                     TimeEvents.InvokeOnNewDay(this.Monitor, this.PreviousDay, Game1.dayOfMonth, Game1.newDay);
@@ -603,7 +603,7 @@ namespace StardewModdingAPI.Framework
                 GameEvents.InvokeUpdateTick(this.Monitor);
                 if (this.FirstUpdate)
                 {
-#if !SMAPI_2_0
+#if SMAPI_1_x
                     GameEvents.InvokeFirstUpdateTick(this.Monitor);
 #endif
                     this.FirstUpdate = false;
diff --git a/src/StardewModdingAPI/Framework/Serialisation/ManifestFieldConverter.cs b/src/StardewModdingAPI/Framework/Serialisation/ManifestFieldConverter.cs
index 5be0f0b6..6947311b 100644
--- a/src/StardewModdingAPI/Framework/Serialisation/ManifestFieldConverter.cs
+++ b/src/StardewModdingAPI/Framework/Serialisation/ManifestFieldConverter.cs
@@ -73,11 +73,11 @@ namespace StardewModdingAPI.Framework.Serialisation
                 {
                     string uniqueID = obj.Value<string>(nameof(IManifestDependency.UniqueID));
                     string minVersion = obj.Value<string>(nameof(IManifestDependency.MinimumVersion));
-#if SMAPI_2_0
+#if SMAPI_1_x
+                    result.Add(new ManifestDependency(uniqueID, minVersion));
+#else
                     bool required = obj.Value<bool?>(nameof(IManifestDependency.IsRequired)) ?? true;
                     result.Add(new ManifestDependency(uniqueID, minVersion, required));
-#else
-                    result.Add(new ManifestDependency(uniqueID, minVersion));
 #endif
                 }
                 return result.ToArray();
diff --git a/src/StardewModdingAPI/ICursorPosition.cs b/src/StardewModdingAPI/ICursorPosition.cs
index d03cda71..8fbc115f 100644
--- a/src/StardewModdingAPI/ICursorPosition.cs
+++ b/src/StardewModdingAPI/ICursorPosition.cs
@@ -1,4 +1,4 @@
-#if SMAPI_2_0
+#if !SMAPI_1_x
 using Microsoft.Xna.Framework;
 
 namespace StardewModdingAPI
diff --git a/src/StardewModdingAPI/IManifestDependency.cs b/src/StardewModdingAPI/IManifestDependency.cs
index 027c1d59..1fa6c812 100644
--- a/src/StardewModdingAPI/IManifestDependency.cs
+++ b/src/StardewModdingAPI/IManifestDependency.cs
@@ -12,7 +12,7 @@
         /// <summary>The minimum required version (if any).</summary>
         ISemanticVersion MinimumVersion { get; }
 
-#if SMAPI_2_0
+#if !SMAPI_1_x
         /// <summary>Whether the dependency must be installed to use the mod.</summary>
         bool IsRequired { get; }
 #endif
diff --git a/src/StardewModdingAPI/Log.cs b/src/StardewModdingAPI/Log.cs
index 46f1caae..60220ad8 100644
--- a/src/StardewModdingAPI/Log.cs
+++ b/src/StardewModdingAPI/Log.cs
@@ -1,4 +1,4 @@
-#if !SMAPI_2_0
+#if SMAPI_1_x
 using System;
 using System.Threading;
 using StardewModdingAPI.Framework;
diff --git a/src/StardewModdingAPI/Mod.cs b/src/StardewModdingAPI/Mod.cs
index cb36c596..b5607234 100644
--- a/src/StardewModdingAPI/Mod.cs
+++ b/src/StardewModdingAPI/Mod.cs
@@ -11,7 +11,7 @@ namespace StardewModdingAPI
         /*********
         ** Properties
         *********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
         /// <summary>Manages deprecation warnings.</summary>
         private static DeprecationManager DeprecationManager;
 
@@ -33,7 +33,7 @@ namespace StardewModdingAPI
         /// <summary>The mod's manifest.</summary>
         public IManifest ModManifest { get; internal set; }
 
-#if !SMAPI_2_0
+#if SMAPI_1_x
         /// <summary>The full path to the mod's directory on the disk.</summary>
         [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.DirectoryPath) + " instead")]
         public string PathOnDisk
@@ -79,7 +79,7 @@ namespace StardewModdingAPI
         /*********
         ** Public 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)
@@ -108,7 +108,7 @@ namespace StardewModdingAPI
         /*********
         ** Private methods
         *********/
-#if !SMAPI_2_0
+#if SMAPI_1_x
         /// <summary>Get the full path to the per-save configuration file for the current save (if <see cref="Manifest.PerSaveConfigs"/> is <c>true</c>).</summary>
         [Obsolete]
         private string GetPerSaveConfigFolder()
diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs
index 97e18322..08bd2b84 100644
--- a/src/StardewModdingAPI/Program.cs
+++ b/src/StardewModdingAPI/Program.cs
@@ -127,7 +127,7 @@ namespace StardewModdingAPI
                 // init logging
                 this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} on {this.GetFriendlyPlatformName()}", LogLevel.Info);
                 this.Monitor.Log($"Mods go here: {Constants.ModPath}");
-#if !SMAPI_2_0
+#if SMAPI_1_x
                 this.Monitor.Log("Preparing SMAPI...");
 #endif
 
@@ -213,10 +213,10 @@ namespace StardewModdingAPI
             }
 
             // start game
-#if SMAPI_2_0
-            this.Monitor.Log("Starting game...", LogLevel.Trace);
-#else
+#if SMAPI_1_x
             this.Monitor.Log("Starting game...");
+#else
+            this.Monitor.Log("Starting game...", LogLevel.Trace);
 #endif
             try
             {
@@ -234,7 +234,7 @@ namespace StardewModdingAPI
             }
         }
 
-#if !SMAPI_2_0
+#if SMAPI_1_x
         /// <summary>Get a monitor for legacy code which doesn't have one passed in.</summary>
         [Obsolete("This method should only be used when needed for backwards compatibility.")]
         internal IMonitor GetLegacyMonitorForMod()
@@ -333,7 +333,7 @@ namespace StardewModdingAPI
             this.DeprecationManager = new DeprecationManager(this.Monitor, this.ModRegistry);
             this.CommandManager = new CommandManager();
 
-#if !SMAPI_2_0
+#if SMAPI_1_x
             // inject compatibility shims
 #pragma warning disable 618
             Command.Shim(this.CommandManager, this.DeprecationManager, this.ModRegistry);
@@ -357,7 +357,7 @@ namespace StardewModdingAPI
             if (this.Settings.DeveloperMode)
             {
                 this.Monitor.ShowTraceInConsole = true;
-#if SMAPI_2_0
+#if !SMAPI_1_x
                 this.Monitor.ShowFullStampInConsole = true;
 #endif
                 this.Monitor.Log($"You configured SMAPI to run in developer mode. The console may be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Info);
@@ -375,10 +375,10 @@ namespace StardewModdingAPI
 
             // load mods
             {
-#if SMAPI_2_0
-                this.Monitor.Log("Loading mod metadata...", LogLevel.Trace);
-#else
+#if SMAPI_1_x
                 this.Monitor.Log("Loading mod metadata...");
+#else
+                this.Monitor.Log("Loading mod metadata...", LogLevel.Trace);
 #endif
                 ModResolver resolver = new ModResolver();
 
@@ -387,7 +387,7 @@ namespace StardewModdingAPI
                 resolver.ValidateManifests(mods, Constants.ApiVersion);
 
                 // check for deprecated metadata
-#if !SMAPI_2_0
+#if SMAPI_1_x
                 IList<Action> deprecationWarnings = new List<Action>();
                 foreach (IModMetadata mod in mods.Where(m => m.Status != ModMetadataStatus.Failed))
                 {
@@ -429,12 +429,12 @@ namespace StardewModdingAPI
                 mods = resolver.ProcessDependencies(mods).ToArray();
 
                 // load mods
-#if SMAPI_2_0
-                this.LoadMods(mods, new JsonHelper(), this.ContentManager);
-#else
+#if SMAPI_1_x
                 this.LoadMods(mods, new JsonHelper(), this.ContentManager, deprecationWarnings);
                 foreach (Action warning in deprecationWarnings)
                     warning();
+#else
+                this.LoadMods(mods, new JsonHelper(), this.ContentManager);
 #endif
             }
             if (this.Monitor.IsExiting)
@@ -469,7 +469,7 @@ namespace StardewModdingAPI
         private void RunConsoleLoop()
         {
             // prepare console
-#if !SMAPI_2_0
+#if SMAPI_1_x
             this.Monitor.Log("Starting console...");
 #endif
             this.Monitor.Log("Type 'help' for help, or 'help <cmd>' for a command's usage", LogLevel.Info);
@@ -603,17 +603,17 @@ namespace StardewModdingAPI
         /// <param name="mods">The mods to load.</param>
         /// <param name="jsonHelper">The JSON helper with which to read mods' JSON files.</param>
         /// <param name="contentManager">The content manager to use for mod content.</param>
-#if !SMAPI_2_0
+#if SMAPI_1_x
         /// <param name="deprecationWarnings">A list to populate with any deprecation warnings.</param>
         private void LoadMods(IModMetadata[] mods, JsonHelper jsonHelper, SContentManager contentManager, IList<Action> deprecationWarnings)
 #else
         private void LoadMods(IModMetadata[] mods, JsonHelper jsonHelper, SContentManager contentManager)
 #endif
         {
-#if SMAPI_2_0
-            this.Monitor.Log("Loading mods...", LogLevel.Trace);
-#else
+#if SMAPI_1_x
             this.Monitor.Log("Loading mods...");
+#else
+            this.Monitor.Log("Loading mods...", LogLevel.Trace);
 #endif
             // load mod assemblies
             IDictionary<IModMetadata, string> skippedMods = new Dictionary<IModMetadata, string>();
@@ -691,7 +691,7 @@ namespace StardewModdingAPI
                             continue;
                         }
 
-#if !SMAPI_2_0
+#if SMAPI_1_x
                         // prevent mods from using SMAPI 2.0 content interception before release
                         // ReSharper disable SuspiciousTypeConversion.Global
                         if (mod is IAssetEditor || mod is IAssetLoader)
@@ -712,7 +712,7 @@ namespace StardewModdingAPI
                             mod.ModManifest = manifest;
                             mod.Helper = new ModHelper(manifest.UniqueID, metadata.DirectoryPath, jsonHelper, contentHelper, commandHelper, modRegistryHelper, reflectionHelper, translationHelper);
                             mod.Monitor = this.GetSecondaryMonitor(metadata.DisplayName);
-#if !SMAPI_2_0
+#if SMAPI_1_x
                             mod.PathOnDisk = metadata.DirectoryPath;
 #endif
                         }
@@ -730,7 +730,7 @@ namespace StardewModdingAPI
             IModMetadata[] loadedMods = this.ModRegistry.GetMods().ToArray();
 
             // log skipped mods
-#if SMAPI_2_0
+#if !SMAPI_1_x
             this.Monitor.Newline();
 #endif
             if (skippedMods.Any())
@@ -746,7 +746,7 @@ namespace StardewModdingAPI
                     else
                         this.Monitor.Log($"   {mod.DisplayName} because {reason}", LogLevel.Error);
                 }
-#if SMAPI_2_0
+#if !SMAPI_1_x
                 this.Monitor.Newline();
 #endif
             }
@@ -763,7 +763,7 @@ namespace StardewModdingAPI
                     LogLevel.Info
                 );
             }
-#if SMAPI_2_0
+#if !SMAPI_1_x
             this.Monitor.Newline();
 #endif
 
@@ -785,7 +785,7 @@ namespace StardewModdingAPI
                 {
                     IMod mod = metadata.Mod;
                     mod.Entry(mod.Helper);
-#if !SMAPI_2_0
+#if SMAPI_1_x
                     (mod as Mod)?.Entry(); // deprecated since 1.0
 
                     // raise deprecation warning for old Entry() methods
@@ -869,7 +869,10 @@ namespace StardewModdingAPI
                     }
                     else
                     {
-#if SMAPI_2_0
+#if SMAPI_1_x
+                        this.Monitor.Log("The following commands are registered: " + string.Join(", ", this.CommandManager.GetAll().Select(p => p.Name)) + ".", LogLevel.Info);
+                        this.Monitor.Log("For more information about a command, type 'help command_name'.", LogLevel.Info);
+#else
                         string message = "The following commands are registered:\n";
                         IGrouping<string, string>[] groups = (from command in this.CommandManager.GetAll() orderby command.ModName, command.Name group command.Name by command.ModName).ToArray();
                         foreach (var group in groups)
@@ -881,9 +884,6 @@ namespace StardewModdingAPI
                         message += "For more information about a command, type 'help command_name'.";
 
                         this.Monitor.Log(message, LogLevel.Info);
-#else
-                        this.Monitor.Log("The following commands are registered: " + string.Join(", ", this.CommandManager.GetAll().Select(p => p.Name)) + ".", LogLevel.Info);
-                        this.Monitor.Log("For more information about a command, type 'help command_name'.", LogLevel.Info);
 #endif
                     }
                     break;
@@ -933,7 +933,7 @@ namespace StardewModdingAPI
             {
                 WriteToConsole = this.Monitor.WriteToConsole,
                 ShowTraceInConsole = this.Settings.DeveloperMode,
-#if SMAPI_2_0
+#if !SMAPI_1_x
                 ShowFullStampInConsole = this.Settings.DeveloperMode
 #endif
             };
diff --git a/src/StardewModdingAPI/Utilities/SButton.cs b/src/StardewModdingAPI/Utilities/SButton.cs
index f4fccfff..c66d5ade 100644
--- a/src/StardewModdingAPI/Utilities/SButton.cs
+++ b/src/StardewModdingAPI/Utilities/SButton.cs
@@ -1,16 +1,16 @@
-using System;
+using System;
 using Microsoft.Xna.Framework.Input;
 
 namespace StardewModdingAPI.Utilities
 {
     /// <summary>A unified button constant which includes all controller, keyboard, and mouse buttons.</summary>
     /// <remarks>Derived from <see cref="Keys"/>, <see cref="Buttons"/>, and <see cref="System.Windows.Forms.MouseButtons"/>.</remarks>
-#if SMAPI_2_0
-    public
-#else
+#if SMAPI_1_x
     internal
+#else
+    public
 #endif
-        enum SButton
+    enum SButton
     {
         /// <summary>No valid key.</summary>
         None = 0,
@@ -593,10 +593,10 @@ namespace StardewModdingAPI.Utilities
     }
 
     /// <summary>Provides extension methods for <see cref="SButton"/>.</summary>
-#if SMAPI_2_0
-    public
-#else
+#if SMAPI_1_x
     internal
+#else
+    public
 #endif
     static class SButtonExtensions
     {
-- 
cgit