add SMAPI 3.0 compatibility strict mode (#606)

This commit is contained in:
Jesse Plamondon-Willard 2018-12-03 02:39:20 -05:00
parent a2a0469cd0
commit 3744e2f1e5
No known key found for this signature in database
GPG Key ID: 7D7C8097B62033CE
51 changed files with 229 additions and 37 deletions

View File

@ -105,8 +105,8 @@ SMAPI uses a small number of conditional compilation constants, which you can se
flag | purpose flag | purpose
---- | ------- ---- | -------
`SMAPI_FOR_WINDOWS` | Indicates that SMAPI is being compiled on Windows for players on Windows. Set automatically in `crossplatform.targets`. `SMAPI_FOR_WINDOWS` | Whether SMAPI is being compiled on Windows for players on Windows. Set automatically in `crossplatform.targets`.
`SMAPI_3_0_STRICT` | Whether to exclude all deprecated APIs from compilation. This is useful for testing mods for SMAPI 3.0 compatibility.
# SMAPI web services # SMAPI web services
## Overview ## Overview

View File

@ -29,7 +29,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands
helper.ConsoleCommands.Add(command.Name, command.Description, (name, args) => this.HandleCommand(command, name, args)); helper.ConsoleCommands.Add(command.Name, command.Description, (name, args) => this.HandleCommand(command, name, args));
// hook events // hook events
GameEvents.UpdateTick += this.GameEvents_UpdateTick; helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked;
} }
@ -39,7 +39,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands
/// <summary>The method invoked when the game updates its state.</summary> /// <summary>The method invoked when the game updates its state.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param> /// <param name="e">The event arguments.</param>
private void GameEvents_UpdateTick(object sender, EventArgs e) private void OnUpdateTicked(object sender, EventArgs e)
{ {
if (!Context.IsWorldReady) if (!Context.IsWorldReady)
return; return;

View File

@ -47,7 +47,7 @@ namespace StardewModdingAPI.Tests.Utilities
Assert.AreEqual(major, version.MajorVersion, "The major version doesn't match the given value."); Assert.AreEqual(major, version.MajorVersion, "The major version doesn't match the given value.");
Assert.AreEqual(minor, version.MinorVersion, "The minor version doesn't match the given value."); Assert.AreEqual(minor, version.MinorVersion, "The minor version doesn't match the given value.");
Assert.AreEqual(patch, version.PatchVersion, "The patch version doesn't match the given value."); Assert.AreEqual(patch, version.PatchVersion, "The patch version doesn't match the given value.");
Assert.AreEqual(string.IsNullOrWhiteSpace(tag) ? null : tag.Trim(), version.Build, "The tag doesn't match the given value."); Assert.AreEqual(string.IsNullOrWhiteSpace(tag) ? null : tag.Trim(), version.PrereleaseTag, "The tag doesn't match the given value.");
return version.ToString(); return version.ToString();
} }

View File

@ -22,7 +22,7 @@ namespace StardewModdingAPI
/// <summary>Whether <see cref="IsPlayerFree"/> is true and the player is free to move (e.g. not using a tool).</summary> /// <summary>Whether <see cref="IsPlayerFree"/> is true and the player is free to move (e.g. not using a tool).</summary>
public static bool CanPlayerMove => Context.IsPlayerFree && Game1.player.CanMove; public static bool CanPlayerMove => Context.IsPlayerFree && Game1.player.CanMove;
/// <summary>Whether the game is currently running the draw loop. This isn't relevant to most mods, since you should use <see cref="GraphicsEvents.OnPostRenderEvent"/> to draw to the screen.</summary> /// <summary>Whether the game is currently running the draw loop. This isn't relevant to most mods, since you should use <see cref="IDisplayEvents"/> events to draw to the screen.</summary>
public static bool IsInDrawLoop { get; internal set; } public static bool IsInDrawLoop { get; internal set; }
/// <summary>Whether <see cref="IsWorldReady"/> and the player loaded the save in multiplayer mode (regardless of whether any other players are connected).</summary> /// <summary>Whether <see cref="IsWorldReady"/> and the player loaded the save in multiplayer mode (regardless of whether any other players are connected).</summary>

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -46,3 +47,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
@ -124,3 +125,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewValley.Menus; using StardewValley.Menus;
@ -29,3 +30,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewValley.Menus; using StardewValley.Menus;
@ -24,3 +25,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
@ -30,3 +31,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,4 +1,5 @@
using System; #if !SMAPI_3_0_STRICT
using System;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
@ -30,3 +31,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
@ -35,3 +36,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,4 +1,5 @@
using System; #if !SMAPI_3_0_STRICT
using System;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
@ -35,3 +36,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -60,3 +61,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
namespace StardewModdingAPI.Events namespace StardewModdingAPI.Events
@ -28,3 +29,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -39,3 +40,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
@ -24,3 +25,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
@ -29,3 +30,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Enums; using StardewModdingAPI.Enums;
@ -51,3 +52,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -37,3 +38,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -38,3 +39,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -31,3 +32,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,4 +1,5 @@
using System; #if !SMAPI_3_0_STRICT
using System;
namespace StardewModdingAPI.Events namespace StardewModdingAPI.Events
{ {
@ -28,3 +29,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,4 +1,5 @@
using System; #if !SMAPI_3_0_STRICT
using System;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
@ -40,3 +41,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewValley; using StardewValley;
@ -30,3 +31,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,4 +1,5 @@
using System; #if !SMAPI_3_0_STRICT
using System;
namespace StardewModdingAPI.Events namespace StardewModdingAPI.Events
{ {
@ -28,4 +29,5 @@ namespace StardewModdingAPI.Events
this.NewValue = newValue; this.NewValue = newValue;
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -123,3 +124,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -121,3 +122,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -57,3 +58,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -68,3 +69,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -57,3 +58,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -46,3 +47,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -79,3 +80,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -69,3 +70,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -101,3 +102,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -46,3 +47,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,3 +1,4 @@
#if !SMAPI_3_0_STRICT
using System; using System;
using StardewModdingAPI.Framework; using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Events;
@ -57,3 +58,4 @@ namespace StardewModdingAPI.Events
} }
} }
} }
#endif

View File

