summaryrefslogtreecommitdiff
path: root/src/StardewModdingAPI
diff options
context:
space:
mode:
Diffstat (limited to 'src/StardewModdingAPI')
-rw-r--r--src/StardewModdingAPI/Constants.cs2
-rw-r--r--src/StardewModdingAPI/Framework/ModRegistry.cs29
-rw-r--r--src/StardewModdingAPI/IModHelper.cs3
-rw-r--r--src/StardewModdingAPI/IModRegistry.cs20
-rw-r--r--src/StardewModdingAPI/Inheritance/SGame.cs218
-rw-r--r--src/StardewModdingAPI/Inheritance/SObject.cs2
-rw-r--r--src/StardewModdingAPI/LogWriter.cs2
-rw-r--r--src/StardewModdingAPI/Mod.cs2
-rw-r--r--src/StardewModdingAPI/ModHelper.cs13
-rw-r--r--src/StardewModdingAPI/Program.cs36
-rw-r--r--src/StardewModdingAPI/StardewModdingAPI.csproj1
-rw-r--r--src/StardewModdingAPI/Version.cs2
12 files changed, 205 insertions, 125 deletions
diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs
index 2211e167..df527dfe 100644
--- a/src/StardewModdingAPI/Constants.cs
+++ b/src/StardewModdingAPI/Constants.cs
@@ -30,7 +30,7 @@ namespace StardewModdingAPI
public static readonly Version Version = (Version)Constants.ApiVersion;
/// <summary>SMAPI's current semantic version.</summary>
- public static ISemanticVersion ApiVersion => new Version(1, 6, 0, null, suppressDeprecationWarning: true);
+ public static ISemanticVersion ApiVersion => new Version(1, 7, 0, null, suppressDeprecationWarning: true);
/// <summary>The minimum supported version of Stardew Valley.</summary>
public const string MinimumGameVersion = "1.1";
diff --git a/src/StardewModdingAPI/Framework/ModRegistry.cs b/src/StardewModdingAPI/Framework/ModRegistry.cs
index 51ec7123..209f1928 100644
--- a/src/StardewModdingAPI/Framework/ModRegistry.cs
+++ b/src/StardewModdingAPI/Framework/ModRegistry.cs
@@ -7,7 +7,7 @@ using System.Reflection;
namespace StardewModdingAPI.Framework
{
/// <summary>Tracks the installed mods.</summary>
- internal class ModRegistry
+ internal class ModRegistry : IModRegistry
{
/*********
** Properties
@@ -22,6 +22,33 @@ namespace StardewModdingAPI.Framework
/*********
** Public methods
*********/
+ /****
+ ** IModRegistry
+ ****/
+ /// <summary>Get metadata for all loaded mods.</summary>
+ public IEnumerable<IManifest> GetAll()
+ {
+ return this.Mods.Select(p => p.ModManifest);
+ }
+
+ /// <summary>Get metadata for a loaded mod.</summary>
+ /// <param name="uniqueID">The mod's unique ID.</param>
+ /// <returns>Returns the matching mod's metadata, or <c>null</c> if not found.</returns>
+ public IManifest Get(string uniqueID)
+ {
+ return this.GetAll().FirstOrDefault(p => p.UniqueID == uniqueID);
+ }
+
+ /// <summary>Get whether a mod has been loaded.</summary>
+ /// <param name="uniqueID">The mod's unique ID.</param>
+ public bool IsLoaded(string uniqueID)
+ {
+ return this.GetAll().Any(p => p.UniqueID == uniqueID);
+ }
+
+ /****
+ ** Internal methods
+ ****/
/// <summary>Register a mod as a possible source of deprecation warnings.</summary>
/// <param name="mod">The mod instance.</param>
public void Add(IMod mod)
diff --git a/src/StardewModdingAPI/IModHelper.cs b/src/StardewModdingAPI/IModHelper.cs
index 183b3b2b..02f9c038 100644
--- a/src/StardewModdingAPI/IModHelper.cs
+++ b/src/StardewModdingAPI/IModHelper.cs
@@ -12,6 +12,9 @@
/// <summary>Simplifies access to private game code.</summary>
IReflectionHelper Reflection { get; }
+ /// <summary>Metadata about loaded mods.</summary>
+ IModRegistry ModRegistry { get; }
+
/*********
** Public methods
diff --git a/src/StardewModdingAPI/IModRegistry.cs b/src/StardewModdingAPI/IModRegistry.cs
new file mode 100644
index 00000000..676c9734
--- /dev/null
+++ b/src/StardewModdingAPI/IModRegistry.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+
+namespace StardewModdingAPI
+{
+ /// <summary>Provides metadata about loaded mods.</summary>
+ public interface IModRegistry
+ {
+ /// <summary>Get metadata for all loaded mods.</summary>
+ IEnumerable<IManifest> GetAll();
+
+ /// <summary>Get metadata for a loaded mod.</summary>
+ /// <param name="uniqueID">The mod's unique ID.</param>
+ /// <returns>Returns the matching mod's metadata, or <c>null</c> if not found.</returns>
+ IManifest Get(string uniqueID);
+
+ /// <summary>Get whether a mod has been loaded.</summary>
+ /// <param name="uniqueID">The mod's unique ID.</param>
+ bool IsLoaded(string uniqueID);
+ }
+} \ No newline at end of file
diff --git a/src/StardewModdingAPI/Inheritance/SGame.cs b/src/StardewModdingAPI/Inheritance/SGame.cs
index 8e87bac6..69c20244 100644
--- a/src/StardewModdingAPI/Inheritance/SGame.cs
+++ b/src/StardewModdingAPI/Inheritance/SGame.cs
@@ -24,8 +24,12 @@ namespace StardewModdingAPI.Inheritance
/*********
** Properties
*********/
- /// <summary>Whether to raise <see cref="PlayerEvents.LoadedGame"/> on the next tick.</summary>
- private bool FireLoadedGameEvent;
+ /// <summary>The number of ticks until SMAPI should notify mods when <see cref="Game1.hasLoadedGame"/> is set.</summary>
+ /// <remarks>Skipping a few frames ensures the game finishes initialising the world before mods try to change it.</remarks>
+ private int AfterLoadTimer = 5;
+
+ /// <summary>Whether the player has loaded a save and the world has finished initialising.</summary>
+ private bool IsWorldReady => this.AfterLoadTimer < 0;
/// <summary>The debug messages to add to the next debug output.</summary>
internal static Queue<string> DebugMessageQueue { get; private set; }
@@ -860,66 +864,81 @@ namespace StardewModdingAPI.Inheritance
/// <summary>Detect changes since the last update ticket and trigger mod events.</summary>
private void UpdateEventCalls()
{
- // get latest state
- this.KStateNow = Keyboard.GetState();
- this.MStateNow = Mouse.GetState();
- this.MPositionNow = new Point(Game1.getMouseX(), Game1.getMouseY());
-
- // raise key pressed
- foreach (var key in this.FramePressedKeys)
- ControlEvents.InvokeKeyPressed(this.Monitor, key);
-
- // raise key released
- foreach (var key in this.FrameReleasedKeys)
- ControlEvents.InvokeKeyReleased(this.Monitor, key);
-
- // raise controller button pressed
- for (var i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
+ // save loaded event
+ if (Game1.hasLoadedGame && this.AfterLoadTimer >= 0)
{
- var buttons = this.GetFramePressedButtons(i);
- foreach (var button in buttons)
+ if (this.AfterLoadTimer == 0)
{
- if (button == Buttons.LeftTrigger || button == Buttons.RightTrigger)
- ControlEvents.InvokeTriggerPressed(this.Monitor, i, button, button == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
- else
- ControlEvents.InvokeButtonPressed(this.Monitor, i, button);
+ SaveEvents.InvokeAfterLoad(this.Monitor);
+ PlayerEvents.InvokeLoadedGame(this.Monitor, new EventArgsLoadedGameChanged(Game1.hasLoadedGame));
}
+ this.AfterLoadTimer--;
}
- // raise controller button released
- for (var i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
+ // input events
{
- foreach (var button in this.GetFrameReleasedButtons(i))
+ // get latest state
+ this.KStateNow = Keyboard.GetState();
+ this.MStateNow = Mouse.GetState();
+ this.MPositionNow = new Point(Game1.getMouseX(), Game1.getMouseY());
+
+ // raise key pressed
+ foreach (var key in this.FramePressedKeys)
+ ControlEvents.InvokeKeyPressed(this.Monitor, key);
+
+ // raise key released
+ foreach (var key in this.FrameReleasedKeys)
+ ControlEvents.InvokeKeyReleased(this.Monitor, key);
+
+ // raise controller button pressed
+ for (var i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
{
- if (button == Buttons.LeftTrigger || button == Buttons.RightTrigger)
- ControlEvents.InvokeTriggerReleased(this.Monitor, i, button, button == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
- else
- ControlEvents.InvokeButtonReleased(this.Monitor, i, button);
+ var buttons = this.GetFramePressedButtons(i);
+ foreach (var button in buttons)
+ {
+ if (button == Buttons.LeftTrigger || button == Buttons.RightTrigger)
+ ControlEvents.InvokeTriggerPressed(this.Monitor, i, button, button == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
+ else
+ ControlEvents.InvokeButtonPressed(this.Monitor, i, button);
+ }
+ }
+
+ // raise controller button released
+ for (var i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
+ {
+ foreach (var button in this.GetFrameReleasedButtons(i))
+ {
+ if (button == Buttons.LeftTrigger || button == Buttons.RightTrigger)
+ ControlEvents.InvokeTriggerReleased(this.Monitor, i, button, button == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
+ else
+ ControlEvents.InvokeButtonReleased(this.Monitor, i, button);
+ }
}
- }
- // raise keyboard state changed
- if (this.KStateNow != this.KStatePrior)
- ControlEvents.InvokeKeyboardChanged(this.Monitor, this.KStatePrior, this.KStateNow);
+ // raise keyboard state changed
+ if (this.KStateNow != this.KStatePrior)
+ ControlEvents.InvokeKeyboardChanged(this.Monitor, this.KStatePrior, this.KStateNow);
- // raise mouse state changed
- if (this.MStateNow != this.MStatePrior)
- {
- ControlEvents.InvokeMouseChanged(this.Monitor, this.MStatePrior, this.MStateNow, this.MPositionPrior, this.MPositionNow);
- this.MStatePrior = this.MStateNow;
- this.MPositionPrior = this.MPositionPrior;
+ // raise mouse state changed
+ if (this.MStateNow != this.MStatePrior)
+ {
+ ControlEvents.InvokeMouseChanged(this.Monitor, this.MStatePrior, this.MStateNow, this.MPositionPrior, this.MPositionNow);
+ this.MStatePrior = this.MStateNow;
+ this.MPositionPrior = this.MPositionPrior;
+ }
}
- // raise menu changed
+ // menu events
if (Game1.activeClickableMenu != this.PreviousActiveMenu)
{
IClickableMenu previousMenu = this.PreviousActiveMenu;
IClickableMenu newMenu = Game1.activeClickableMenu;
// raise save events
- if (newMenu is SaveGameMenu)
+ // (saving is performed by SaveGameMenu; on days when the player shipping something, ShippingMenu wraps SaveGameMenu)
+ if (newMenu is SaveGameMenu || newMenu is ShippingMenu)
SaveEvents.InvokeBeforeSave(this.Monitor);
- else if (previousMenu is SaveGameMenu)
+ else if (previousMenu is SaveGameMenu || previousMenu is ShippingMenu)
SaveEvents.InvokeAfterSave(this.Monitor);
// raise menu events
@@ -933,23 +952,23 @@ namespace StardewModdingAPI.Inheritance
this.PreviousActiveMenu = newMenu;
}
- // raise location list changed
- if (this.GetHash(Game1.locations) != this.PreviousGameLocations)
+ // world & player events
+ if (this.IsWorldReady)
{
- LocationEvents.InvokeLocationsChanged(this.Monitor, Game1.locations);
- this.PreviousGameLocations = this.GetHash(Game1.locations);
- }
+ // raise location list changed
+ if (this.GetHash(Game1.locations) != this.PreviousGameLocations)
+ {
+ LocationEvents.InvokeLocationsChanged(this.Monitor, Game1.locations);
+ this.PreviousGameLocations = this.GetHash(Game1.locations);
+ }
- // raise current location changed
- if (Game1.currentLocation != this.PreviousGameLocation)
- {
- LocationEvents.InvokeCurrentLocationChanged(this.Monitor, this.PreviousGameLocation, Game1.currentLocation);
- this.PreviousGameLocation = Game1.currentLocation;
- }
+ // raise current location changed
+ if (Game1.currentLocation != this.PreviousGameLocation)
+ {
+ LocationEvents.InvokeCurrentLocationChanged(this.Monitor, this.PreviousGameLocation, Game1.currentLocation);
+ this.PreviousGameLocation = Game1.currentLocation;
+ }
- // player events
- if (Game1.player != null)
- {
// raise player changed
if (Game1.player != this.PreviousFarmer)
{
@@ -996,59 +1015,48 @@ namespace StardewModdingAPI.Inheritance
PlayerEvents.InvokeInventoryChanged(this.Monitor, Game1.player.items, changedItems);
this.PreviousItems = Game1.player.items.Where(n => n != null).ToDictionary(n => n, n => n.Stack);
}
- }
- // raise current location's object list changed
- int? objectHash = Game1.currentLocation?.objects != null ? this.GetHash(Game1.currentLocation.objects) : (int?)null;
- if (objectHash != null && this.PreviousLocationObjects != objectHash)
- {
- LocationEvents.InvokeOnNewLocationObject(this.Monitor, Game1.currentLocation.objects);
- this.PreviousLocationObjects = objectHash.Value;
- }
-
- // raise time changed
- if (Game1.timeOfDay != this.PreviousTimeOfDay)
- {
- TimeEvents.InvokeTimeOfDayChanged(this.Monitor, this.PreviousTimeOfDay, Game1.timeOfDay);
- this.PreviousTimeOfDay = Game1.timeOfDay;
- }
- if (Game1.dayOfMonth != this.PreviousDayOfMonth)
- {
- TimeEvents.InvokeDayOfMonthChanged(this.Monitor, this.PreviousDayOfMonth, Game1.dayOfMonth);
- this.PreviousDayOfMonth = Game1.dayOfMonth;
- }
- if (Game1.currentSeason != this.PreviousSeasonOfYear)
- {
- TimeEvents.InvokeSeasonOfYearChanged(this.Monitor, this.PreviousSeasonOfYear, Game1.currentSeason);
- this.PreviousSeasonOfYear = Game1.currentSeason;
- }
- if (Game1.year != this.PreviousYearOfGame)
- {
- TimeEvents.InvokeYearOfGameChanged(this.Monitor, this.PreviousYearOfGame, Game1.year);
- this.PreviousYearOfGame = Game1.year;
- }
+ // raise current location's object list changed
+ {
+ int? objectHash = Game1.currentLocation?.objects != null ? this.GetHash(Game1.currentLocation.objects) : (int?)null;
+ if (objectHash != null && this.PreviousLocationObjects != objectHash)
+ {
+ LocationEvents.InvokeOnNewLocationObject(this.Monitor, Game1.currentLocation.objects);
+ this.PreviousLocationObjects = objectHash.Value;
+ }
+ }
- // raise player loaded save (in the following tick to let the game finish updating first)
- if (this.FireLoadedGameEvent)
- {
- SaveEvents.InvokeAfterLoad(this.Monitor);
- PlayerEvents.InvokeLoadedGame(this.Monitor, new EventArgsLoadedGameChanged(Game1.hasLoadedGame));
- this.FireLoadedGameEvent = false;
- }
- if (Game1.hasLoadedGame != this.PreviouslyLoadedGame)
- {
- this.FireLoadedGameEvent = true;
- this.PreviouslyLoadedGame = Game1.hasLoadedGame;
- }
+ // raise time changed
+ if (Game1.timeOfDay != this.PreviousTimeOfDay)
+ {
+ TimeEvents.InvokeTimeOfDayChanged(this.Monitor, this.PreviousTimeOfDay, Game1.timeOfDay);
+ this.PreviousTimeOfDay = Game1.timeOfDay;
+ }
+ if (Game1.dayOfMonth != this.PreviousDayOfMonth)
+ {
+ TimeEvents.InvokeDayOfMonthChanged(this.Monitor, this.PreviousDayOfMonth, Game1.dayOfMonth);
+ this.PreviousDayOfMonth = Game1.dayOfMonth;
+ }
+ if (Game1.currentSeason != this.PreviousSeasonOfYear)
+ {
+ TimeEvents.InvokeSeasonOfYearChanged(this.Monitor, this.PreviousSeasonOfYear, Game1.currentSeason);
+ this.PreviousSeasonOfYear = Game1.currentSeason;
+ }
+ if (Game1.year != this.PreviousYearOfGame)
+ {
+ TimeEvents.InvokeYearOfGameChanged(this.Monitor, this.PreviousYearOfGame, Game1.year);
+ this.PreviousYearOfGame = Game1.year;
+ }
- // raise mine level changed
- if (Game1.mine != null && Game1.mine.mineLevel != this.PreviousMineLevel)
- {
- MineEvents.InvokeMineLevelChanged(this.Monitor, this.PreviousMineLevel, Game1.mine.mineLevel);
- this.PreviousMineLevel = Game1.mine.mineLevel;
+ // raise mine level changed
+ if (Game1.mine != null && Game1.mine.mineLevel != this.PreviousMineLevel)
+ {
+ MineEvents.InvokeMineLevelChanged(this.Monitor, this.PreviousMineLevel, Game1.mine.mineLevel);
+ this.PreviousMineLevel = Game1.mine.mineLevel;
+ }
}
- // raise game transitioning to new day
+ // raise game day transition event (obsolete)
if (Game1.newDay != this.PreviousIsNewDay)
{
TimeEvents.InvokeOnNewDay(this.Monitor, this.PreviousDayOfMonth, Game1.dayOfMonth, Game1.newDay);
diff --git a/src/StardewModdingAPI/Inheritance/SObject.cs b/src/StardewModdingAPI/Inheritance/SObject.cs
index eae5424d..0b0a7ec9 100644
--- a/src/StardewModdingAPI/Inheritance/SObject.cs
+++ b/src/StardewModdingAPI/Inheritance/SObject.cs
@@ -49,7 +49,7 @@ namespace StardewModdingAPI.Inheritance
*********/
public SObject()
{
- Program.DeprecationManager.Warn(nameof(SObject), "0.39.3", DeprecationLevel.Info);
+ Program.DeprecationManager.Warn(nameof(SObject), "0.39.3", DeprecationLevel.PendingRemoval);
this.name = "Modded Item Name";
this.Description = "Modded Item Description";
diff --git a/src/StardewModdingAPI/LogWriter.cs b/src/StardewModdingAPI/LogWriter.cs
index 9c2ef515..e22759a7 100644
--- a/src/StardewModdingAPI/LogWriter.cs
+++ b/src/StardewModdingAPI/LogWriter.cs
@@ -60,7 +60,7 @@ namespace StardewModdingAPI
/// <summary>Raise a deprecation warning.</summary>
private void WarnDeprecated()
{
- Program.DeprecationManager.Warn($"the {nameof(LogWriter)} class", "1.0", DeprecationLevel.Info);
+ Program.DeprecationManager.Warn($"the {nameof(LogWriter)} class", "1.0", DeprecationLevel.PendingRemoval);
}
}
} \ No newline at end of file
diff --git a/src/StardewModdingAPI/Mod.cs b/src/StardewModdingAPI/Mod.cs
index d12a7e05..0d35939d 100644
--- a/src/StardewModdingAPI/Mod.cs
+++ b/src/StardewModdingAPI/Mod.cs
@@ -71,7 +71,7 @@ namespace StardewModdingAPI
{
get
{
- Program.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigPath)}", "1.0", DeprecationLevel.Notice);
+ Program.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigPath)}", "1.0", DeprecationLevel.Info);
Program.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigFolder)}", "1.0"); // avoid redundant warnings
return Constants.CurrentSavePathExists ? Path.Combine(this.PerSaveConfigFolder, Constants.SaveFolderName + ".json") : "";
}
diff --git a/src/StardewModdingAPI/ModHelper.cs b/src/StardewModdingAPI/ModHelper.cs
index 78b3eefa..c20130cf 100644
--- a/src/StardewModdingAPI/ModHelper.cs
+++ b/src/StardewModdingAPI/ModHelper.cs
@@ -30,22 +30,31 @@ namespace StardewModdingAPI
/// <summary>Simplifies access to private game code.</summary>
public IReflectionHelper Reflection { get; } = new ReflectionHelper();
+ /// <summary>Metadata about loaded mods.</summary>
+ public IModRegistry ModRegistry { get; }
+
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
/// <param name="modDirectory">The mod directory path.</param>
- public ModHelper(string modDirectory)
+ /// <param name="modRegistry">Metadata about loaded mods.</param>
+ /// <exception cref="ArgumentException">An argument is null or invalid.</exception>
+ /// <exception cref="InvalidOperationException">The <paramref name="modDirectory"/> path does not exist on disk.</exception>
+ public ModHelper(string modDirectory, IModRegistry modRegistry)
{
// validate
+ if (modRegistry == null)
+ throw new ArgumentException("The mod registry cannot be null.");
if (string.IsNullOrWhiteSpace(modDirectory))
- throw new InvalidOperationException("The mod directory cannot be empty.");
+ throw new ArgumentException("The mod directory cannot be empty.");
if (!Directory.Exists(modDirectory))
throw new InvalidOperationException("The specified mod directory does not exist.");
// initialise
this.DirectoryPath = modDirectory;
+ this.ModRegistry = modRegistry;
}
/****
diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs
index e5c27e71..ec3ccce7 100644
--- a/src/StardewModdingAPI/Program.cs
+++ b/src/StardewModdingAPI/Program.cs
@@ -100,7 +100,7 @@ namespace StardewModdingAPI
Program.Monitor.WriteToConsole = !args.Contains("--no-terminal");
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB"); // for consistent log formatting
- // add info headers
+ // add info header
Program.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Game1.version} on {Environment.OSVersion}", LogLevel.Info);
// initialise user settings
@@ -126,7 +126,10 @@ namespace StardewModdingAPI
if (!Program.Settings.CheckForUpdates)
Program.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 editing or deleting {Constants.ApiConfigPath}.", LogLevel.Warn);
if (!Program.Monitor.WriteToConsole)
- Program.Monitor.Log($"Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn);
+ Program.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn);
+
+ // print file paths
+ Program.Monitor.Log($"Mods go here: {Program.ModPath}");
// initialise legacy log
Log.Monitor = Program.GetSecondaryMonitor("legacy mod");
@@ -223,7 +226,7 @@ namespace StardewModdingAPI
Program.StardewAssembly = Assembly.UnsafeLoadFrom(Program.GameExecutablePath);
Program.StardewProgramType = Program.StardewAssembly.GetType("StardewValley.Program", true);
Program.StardewGameInfo = Program.StardewProgramType.GetField("gamePtr");
- Game1.version += $"-Z_MODDED | SMAPI {Constants.ApiVersion}";
+ Game1.version += $" | SMAPI {Constants.ApiVersion}";
// add error interceptors
#if SMAPI_FOR_WINDOWS
@@ -291,7 +294,7 @@ namespace StardewModdingAPI
}
catch (Exception ex)
{
- Program.Monitor.Log($"SMAPI encountered a fatal error:\n{ex.GetLogSummary()}", LogLevel.Error);
+ Program.Monitor.Log($"The game encountered a fatal error:\n{ex.GetLogSummary()}", LogLevel.Error);
}
}
@@ -333,7 +336,8 @@ namespace StardewModdingAPI
Program.Monitor.Log($"Couldn't read metadata file at {Constants.ApiModMetadataPath}. SMAPI will still run, but some features may be disabled.\n{ex}", LogLevel.Warn);
}
- // load mods
+ // load mod assemblies
+ List<Action> deprecationWarnings = new List<Action>(); // queue up deprecation warnings to show after mod list
foreach (string directory in Directory.GetDirectories(Program.ModPath))
{
string directoryName = new DirectoryInfo(directory).Name;
@@ -350,7 +354,7 @@ namespace StardewModdingAPI
}
// get helper
- IModHelper helper = new ModHelper(directory);
+ IModHelper helper = new ModHelper(directory, Program.ModRegistry);
// get manifest path
string manifestPath = Path.Combine(directory, "manifest.json");
@@ -388,7 +392,7 @@ namespace StardewModdingAPI
// log deprecated fields
if (manifest.UsedAuthourField)
- Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Manifest)}.{nameof(Manifest.Authour)}", "1.0", DeprecationLevel.Notice);
+ deprecationWarnings.Add(() => Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Manifest)}.{nameof(Manifest.Authour)}", "1.0", DeprecationLevel.Notice));
}
catch (Exception ex)
{
@@ -436,7 +440,7 @@ namespace StardewModdingAPI
// create per-save directory
if (manifest.PerSaveConfigs)
{
- Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Manifest)}.{nameof(Manifest.PerSaveConfigs)}", "1.0", DeprecationLevel.Notice);
+ deprecationWarnings.Add(() => Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Manifest)}.{nameof(Manifest.PerSaveConfigs)}", "1.0", DeprecationLevel.Info));
try
{
string psDir = Path.Combine(directory, "psconfigs");
@@ -536,8 +540,16 @@ namespace StardewModdingAPI
Program.Monitor.Log($"{errorPrefix}: an error occurred while loading the target DLL.\n{ex.GetLogSummary()}", LogLevel.Error);
continue;
}
+ }
- // call mod entry
+ // log deprecation warnings
+ foreach (Action warning in deprecationWarnings)
+ warning();
+ deprecationWarnings = null;
+
+ // initialise mods
+ foreach (Mod mod in Program.ModRegistry.GetMods())
+ {
try
{
// call entry methods
@@ -547,13 +559,13 @@ namespace StardewModdingAPI
// raise deprecation warning for old Entry() methods
if (Program.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) }))
- Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Mod)}.{nameof(Mod.Entry)}(object[]) instead of {nameof(Mod)}.{nameof(Mod.Entry)}({nameof(IModHelper)})", "1.0", DeprecationLevel.Notice);
+ Program.DeprecationManager.Warn(mod.ModManifest.Name, $"{nameof(Mod)}.{nameof(Mod.Entry)}(object[]) instead of {nameof(Mod)}.{nameof(Mod.Entry)}({nameof(IModHelper)})", "1.0", DeprecationLevel.Notice);
if (Program.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) }))
- Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Mod)}.{nameof(Mod.Entry)}({nameof(ModHelper)}) instead of {nameof(Mod)}.{nameof(Mod.Entry)}({nameof(IModHelper)})", "1.1", DeprecationLevel.Info);
+ Program.DeprecationManager.Warn(mod.ModManifest.Name, $"{nameof(Mod)}.{nameof(Mod.Entry)}({nameof(ModHelper)}) instead of {nameof(Mod)}.{nameof(Mod.Entry)}({nameof(IModHelper)})", "1.1", DeprecationLevel.PendingRemoval);
}
catch (Exception ex)
{
- Program.Monitor.Log($"The {manifest.Name} mod failed on entry initialisation. It will still be loaded, but may not function correctly.\n{ex.GetLogSummary()}", LogLevel.Warn);
+ Program.Monitor.Log($"The {mod.ModManifest.Name} mod failed on entry initialisation. It will still be loaded, but may not function correctly.\n{ex.GetLogSummary()}", LogLevel.Warn);
}
}
diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj
index 125f287e..d56b6866 100644
--- a/src/StardewModdingAPI/StardewModdingAPI.csproj
+++ b/src/StardewModdingAPI/StardewModdingAPI.csproj
@@ -148,6 +148,7 @@
<Compile Include="Events\EventArgsStringChanged.cs" />
<Compile Include="Events\GameEvents.cs" />
<Compile Include="Events\GraphicsEvents.cs" />
+ <Compile Include="IModRegistry.cs" />
<Compile Include="Events\LocationEvents.cs" />
<Compile Include="Events\MenuEvents.cs" />
<Compile Include="Events\MineEvents.cs" />
diff --git a/src/StardewModdingAPI/Version.cs b/src/StardewModdingAPI/Version.cs
index 87cd4f3d..e66d7be5 100644
--- a/src/StardewModdingAPI/Version.cs
+++ b/src/StardewModdingAPI/Version.cs
@@ -30,7 +30,7 @@ namespace StardewModdingAPI
{
get
{
- Program.DeprecationManager.Warn($"{nameof(Version)}.{nameof(Version.VersionString)}", "1.0", DeprecationLevel.Notice);
+ Program.DeprecationManager.Warn($"{nameof(Version)}.{nameof(Version.VersionString)}", "1.0", DeprecationLevel.Info);
return this.GetSemanticVersion().ToString();
}
}