@ -1,5 +1,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
#if !SMAPI_3_0_STRICT
using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input;
#endif
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
namespace StardewModdingAPI.Framework.Events namespace StardewModdingAPI.Framework.Events
@ -156,6 +158,7 @@ namespace StardewModdingAPI.Framework.Events
public readonly ManagedEvent<UnvalidatedUpdateTickedEventArgs> UnvalidatedUpdateTicked; public readonly ManagedEvent<UnvalidatedUpdateTickedEventArgs> UnvalidatedUpdateTicked;
#if !SMAPI_3_0_STRICT
/********* /*********
** Events (old) ** Events (old)
*********/ *********/
@ -342,6 +345,7 @@ namespace StardewModdingAPI.Framework.Events
/// <summary>Raised after the in-game clock changes.</summary> /// <summary>Raised after the in-game clock changes.</summary>
public readonly ManagedEvent<EventArgsIntChanged> Legacy_TimeOfDayChanged; public readonly ManagedEvent<EventArgsIntChanged> Legacy_TimeOfDayChanged;
#endif
/********* /*********
@ -354,7 +358,9 @@ namespace StardewModdingAPI.Framework.Events
{ {
// create shortcut initialisers // create shortcut initialisers
ManagedEvent<TEventArgs> ManageEventOf<TEventArgs>(string typeName, string eventName) => new ManagedEvent<TEventArgs>($"{typeName}.{eventName}", monitor, modRegistry); ManagedEvent<TEventArgs> ManageEventOf<TEventArgs>(string typeName, string eventName) => new ManagedEvent<TEventArgs>($"{typeName}.{eventName}", monitor, modRegistry);
#if !SMAPI_3_0_STRICT
ManagedEvent ManageEvent(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); ManagedEvent ManageEvent(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry);
#endif
// init events (new) // init events (new)
this.MenuChanged = ManageEventOf<MenuChangedEventArgs>(nameof(IModEvents.Display), nameof(IDisplayEvents.MenuChanged)); this.MenuChanged = ManageEventOf<MenuChangedEventArgs>(nameof(IModEvents.Display), nameof(IDisplayEvents.MenuChanged));
@ -405,6 +411,7 @@ namespace StardewModdingAPI.Framework.Events
this.UnvalidatedUpdateTicking = ManageEventOf<UnvalidatedUpdateTickingEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicking)); this.UnvalidatedUpdateTicking = ManageEventOf<UnvalidatedUpdateTickingEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicking));
this.UnvalidatedUpdateTicked = ManageEventOf<UnvalidatedUpdateTickedEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicked)); this.UnvalidatedUpdateTicked = ManageEventOf<UnvalidatedUpdateTickedEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicked));
#if !SMAPI_3_0_STRICT
// init events (old) // init events (old)
this.Legacy_LocaleChanged = ManageEventOf<EventArgsValueChanged<string>>(nameof(ContentEvents), nameof(ContentEvents.AfterLocaleChanged)); this.Legacy_LocaleChanged = ManageEventOf<EventArgsValueChanged<string>>(nameof(ContentEvents), nameof(ContentEvents.AfterLocaleChanged));
@ -466,6 +473,7 @@ namespace StardewModdingAPI.Framework.Events
this.Legacy_AfterDayStarted = ManageEvent(nameof(TimeEvents), nameof(TimeEvents.AfterDayStarted)); this.Legacy_AfterDayStarted = ManageEvent(nameof(TimeEvents), nameof(TimeEvents.AfterDayStarted));
this.Legacy_TimeOfDayChanged = ManageEventOf<EventArgsIntChanged>(nameof(TimeEvents), nameof(TimeEvents.TimeOfDayChanged)); this.Legacy_TimeOfDayChanged = ManageEventOf<EventArgsIntChanged>(nameof(TimeEvents), nameof(TimeEvents.TimeOfDayChanged));
#endif
} }
} }
} }

View File

@ -131,6 +131,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
this.Data.WriteJsonFile("config.json", config); this.Data.WriteJsonFile("config.json", config);
} }
#if !SMAPI_3_0_STRICT
/**** /****
** Generic JSON files ** Generic JSON files
****/ ****/
@ -199,6 +200,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
// create content pack // create content pack
return this.CreateContentPack(directoryPath, manifest); return this.CreateContentPack(directoryPath, manifest);
} }
#endif
/// <summary>Get all content packs loaded for this mod.</summary> /// <summary>Get all content packs loaded for this mod.</summary>
public IEnumerable<IContentPack> GetContentPacks() public IEnumerable<IContentPack> GetContentPacks()

View File

@ -23,7 +23,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <summary>The instruction is compatible, but uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary> /// <summary>The instruction is compatible, but uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary>
DetectedDynamic, DetectedDynamic,
/// <summary>The instruction is compatible, but references <see cref="SpecialisedEvents.UnvalidatedUpdateTick"/> which may impact stability.</summary> /// <summary>The instruction is compatible, but references <see cref="ISpecialisedEvents.UnvalidatedUpdateTicking"/> or <see cref="ISpecialisedEvents.UnvalidatedUpdateTicked"/> which may impact stability.</summary>
DetectedUnvalidatedUpdateTick, DetectedUnvalidatedUpdateTick,
/// <summary>The instruction accesses the filesystem directly.</summary> /// <summary>The instruction accesses the filesystem directly.</summary>

View File

@ -22,7 +22,7 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <summary>The mod uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary> /// <summary>The mod uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary>
UsesDynamic = 8, UsesDynamic = 8,
/// <summary>The mod references <see cref="SpecialisedEvents.UnvalidatedUpdateTick"/> which may impact stability.</summary> /// <summary>The mod references <see cref="ISpecialisedEvents.UnvalidatedUpdateTicking"/> or <see cref="ISpecialisedEvents.UnvalidatedUpdateTicked"/> which may impact stability.</summary>
UsesUnvalidatedUpdateTick = 16, UsesUnvalidatedUpdateTick = 16,
/// <summary>The mod has no update keys set.</summary> /// <summary>The mod has no update keys set.</summary>

View File

@ -180,6 +180,7 @@ namespace StardewModdingAPI.Framework
// initialise SMAPI // initialise SMAPI
try try
{ {
#if !SMAPI_3_0_STRICT
// hook up events // hook up events
ContentEvents.Init(this.EventManager, this.DeprecationManager); ContentEvents.Init(this.EventManager, this.DeprecationManager);
ControlEvents.Init(this.EventManager, this.DeprecationManager); ControlEvents.Init(this.EventManager, this.DeprecationManager);
@ -194,6 +195,7 @@ namespace StardewModdingAPI.Framework
SaveEvents.Init(this.EventManager, this.DeprecationManager); SaveEvents.Init(this.EventManager, this.DeprecationManager);
SpecialisedEvents.Init(this.EventManager, this.DeprecationManager); SpecialisedEvents.Init(this.EventManager, this.DeprecationManager);
TimeEvents.Init(this.EventManager, this.DeprecationManager); TimeEvents.Init(this.EventManager, this.DeprecationManager);
#endif
// init JSON parser // init JSON parser
JsonConverter[] converters = { JsonConverter[] converters = {
@ -216,7 +218,7 @@ namespace StardewModdingAPI.Framework
// override game // override game
SGame.ConstructorHack = new SGameConstructorHack(this.Monitor, this.Reflection, this.Toolkit.JsonHelper); SGame.ConstructorHack = new SGameConstructorHack(this.Monitor, this.Reflection, this.Toolkit.JsonHelper);
this.GameInstance = new SGame(this.Monitor, this.MonitorForGame, this.Reflection, this.EventManager, this.Toolkit.JsonHelper, this.ModRegistry, this.DeprecationManager, this.InitialiseAfterGameStart, this.Dispose); this.GameInstance = new SGame(this.Monitor, this.MonitorForGame, this.Reflection, this.EventManager, this.Toolkit.JsonHelper, this.ModRegistry, this.DeprecationManager, this.OnLocaleChanged, this.InitialiseAfterGameStart, this.Dispose);
StardewValley.Program.gamePtr = this.GameInstance; StardewValley.Program.gamePtr = this.GameInstance;
// add exit handler // add exit handler
@ -239,12 +241,13 @@ namespace StardewModdingAPI.Framework
} }
}).Start(); }).Start();
// hook into game events
ContentEvents.AfterLocaleChanged += (sender, e) => this.OnLocaleChanged();
// set window titles // set window titles
this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion}"; this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion}";
Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion}"; Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion}";
#if SMAPI_3_0_STRICT
this.GameInstance.Window.Title += " [SMAPI 3.0 strict mode]";
Console.Title += " [SMAPI 3.0 strict mode]";
#endif
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -348,8 +351,11 @@ namespace StardewModdingAPI.Framework
private void InitialiseAfterGameStart() private void InitialiseAfterGameStart()
{ {
// add headers // add headers
#if SMAPI_3_0_STRICT
this.Monitor.Log($"You're running SMAPI 3.0 strict mode, so most mods won't work correctly. If that wasn't intended, install the normal version of SMAPI from https://smapi.io instead.", LogLevel.Warn);
#endif
if (this.Settings.DeveloperMode) if (this.Settings.DeveloperMode)
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); this.Monitor.Log($"You have SMAPI for developers, so the console will be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Info);
if (!this.Settings.CheckForUpdates) if (!this.Settings.CheckForUpdates)
this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by reinstalling SMAPI or editing {Constants.ApiConfigPath}.", LogLevel.Warn); this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by reinstalling SMAPI or editing {Constants.ApiConfigPath}.", LogLevel.Warn);
if (!this.Monitor.WriteToConsole) if (!this.Monitor.WriteToConsole)
@ -409,6 +415,11 @@ namespace StardewModdingAPI.Framework
int modsLoaded = this.ModRegistry.GetAll().Count(); int modsLoaded = this.ModRegistry.GetAll().Count();
this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion} with {modsLoaded} mods"; this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion} with {modsLoaded} mods";
Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion} with {modsLoaded} mods"; Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion} with {modsLoaded} mods";
#if SMAPI_3_0_STRICT
this.GameInstance.Window.Title += " [SMAPI 3.0 strict mode]";
Console.Title += " [SMAPI 3.0 strict mode]";
#endif
// start SMAPI console // start SMAPI console
new Thread(this.RunConsoleLoop).Start(); new Thread(this.RunConsoleLoop).Start();

View File

@ -9,7 +9,6 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Netcode; using Netcode;
using StardewModdingAPI.Enums; using StardewModdingAPI.Enums;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
@ -70,12 +69,15 @@ namespace StardewModdingAPI.Framework
/// <summary>Whether the after-load events were raised for this session.</summary> /// <summary>Whether the after-load events were raised for this session.</summary>
private bool RaisedAfterLoadEvent; private bool RaisedAfterLoadEvent;
/// <summary>Whether the game is saving and SMAPI has already raised <see cref="SaveEvents.BeforeSave"/>.</summary> /// <summary>Whether the game is saving and SMAPI has already raised <see cref="IGameLoopEvents.Saving"/>.</summary>
private bool IsBetweenSaveEvents; private bool IsBetweenSaveEvents;
/// <summary>Whether the game is creating the save file and SMAPI has already raised <see cref="SaveEvents.BeforeCreate"/>.</summary> /// <summary>Whether the game is creating the save file and SMAPI has already raised <see cref="IGameLoopEvents.SaveCreating"/>.</summary>
private bool IsBetweenCreateEvents; private bool IsBetweenCreateEvents;
/// <summary>A callback to invoke after the content language changes.</summary>
private readonly Action OnLocaleChanged;
/// <summary>A callback to invoke after the game finishes initialising.</summary> /// <summary>A callback to invoke after the game finishes initialising.</summary>
private readonly Action OnGameInitialised; private readonly Action OnGameInitialised;
@ -138,9 +140,10 @@ namespace StardewModdingAPI.Framework
/// <param name="jsonHelper">Encapsulates SMAPI's JSON file parsing.</param> /// <param name="jsonHelper">Encapsulates SMAPI's JSON file parsing.</param>
/// <param name="modRegistry">Tracks the installed mods.</param> /// <param name="modRegistry">Tracks the installed mods.</param>
/// <param name="deprecationManager">Manages deprecation warnings.</param> /// <param name="deprecationManager">Manages deprecation warnings.</param>
/// <param name="onLocaleChanged">A callback to invoke after the content language changes.</param>
/// <param name="onGameInitialised">A callback to invoke after the game finishes initialising.</param> /// <param name="onGameInitialised">A callback to invoke after the game finishes initialising.</param>
/// <param name="onGameExiting">A callback to invoke when the game exits.</param> /// <param name="onGameExiting">A callback to invoke when the game exits.</param>
internal SGame(IMonitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onGameInitialised, Action onGameExiting) internal SGame(IMonitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onLocaleChanged, Action onGameInitialised, Action onGameExiting)
{ {
SGame.ConstructorHack = null; SGame.ConstructorHack = null;
@ -158,6 +161,7 @@ namespace StardewModdingAPI.Framework
this.ModRegistry = modRegistry; this.ModRegistry = modRegistry;
this.Reflection = reflection; this.Reflection = reflection;
this.DeprecationManager = deprecationManager; this.DeprecationManager = deprecationManager;
this.OnLocaleChanged = onLocaleChanged;
this.OnGameInitialised = onGameInitialised; this.OnGameInitialised = onGameInitialised;
this.OnGameExiting = onGameExiting; this.OnGameExiting = onGameExiting;
Game1.input = new SInputState(); Game1.input = new SInputState();
@ -212,7 +216,9 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log("Context: returned to title", LogLevel.Trace); this.Monitor.Log("Context: returned to title", LogLevel.Trace);
this.Multiplayer.Peers.Clear(); this.Multiplayer.Peers.Clear();
this.Events.ReturnedToTitle.RaiseEmpty(); this.Events.ReturnedToTitle.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_AfterReturnToTitle.Raise(); this.Events.Legacy_AfterReturnToTitle.Raise();
#endif
} }
/// <summary>Constructor a content manager to read XNB files.</summary> /// <summary>Constructor a content manager to read XNB files.</summary>
@ -296,7 +302,9 @@ namespace StardewModdingAPI.Framework
this.Events.UnvalidatedUpdateTicking.Raise(new UnvalidatedUpdateTickingEventArgs(this.TicksElapsed)); this.Events.UnvalidatedUpdateTicking.Raise(new UnvalidatedUpdateTickingEventArgs(this.TicksElapsed));
base.Update(gameTime); base.Update(gameTime);
this.Events.UnvalidatedUpdateTicked.Raise(new UnvalidatedUpdateTickedEventArgs(this.TicksElapsed)); this.Events.UnvalidatedUpdateTicked.Raise(new UnvalidatedUpdateTickedEventArgs(this.TicksElapsed));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_UnvalidatedUpdateTick.Raise(); this.Events.Legacy_UnvalidatedUpdateTick.Raise();
#endif
return; return;
} }
@ -343,7 +351,9 @@ namespace StardewModdingAPI.Framework
// This should *always* run, even when suppressing mod events, since the game uses // This should *always* run, even when suppressing mod events, since the game uses
// this too. For example, doing this after mod event suppression would prevent the // this too. For example, doing this after mod event suppression would prevent the
// user from doing anything on the overnight shipping screen. // user from doing anything on the overnight shipping screen.
#if !SMAPI_3_0_STRICT
SInputState previousInputState = this.Input.Clone(); SInputState previousInputState = this.Input.Clone();
#endif
SInputState inputState = this.Input; SInputState inputState = this.Input;
if (this.IsActive) if (this.IsActive)
inputState.TrueUpdate(); inputState.TrueUpdate();
@ -364,7 +374,9 @@ namespace StardewModdingAPI.Framework
this.IsBetweenCreateEvents = true; this.IsBetweenCreateEvents = true;
this.Monitor.Log("Context: before save creation.", LogLevel.Trace); this.Monitor.Log("Context: before save creation.", LogLevel.Trace);
this.Events.SaveCreating.RaiseEmpty(); this.Events.SaveCreating.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_BeforeCreateSave.Raise(); this.Events.Legacy_BeforeCreateSave.Raise();
#endif
} }
// raise before-save // raise before-save
@ -373,14 +385,18 @@ namespace StardewModdingAPI.Framework
this.IsBetweenSaveEvents = true; this.IsBetweenSaveEvents = true;
this.Monitor.Log("Context: before save.", LogLevel.Trace); this.Monitor.Log("Context: before save.", LogLevel.Trace);
this.Events.Saving.RaiseEmpty(); this.Events.Saving.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_BeforeSave.Raise(); this.Events.Legacy_BeforeSave.Raise();
#endif
} }
// suppress non-save events // suppress non-save events
this.Events.UnvalidatedUpdateTicking.Raise(new UnvalidatedUpdateTickingEventArgs(this.TicksElapsed)); this.Events.UnvalidatedUpdateTicking.Raise(new UnvalidatedUpdateTickingEventArgs(this.TicksElapsed));
base.Update(gameTime); base.Update(gameTime);
this.Events.UnvalidatedUpdateTicked.Raise(new UnvalidatedUpdateTickedEventArgs(this.TicksElapsed)); this.Events.UnvalidatedUpdateTicked.Raise(new UnvalidatedUpdateTickedEventArgs(this.TicksElapsed));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_UnvalidatedUpdateTick.Raise(); this.Events.Legacy_UnvalidatedUpdateTick.Raise();
#endif
return; return;
} }
if (this.IsBetweenCreateEvents) if (this.IsBetweenCreateEvents)
@ -389,7 +405,9 @@ namespace StardewModdingAPI.Framework
this.IsBetweenCreateEvents = false; this.IsBetweenCreateEvents = false;
this.Monitor.Log($"Context: after save creation, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace); this.Monitor.Log($"Context: after save creation, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace);
this.Events.SaveCreated.RaiseEmpty(); this.Events.SaveCreated.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_AfterCreateSave.Raise(); this.Events.Legacy_AfterCreateSave.Raise();
#endif
} }
if (this.IsBetweenSaveEvents) if (this.IsBetweenSaveEvents)
{ {
@ -398,9 +416,10 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log($"Context: after save, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace); this.Monitor.Log($"Context: after save, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace);
this.Events.Saved.RaiseEmpty(); this.Events.Saved.RaiseEmpty();
this.Events.DayStarted.RaiseEmpty(); this.Events.DayStarted.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_AfterSave.Raise(); this.Events.Legacy_AfterSave.Raise();
this.Events.Legacy_AfterDayStarted.Raise(); this.Events.Legacy_AfterDayStarted.Raise();
#endif
} }
/********* /*********
@ -430,7 +449,11 @@ namespace StardewModdingAPI.Framework
var now = this.Watchers.LocaleWatcher.CurrentValue; var now = this.Watchers.LocaleWatcher.CurrentValue;
this.Monitor.Log($"Context: locale set to {now}.", LogLevel.Trace); this.Monitor.Log($"Context: locale set to {now}.", LogLevel.Trace);
this.OnLocaleChanged();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_LocaleChanged.Raise(new EventArgsValueChanged<string>(was.ToString(), now.ToString())); this.Events.Legacy_LocaleChanged.Raise(new EventArgsValueChanged<string>(was.ToString(), now.ToString()));
#endif
this.Watchers.LocaleWatcher.Reset(); this.Watchers.LocaleWatcher.Reset();
} }
@ -457,9 +480,10 @@ namespace StardewModdingAPI.Framework
this.RaisedAfterLoadEvent = true; this.RaisedAfterLoadEvent = true;
this.Events.SaveLoaded.RaiseEmpty(); this.Events.SaveLoaded.RaiseEmpty();
this.Events.DayStarted.RaiseEmpty(); this.Events.DayStarted.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_AfterLoad.Raise(); this.Events.Legacy_AfterLoad.Raise();
this.Events.Legacy_AfterDayStarted.Raise(); this.Events.Legacy_AfterDayStarted.Raise();
#endif
} }
/********* /*********
@ -478,7 +502,9 @@ namespace StardewModdingAPI.Framework
Point newSize = this.Watchers.WindowSizeWatcher.CurrentValue; Point newSize = this.Watchers.WindowSizeWatcher.CurrentValue;
this.Events.WindowResized.Raise(new WindowResizedEventArgs(oldSize, newSize)); this.Events.WindowResized.Raise(new WindowResizedEventArgs(oldSize, newSize));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_Resize.Raise(); this.Events.Legacy_Resize.Raise();
#endif
this.Watchers.WindowSizeWatcher.Reset(); this.Watchers.WindowSizeWatcher.Reset();
} }
@ -527,9 +553,10 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log($"Events: button {button} pressed.", LogLevel.Trace); this.Monitor.Log($"Events: button {button} pressed.", LogLevel.Trace);
this.Events.ButtonPressed.Raise(new ButtonPressedEventArgs(button, cursor, inputState)); this.Events.ButtonPressed.Raise(new ButtonPressedEventArgs(button, cursor, inputState));
this.Events.Legacy_ButtonPressed.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons));
#if !SMAPI_3_0_STRICT
// legacy events // legacy events
this.Events.Legacy_ButtonPressed.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons));
if (button.TryGetKeyboard(out Keys key)) if (button.TryGetKeyboard(out Keys key))
{ {
if (key != Keys.None) if (key != Keys.None)
@ -542,6 +569,7 @@ namespace StardewModdingAPI.Framework
else else
this.Events.Legacy_ControllerButtonPressed.Raise(new EventArgsControllerButtonPressed(PlayerIndex.One, controllerButton)); this.Events.Legacy_ControllerButtonPressed.Raise(new EventArgsControllerButtonPressed(PlayerIndex.One, controllerButton));
} }
#endif
} }
else if (status == InputStatus.Released) else if (status == InputStatus.Released)
{ {
@ -549,9 +577,10 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log($"Events: button {button} released.", LogLevel.Trace); this.Monitor.Log($"Events: button {button} released.", LogLevel.Trace);
this.Events.ButtonReleased.Raise(new ButtonReleasedEventArgs(button, cursor, inputState)); this.Events.ButtonReleased.Raise(new ButtonReleasedEventArgs(button, cursor, inputState));
this.Events.Legacy_ButtonReleased.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons));
#if !SMAPI_3_0_STRICT
// legacy events // legacy events
this.Events.Legacy_ButtonReleased.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons));
if (button.TryGetKeyboard(out Keys key)) if (button.TryGetKeyboard(out Keys key))
{ {
if (key != Keys.None) if (key != Keys.None)
@ -564,14 +593,17 @@ namespace StardewModdingAPI.Framework
else else
this.Events.Legacy_ControllerButtonReleased.Raise(new EventArgsControllerButtonReleased(PlayerIndex.One, controllerButton)); this.Events.Legacy_ControllerButtonReleased.Raise(new EventArgsControllerButtonReleased(PlayerIndex.One, controllerButton));
} }
#endif
} }
} }
#if !SMAPI_3_0_STRICT
// raise legacy state-changed events // raise legacy state-changed events
if (inputState.RealKeyboard != previousInputState.RealKeyboard) if (inputState.RealKeyboard != previousInputState.RealKeyboard)
this.Events.Legacy_KeyboardChanged.Raise(new EventArgsKeyboardStateChanged(previousInputState.RealKeyboard, inputState.RealKeyboard)); this.Events.Legacy_KeyboardChanged.Raise(new EventArgsKeyboardStateChanged(previousInputState.RealKeyboard, inputState.RealKeyboard));
if (inputState.RealMouse != previousInputState.RealMouse) if (inputState.RealMouse != previousInputState.RealMouse)
this.Events.Legacy_MouseChanged.Raise(new EventArgsMouseStateChanged(previousInputState.RealMouse, inputState.RealMouse, new Point((int)previousInputState.CursorPosition.ScreenPixels.X, (int)previousInputState.CursorPosition.ScreenPixels.Y), new Point((int)inputState.CursorPosition.ScreenPixels.X, (int)inputState.CursorPosition.ScreenPixels.Y))); this.Events.Legacy_MouseChanged.Raise(new EventArgsMouseStateChanged(previousInputState.RealMouse, inputState.RealMouse, new Point((int)previousInputState.CursorPosition.ScreenPixels.X, (int)previousInputState.CursorPosition.ScreenPixels.Y), new Point((int)inputState.CursorPosition.ScreenPixels.X, (int)inputState.CursorPosition.ScreenPixels.Y)));
#endif
} }
} }
@ -589,10 +621,12 @@ namespace StardewModdingAPI.Framework
// raise menu events // raise menu events
this.Events.MenuChanged.Raise(new MenuChangedEventArgs(was, now)); this.Events.MenuChanged.Raise(new MenuChangedEventArgs(was, now));
#if !SMAPI_3_0_STRICT
if (now != null) if (now != null)
this.Events.Legacy_MenuChanged.Raise(new EventArgsClickableMenuChanged(was, now)); this.Events.Legacy_MenuChanged.Raise(new EventArgsClickableMenuChanged(was, now));
else else
this.Events.Legacy_MenuClosed.Raise(new EventArgsClickableMenuClosed(was)); this.Events.Legacy_MenuClosed.Raise(new EventArgsClickableMenuClosed(was));
#endif
} }
/********* /*********
@ -620,7 +654,9 @@ namespace StardewModdingAPI.Framework
} }
this.Events.LocationListChanged.Raise(new LocationListChangedEventArgs(added, removed)); this.Events.LocationListChanged.Raise(new LocationListChangedEventArgs(added, removed));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_LocationsChanged.Raise(new EventArgsLocationsChanged(added, removed)); this.Events.Legacy_LocationsChanged.Raise(new EventArgsLocationsChanged(added, removed));
#endif
} }
// raise location contents changed // raise location contents changed
@ -637,7 +673,9 @@ namespace StardewModdingAPI.Framework
watcher.BuildingsWatcher.Reset(); watcher.BuildingsWatcher.Reset();
this.Events.BuildingListChanged.Raise(new BuildingListChangedEventArgs(location, added, removed)); this.Events.BuildingListChanged.Raise(new BuildingListChangedEventArgs(location, added, removed));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); this.Events.Legacy_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed));
#endif
} }
// debris changed // debris changed
@ -682,7 +720,9 @@ namespace StardewModdingAPI.Framework
watcher.ObjectsWatcher.Reset(); watcher.ObjectsWatcher.Reset();
this.Events.ObjectListChanged.Raise(new ObjectListChangedEventArgs(location, added, removed)); this.Events.ObjectListChanged.Raise(new ObjectListChangedEventArgs(location, added, removed));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed)); this.Events.Legacy_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed));
#endif
} }
// terrain features changed // terrain features changed
@ -712,7 +752,9 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log($"Events: time changed from {was} to {now}.", LogLevel.Trace); this.Monitor.Log($"Events: time changed from {was} to {now}.", LogLevel.Trace);
this.Events.TimeChanged.Raise(new TimeChangedEventArgs(was, now)); this.Events.TimeChanged.Raise(new TimeChangedEventArgs(was, now));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_TimeOfDayChanged.Raise(new EventArgsIntChanged(was, now)); this.Events.Legacy_TimeOfDayChanged.Raise(new EventArgsIntChanged(was, now));
#endif
} }
else else
this.Watchers.TimeWatcher.Reset(); this.Watchers.TimeWatcher.Reset();
@ -730,7 +772,9 @@ namespace StardewModdingAPI.Framework
GameLocation oldLocation = playerTracker.LocationWatcher.PreviousValue; GameLocation oldLocation = playerTracker.LocationWatcher.PreviousValue;
this.Events.Warped.Raise(new WarpedEventArgs(playerTracker.Player, oldLocation, newLocation)); this.Events.Warped.Raise(new WarpedEventArgs(playerTracker.Player, oldLocation, newLocation));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_PlayerWarped.Raise(new EventArgsPlayerWarped(oldLocation, newLocation)); this.Events.Legacy_PlayerWarped.Raise(new EventArgsPlayerWarped(oldLocation, newLocation));
#endif
} }
// raise player leveled up a skill // raise player leveled up a skill
@ -740,7 +784,9 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log($"Events: player skill '{pair.Key}' changed from {pair.Value.PreviousValue} to {pair.Value.CurrentValue}.", LogLevel.Trace); this.Monitor.Log($"Events: player skill '{pair.Key}' changed from {pair.Value.PreviousValue} to {pair.Value.CurrentValue}.", LogLevel.Trace);
this.Events.LevelChanged.Raise(new LevelChangedEventArgs(playerTracker.Player, pair.Key, pair.Value.PreviousValue, pair.Value.CurrentValue)); this.Events.LevelChanged.Raise(new LevelChangedEventArgs(playerTracker.Player, pair.Key, pair.Value.PreviousValue, pair.Value.CurrentValue));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_LeveledUp.Raise(new EventArgsLevelUp((EventArgsLevelUp.LevelType)pair.Key, pair.Value.CurrentValue)); this.Events.Legacy_LeveledUp.Raise(new EventArgsLevelUp((EventArgsLevelUp.LevelType)pair.Key, pair.Value.CurrentValue));
#endif
} }
// raise player inventory changed // raise player inventory changed
@ -750,7 +796,9 @@ namespace StardewModdingAPI.Framework
if (this.Monitor.IsVerbose) if (this.Monitor.IsVerbose)
this.Monitor.Log("Events: player inventory changed.", LogLevel.Trace); this.Monitor.Log("Events: player inventory changed.", LogLevel.Trace);
this.Events.InventoryChanged.Raise(new InventoryChangedEventArgs(playerTracker.Player, changedItems)); this.Events.InventoryChanged.Raise(new InventoryChangedEventArgs(playerTracker.Player, changedItems));
#if !SMAPI_3_0_STRICT
this.Events.Legacy_InventoryChanged.Raise(new EventArgsInventoryChanged(Game1.player.Items, changedItems)); this.Events.Legacy_InventoryChanged.Raise(new EventArgsInventoryChanged(Game1.player.Items, changedItems));
#endif
} }
// raise mine level changed // raise mine level changed
@ -758,7 +806,9 @@ namespace StardewModdingAPI.Framework
{ {
if (this.Monitor.IsVerbose) if (this.Monitor.IsVerbose)
this.Monitor.Log($"Context: mine level changed to {mineLevel}.", LogLevel.Trace); this.Monitor.Log($"Context: mine level changed to {mineLevel}.", LogLevel.Trace);
#if !SMAPI_3_0_STRICT
this.Events.Legacy_MineLevelChanged.Raise(new EventArgsMineLevelChanged(playerTracker.MineLevelWatcher.PreviousValue, mineLevel)); this.Events.Legacy_MineLevelChanged.Raise(new EventArgsMineLevelChanged(playerTracker.MineLevelWatcher.PreviousValue, mineLevel));
#endif
} }
} }
this.Watchers.CurrentPlayerTracker?.Reset(); this.Watchers.CurrentPlayerTracker?.Reset();
@ -790,6 +840,7 @@ namespace StardewModdingAPI.Framework
/********* /*********
** Update events ** Update events
*********/ *********/
#if !SMAPI_3_0_STRICT
this.Events.Legacy_UnvalidatedUpdateTick.Raise(); this.Events.Legacy_UnvalidatedUpdateTick.Raise();
if (this.TicksElapsed == 1) if (this.TicksElapsed == 1)
this.Events.Legacy_FirstUpdateTick.Raise(); this.Events.Legacy_FirstUpdateTick.Raise();
@ -806,6 +857,7 @@ namespace StardewModdingAPI.Framework
this.Events.Legacy_HalfSecondTick.Raise(); this.Events.Legacy_HalfSecondTick.Raise();
if (this.CurrentUpdateTick % 60 == 0) if (this.CurrentUpdateTick % 60 == 0)
this.Events.Legacy_OneSecondTick.Raise(); this.Events.Legacy_OneSecondTick.Raise();
#endif
this.CurrentUpdateTick += 1; this.CurrentUpdateTick += 1;
if (this.CurrentUpdateTick >= 60) if (this.CurrentUpdateTick >= 60)
this.CurrentUpdateTick = 0; this.CurrentUpdateTick = 0;
@ -895,10 +947,14 @@ namespace StardewModdingAPI.Framework
try try
{ {
this.Events.RenderingActiveMenu.RaiseEmpty(); this.Events.RenderingActiveMenu.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPreRenderGuiEvent.Raise(); this.Events.Legacy_OnPreRenderGuiEvent.Raise();
#endif
activeClickableMenu.draw(Game1.spriteBatch); activeClickableMenu.draw(Game1.spriteBatch);
this.Events.RenderedActiveMenu.RaiseEmpty(); this.Events.RenderedActiveMenu.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPostRenderGuiEvent.Raise(); this.Events.Legacy_OnPostRenderGuiEvent.Raise();
#endif
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -906,7 +962,9 @@ namespace StardewModdingAPI.Framework
activeClickableMenu.exitThisMenu(); activeClickableMenu.exitThisMenu();
} }
this.Events.Rendered.RaiseEmpty(); this.Events.Rendered.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPostRenderEvent.Raise(); this.Events.Legacy_OnPostRenderEvent.Raise();
#endif
Game1.spriteBatch.End(); Game1.spriteBatch.End();
} }
@ -930,10 +988,14 @@ namespace StardewModdingAPI.Framework
{ {
Game1.activeClickableMenu.drawBackground(Game1.spriteBatch); Game1.activeClickableMenu.drawBackground(Game1.spriteBatch);
this.Events.RenderingActiveMenu.RaiseEmpty(); this.Events.RenderingActiveMenu.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPreRenderGuiEvent.Raise(); this.Events.Legacy_OnPreRenderGuiEvent.Raise();
#endif
Game1.activeClickableMenu.draw(Game1.spriteBatch); Game1.activeClickableMenu.draw(Game1.spriteBatch);
this.Events.RenderedActiveMenu.RaiseEmpty(); this.Events.RenderedActiveMenu.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPostRenderGuiEvent.Raise(); this.Events.Legacy_OnPostRenderGuiEvent.Raise();
#endif
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -941,7 +1003,9 @@ namespace StardewModdingAPI.Framework
Game1.activeClickableMenu.exitThisMenu(); Game1.activeClickableMenu.exitThisMenu();
} }
this.Events.Rendered.RaiseEmpty(); this.Events.Rendered.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPostRenderEvent.Raise(); this.Events.Legacy_OnPostRenderEvent.Raise();
#endif
Game1.spriteBatch.End(); Game1.spriteBatch.End();
this.drawOverlays(Game1.spriteBatch); this.drawOverlays(Game1.spriteBatch);
if ((double)Game1.options.zoomLevel != 1.0) if ((double)Game1.options.zoomLevel != 1.0)
@ -966,7 +1030,9 @@ namespace StardewModdingAPI.Framework
Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3686"), new Vector2(16f, 32f), new Color(0, (int)byte.MaxValue, 0)); Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3686"), new Vector2(16f, 32f), new Color(0, (int)byte.MaxValue, 0));
Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.parseText(Game1.errorMessage, Game1.dialogueFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White); Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.parseText(Game1.errorMessage, Game1.dialogueFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White);
this.Events.Rendered.RaiseEmpty(); this.Events.Rendered.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPostRenderEvent.Raise(); this.Events.Legacy_OnPostRenderEvent.Raise();
#endif
Game1.spriteBatch.End(); Game1.spriteBatch.End();
} }
else if (Game1.currentMinigame != null) else if (Game1.currentMinigame != null)
@ -979,7 +1045,9 @@ namespace StardewModdingAPI.Framework
Game1.spriteBatch.End(); Game1.spriteBatch.End();
} }
this.drawOverlays(Game1.spriteBatch); this.drawOverlays(Game1.spriteBatch);
#if !SMAPI_3_0_STRICT
this.RaisePostRender(needsNewBatch: true); this.RaisePostRender(needsNewBatch: true);
#endif
if ((double)Game1.options.zoomLevel == 1.0) if ((double)Game1.options.zoomLevel == 1.0)
return; return;
this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null);
@ -997,10 +1065,14 @@ namespace StardewModdingAPI.Framework
try try
{ {
this.Events.RenderingActiveMenu.RaiseEmpty(); this.Events.RenderingActiveMenu.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPreRenderGuiEvent.Raise(); this.Events.Legacy_OnPreRenderGuiEvent.Raise();
#endif
Game1.activeClickableMenu.draw(Game1.spriteBatch); Game1.activeClickableMenu.draw(Game1.spriteBatch);
this.Events.RenderedActiveMenu.RaiseEmpty(); this.Events.RenderedActiveMenu.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPostRenderGuiEvent.Raise(); this.Events.Legacy_OnPostRenderGuiEvent.Raise();
#endif
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1090,7 +1162,9 @@ namespace StardewModdingAPI.Framework
if (++batchOpens == 1) if (++batchOpens == 1)
this.Events.Rendering.RaiseEmpty(); this.Events.Rendering.RaiseEmpty();
this.Events.RenderingWorld.RaiseEmpty(); this.Events.RenderingWorld.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPreRenderEvent.Raise(); this.Events.Legacy_OnPreRenderEvent.Raise();
#endif
if (Game1.background != null) if (Game1.background != null)
Game1.background.draw(Game1.spriteBatch); Game1.background.draw(Game1.spriteBatch);
Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch);
@ -1403,10 +1477,14 @@ namespace StardewModdingAPI.Framework
if ((Game1.displayHUD || Game1.eventUp) && (Game1.currentBillboard == 0 && Game1.gameMode == (byte)3) && (!Game1.freezeControls && !Game1.panMode && !Game1.HostPaused)) if ((Game1.displayHUD || Game1.eventUp) && (Game1.currentBillboard == 0 && Game1.gameMode == (byte)3) && (!Game1.freezeControls && !Game1.panMode && !Game1.HostPaused))
{ {
this.Events.RenderingHud.RaiseEmpty(); this.Events.RenderingHud.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPreRenderHudEvent.Raise(); this.Events.Legacy_OnPreRenderHudEvent.Raise();
#endif
this.drawHUD(); this.drawHUD();
this.Events.RenderedHud.RaiseEmpty(); this.Events.RenderedHud.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPostRenderHudEvent.Raise(); this.Events.Legacy_OnPostRenderHudEvent.Raise();
#endif
} }
else if (Game1.activeClickableMenu == null && Game1.farmEvent == null) else if (Game1.activeClickableMenu == null && Game1.farmEvent == null)
Game1.spriteBatch.Draw(Game1.mouseCursors, new Vector2((float)Game1.getOldMouseX(), (float)Game1.getOldMouseY()), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 0, 16, 16)), Color.White, 0.0f, Vector2.Zero, (float)(4.0 + (double)Game1.dialogueButtonScale / 150.0), SpriteEffects.None, 1f); Game1.spriteBatch.Draw(Game1.mouseCursors, new Vector2((float)Game1.getOldMouseX(), (float)Game1.getOldMouseY()), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 0, 16, 16)), Color.White, 0.0f, Vector2.Zero, (float)(4.0 + (double)Game1.dialogueButtonScale / 150.0), SpriteEffects.None, 1f);
@ -1515,10 +1593,14 @@ namespace StardewModdingAPI.Framework
try try
{ {
this.Events.RenderingActiveMenu.RaiseEmpty(); this.Events.RenderingActiveMenu.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPreRenderGuiEvent.Raise(); this.Events.Legacy_OnPreRenderGuiEvent.Raise();
#endif
Game1.activeClickableMenu.draw(Game1.spriteBatch); Game1.activeClickableMenu.draw(Game1.spriteBatch);
this.Events.RenderedActiveMenu.RaiseEmpty(); this.Events.RenderedActiveMenu.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPostRenderGuiEvent.Raise(); this.Events.Legacy_OnPostRenderGuiEvent.Raise();
#endif
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1535,7 +1617,9 @@ namespace StardewModdingAPI.Framework
} }
this.Events.Rendered.RaiseEmpty(); this.Events.Rendered.RaiseEmpty();
#if !SMAPI_3_0_STRICT
this.Events.Legacy_OnPostRenderEvent.Raise(); this.Events.Legacy_OnPostRenderEvent.Raise();
#endif
Game1.spriteBatch.End(); Game1.spriteBatch.End();
this.drawOverlays(Game1.spriteBatch); this.drawOverlays(Game1.spriteBatch);
this.renderScreenBuffer(); this.renderScreenBuffer();
@ -1555,6 +1639,7 @@ namespace StardewModdingAPI.Framework
this.RaisedAfterLoadEvent = false; this.RaisedAfterLoadEvent = false;
} }
#if !SMAPI_3_0_STRICT
/// <summary>Raise the <see cref="GraphicsEvents.OnPostRenderEvent"/> if there are any listeners.</summary> /// <summary>Raise the <see cref="GraphicsEvents.OnPostRenderEvent"/> if there are any listeners.</summary>
/// <param name="needsNewBatch">Whether to create a new sprite batch.</param> /// <param name="needsNewBatch">Whether to create a new sprite batch.</param>
private void RaisePostRender(bool needsNewBatch = false) private void RaisePostRender(bool needsNewBatch = false)
@ -1568,5 +1653,6 @@ namespace StardewModdingAPI.Framework
Game1.spriteBatch.End(); Game1.spriteBatch.End();
} }
} }
#endif
} }
} }

View File

@ -82,6 +82,7 @@ namespace StardewModdingAPI.Framework
this.OnModMessageReceived = onModMessageReceived; this.OnModMessageReceived = onModMessageReceived;
} }
#if !SMAPI_3_0_STRICT
/// <summary>Handle sync messages from other players and perform other initial sync logic.</summary> /// <summary>Handle sync messages from other players and perform other initial sync logic.</summary>
public override void UpdateEarly() public override void UpdateEarly()
{ {
@ -97,6 +98,7 @@ namespace StardewModdingAPI.Framework
base.UpdateLate(forceSync); base.UpdateLate(forceSync);
this.EventManager.Legacy_AfterMainBroadcast.Raise(); this.EventManager.Legacy_AfterMainBroadcast.Raise();
} }
#endif
/// <summary>Initialise a client before the game connects to a remote server.</summary> /// <summary>Initialise a client before the game connects to a remote server.</summary>
/// <param name="client">The client to initialise.</param> /// <param name="client">The client to initialise.</param>

View File

@ -56,6 +56,7 @@ namespace StardewModdingAPI
/// <param name="config">The config settings to save.</param> /// <param name="config">The config settings to save.</param>
void WriteConfig<TConfig>(TConfig config) where TConfig : class, new(); void WriteConfig<TConfig>(TConfig config) where TConfig : class, new();
#if !SMAPI_3_0_STRICT
/**** /****
** Generic JSON files ** Generic JSON files
****/ ****/
@ -88,5 +89,6 @@ namespace StardewModdingAPI
/// <summary>Get all content packs loaded for this mod.</summary> /// <summary>Get all content packs loaded for this mod.</summary>
IEnumerable<IContentPack> GetContentPacks(); IEnumerable<IContentPack> GetContentPacks();
#endif
} }
} }

View File

@ -52,7 +52,10 @@ namespace StardewModdingAPI.Metadata
new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.serializer), InstructionHandleResult.DetectedSaveSerialiser), new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.serializer), InstructionHandleResult.DetectedSaveSerialiser),
new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.farmerSerializer), InstructionHandleResult.DetectedSaveSerialiser), new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.farmerSerializer), InstructionHandleResult.DetectedSaveSerialiser),
new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.locationSerializer), InstructionHandleResult.DetectedSaveSerialiser), new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.locationSerializer), InstructionHandleResult.DetectedSaveSerialiser),
new TypeFinder(typeof(ISpecialisedEvents).FullName, InstructionHandleResult.DetectedUnvalidatedUpdateTick),
#if !SMAPI_3_0_STRICT
new EventFinder(typeof(SpecialisedEvents).FullName, nameof(SpecialisedEvents.UnvalidatedUpdateTick), InstructionHandleResult.DetectedUnvalidatedUpdateTick), new EventFinder(typeof(SpecialisedEvents).FullName, nameof(SpecialisedEvents.UnvalidatedUpdateTick), InstructionHandleResult.DetectedUnvalidatedUpdateTick),
#endif
/**** /****
** detect paranoid issues ** detect paranoid issues

View File

@ -29,6 +29,7 @@ namespace StardewModdingAPI
/// <summary>The patch version for backwards-compatible bug fixes.</summary> /// <summary>The patch version for backwards-compatible bug fixes.</summary>
public int PatchVersion => this.Version.PatchVersion; public int PatchVersion => this.Version.PatchVersion;
#if !SMAPI_3_0_STRICT
/// <summary>An optional build tag.</summary> /// <summary>An optional build tag.</summary>
[Obsolete("Use " + nameof(ISemanticVersion.PrereleaseTag) + " instead")] [Obsolete("Use " + nameof(ISemanticVersion.PrereleaseTag) + " instead")]
public string Build public string Build
@ -39,6 +40,7 @@ namespace StardewModdingAPI
return this.Version.PrereleaseTag; return this.Version.PrereleaseTag;
} }
} }
#endif
/// <summary>An optional prerelease tag.</summary> /// <summary>An optional prerelease tag.</summary>
public string PrereleaseTag => this.Version.PrereleaseTag; public string PrereleaseTag => this.Version.PrereleaseTag;

View File

@ -32,7 +32,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE;SMAPI_3_0_STRICT</DefineConstants>
<UseVSHostingProcess>true</UseVSHostingProcess> <UseVSHostingProcess>true</UseVSHostingProcess>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>$(SolutionDir)\..\bin\Debug\SMAPI</OutputPath> <OutputPath>$(SolutionDir)\..\bin\Debug\SMAPI</OutputPath>

View File

@ -17,9 +17,11 @@ namespace StardewModdingAPI
/// <summary>The patch version for backwards-compatible bug fixes.</summary> /// <summary>The patch version for backwards-compatible bug fixes.</summary>
int PatchVersion { get; } int PatchVersion { get; }
#if !SMAPI_3_0_STRICT
/// <summary>An optional build tag.</summary> /// <summary>An optional build tag.</summary>
[Obsolete("Use " + nameof(ISemanticVersion.PrereleaseTag) + " instead")] [Obsolete("Use " + nameof(ISemanticVersion.PrereleaseTag) + " instead")]
string Build { get; } string Build { get; }
#endif
/// <summary>An optional prerelease tag.</summary> /// <summary>An optional prerelease tag.</summary>
string PrereleaseTag { get; } string PrereleaseTag { get; }

View File

@ -8,6 +8,10 @@
<DocumentationFile>..\..\bin\$(Configuration)\SMAPI.Toolkit.CoreInterfaces\$(TargetFramework)\StardewModdingAPI.Toolkit.CoreInterfaces.xml</DocumentationFile> <DocumentationFile>..\..\bin\$(Configuration)\SMAPI.Toolkit.CoreInterfaces\$(TargetFramework)\StardewModdingAPI.Toolkit.CoreInterfaces.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineConstants>$(DefineConstants);SMAPI_3_0_STRICT</DefineConstants>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\..\build\GlobalAssemblyInfo.cs" Link="Properties\GlobalAssemblyInfo.cs" /> <Compile Include="..\..\build\GlobalAssemblyInfo.cs" Link="Properties\GlobalAssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

View File

@ -39,9 +39,11 @@ namespace StardewModdingAPI.Toolkit
/// <summary>The patch version for backwards-compatible bug fixes.</summary> /// <summary>The patch version for backwards-compatible bug fixes.</summary>
public int PatchVersion { get; } public int PatchVersion { get; }
#if !SMAPI_3_0_STRICT
/// <summary>An optional prerelease tag.</summary> /// <summary>An optional prerelease tag.</summary>
[Obsolete("Use " + nameof(ISemanticVersion.PrereleaseTag) + " instead")] [Obsolete("Use " + nameof(ISemanticVersion.PrereleaseTag) + " instead")]
public string Build => this.PrereleaseTag; public string Build => this.PrereleaseTag;
#endif
/// <summary>An optional prerelease tag.</summary> /// <summary>An optional prerelease tag.</summary>
public string PrereleaseTag { get; } public string PrereleaseTag { get; }
@ -114,7 +116,7 @@ namespace StardewModdingAPI.Toolkit
{ {
if (other == null) if (other == null)
throw new ArgumentNullException(nameof(other)); throw new ArgumentNullException(nameof(other));
return this.CompareTo(other.MajorVersion, other.MinorVersion, other.PatchVersion, other.Build); return this.CompareTo(other.MajorVersion, other.MinorVersion, other.PatchVersion, other.PrereleaseTag);
} }
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary> /// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
@ -128,7 +130,7 @@ namespace StardewModdingAPI.Toolkit
/// <summary>Whether this is a pre-release version.</summary> /// <summary>Whether this is a pre-release version.</summary>
public bool IsPrerelease() public bool IsPrerelease()
{ {
return !string.IsNullOrWhiteSpace(this.Build); return !string.IsNullOrWhiteSpace(this.PrereleaseTag);
} }
/// <summary>Get whether this version is older than the specified version.</summary> /// <summary>Get whether this version is older than the specified version.</summary>
@ -187,7 +189,7 @@ namespace StardewModdingAPI.Toolkit
: $"{this.MajorVersion}.{this.MinorVersion}"; : $"{this.MajorVersion}.{this.MinorVersion}";
// tag // tag
string tag = this.Build; string tag = this.PrereleaseTag;
if (tag != null) if (tag != null)
result += $"-{tag}"; result += $"-{tag}";
return result; return result;
@ -241,11 +243,11 @@ namespace StardewModdingAPI.Toolkit
return this.MinorVersion.CompareTo(otherMinor); return this.MinorVersion.CompareTo(otherMinor);
if (this.PatchVersion != otherPatch) if (this.PatchVersion != otherPatch)
return this.PatchVersion.CompareTo(otherPatch); return this.PatchVersion.CompareTo(otherPatch);
if (this.Build == otherTag) if (this.PrereleaseTag == otherTag)
return same; return same;
// stable supercedes pre-release // stable supercedes pre-release
bool curIsStable = string.IsNullOrWhiteSpace(this.Build); bool curIsStable = string.IsNullOrWhiteSpace(this.PrereleaseTag);
bool otherIsStable = string.IsNullOrWhiteSpace(otherTag); bool otherIsStable = string.IsNullOrWhiteSpace(otherTag);
if (curIsStable) if (curIsStable)
return curNewer; return curNewer;
@ -253,7 +255,7 @@ namespace StardewModdingAPI.Toolkit
return curOlder; return curOlder;
// compare two pre-release tag values // compare two pre-release tag values
string[] curParts = this.Build.Split('.', '-'); string[] curParts = this.PrereleaseTag.Split('.', '-');
string[] otherParts = otherTag.Split('.', '-'); string[] otherParts = otherTag.Split('.', '-');
for (int i = 0; i < curParts.Length; i++) for (int i = 0; i < curParts.Length; i++)
{ {
@ -292,11 +294,11 @@ namespace StardewModdingAPI.Toolkit
throw new FormatException($"{this} isn't a valid semantic version. The major, minor, and patch numbers can't be negative."); throw new FormatException($"{this} isn't a valid semantic version. The major, minor, and patch numbers can't be negative.");
if (this.MajorVersion == 0 && this.MinorVersion == 0 && this.PatchVersion == 0) if (this.MajorVersion == 0 && this.MinorVersion == 0 && this.PatchVersion == 0)
throw new FormatException($"{this} isn't a valid semantic version. At least one of the major, minor, and patch numbers must be more than zero."); throw new FormatException($"{this} isn't a valid semantic version. At least one of the major, minor, and patch numbers must be more than zero.");
if (this.Build != null) if (this.PrereleaseTag != null)
{ {
if (this.Build.Trim() == "") if (this.PrereleaseTag.Trim() == "")
throw new FormatException($"{this} isn't a valid semantic version. The tag cannot be a blank string (but may be omitted)."); throw new FormatException($"{this} isn't a valid semantic version. The tag cannot be a blank string (but may be omitted).");
if (!Regex.IsMatch(this.Build, $"^{SemanticVersion.TagPattern}$", RegexOptions.IgnoreCase)) if (!Regex.IsMatch(this.PrereleaseTag, $"^{SemanticVersion.TagPattern}$", RegexOptions.IgnoreCase))
throw new FormatException($"{this} isn't a valid semantic version. The tag is invalid."); throw new FormatException($"{this} isn't a valid semantic version. The tag is invalid.");
} }
} }

View File

@ -7,6 +7,10 @@
<DocumentationFile>..\..\bin\$(Configuration)\SMAPI.Toolkit\$(TargetFramework)\StardewModdingAPI.Toolkit.xml</DocumentationFile> <DocumentationFile>..\..\bin\$(Configuration)\SMAPI.Toolkit\$(TargetFramework)\StardewModdingAPI.Toolkit.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineConstants>$(DefineConstants);SMAPI_3_0_STRICT</DefineConstants>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\..\build\GlobalAssemblyInfo.cs" Link="Properties\GlobalAssemblyInfo.cs" /> <Compile Include="..\..\build\GlobalAssemblyInfo.cs" Link="Properties\GlobalAssemblyInfo.cs" />
</ItemGroup> </ItemGroup>