summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Other/ApplySaveFixCommand.cs77
-rw-r--r--src/SMAPI.Mods.ConsoleCommands/manifest.json4
-rw-r--r--src/SMAPI.Mods.SaveBackup/manifest.json4
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/LogParser.cs11
-rw-r--r--src/SMAPI/Constants.cs4
-rw-r--r--src/SMAPI/Framework/ContentCoordinator.cs2
-rw-r--r--src/SMAPI/Framework/ContentManagers/BaseContentManager.cs8
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManager.cs9
-rw-r--r--src/SMAPI/Framework/ContentManagers/IContentManager.cs3
-rw-r--r--src/SMAPI/Framework/ContentManagers/ModContentManager.cs3
-rw-r--r--src/SMAPI/Framework/DeprecationManager.cs31
-rw-r--r--src/SMAPI/Framework/ModHelpers/CommandHelper.cs8
-rw-r--r--src/SMAPI/Framework/SCore.cs37
-rw-r--r--src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs15
-rw-r--r--src/SMAPI/Framework/WatcherCore.cs2
15 files changed, 174 insertions, 44 deletions
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Other/ApplySaveFixCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Other/ApplySaveFixCommand.cs
new file mode 100644
index 00000000..8f59342e
--- /dev/null
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Other/ApplySaveFixCommand.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using StardewValley;
+
+namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Other
+{
+ /// <summary>A command which runs one of the game's save migrations.</summary>
+ internal class ApplySaveFixCommand : TrainerCommand
+ {
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ public ApplySaveFixCommand()
+ : base("apply_save_fix", "Apply one of the game's save migrations to the currently loaded save. WARNING: This may corrupt or make permanent changes to your save. DO NOT USE THIS unless you're absolutely sure.\n\nUsage: apply_save_fix list\nList all valid save IDs.\n\nUsage: apply_save_fix <fix ID>\nApply the named save fix.") { }
+
+ /// <summary>Handle the command.</summary>
+ /// <param name="monitor">Writes messages to the console and log file.</param>
+ /// <param name="command">The command name.</param>
+ /// <param name="args">The command arguments.</param>
+ public override void Handle(IMonitor monitor, string command, ArgumentParser args)
+ {
+ // get fix ID
+ if (!args.TryGet(0, "fix_id", out string rawFixId, required: false))
+ {
+ monitor.Log("Invalid usage. Type 'help apply_save_fix' for details.", LogLevel.Error);
+ return;
+ }
+ rawFixId = rawFixId.Trim();
+
+
+ // list mode
+ if (rawFixId == "list")
+ {
+ monitor.Log("Valid save fix IDs:\n - " + string.Join("\n - ", this.GetSaveIds()), LogLevel.Info);
+ return;
+ }
+
+ // validate fix ID
+ if (!Enum.TryParse(rawFixId, ignoreCase: true, out SaveGame.SaveFixes fixId))
+ {
+ monitor.Log($"Invalid save ID '{rawFixId}'. Type 'help apply_save_fix' for details.", LogLevel.Error);
+ return;
+ }
+
+ // apply
+ monitor.Log("THIS MAY CAUSE PERMANENT CHANGES TO YOUR SAVE FILE. If you're not sure, exit your game without saving to avoid issues.", LogLevel.Warn);
+ monitor.Log($"Trying to apply save fix ID: '{fixId}'.", LogLevel.Warn);
+ try
+ {
+ Game1.applySaveFix(fixId);
+ monitor.Log("Save fix applied.", LogLevel.Info);
+ }
+ catch (Exception ex)
+ {
+ monitor.Log("Applying save fix failed. The save may be in an invalid state; you should exit your game now without saving to avoid issues.", LogLevel.Error);
+ monitor.Log($"Technical details: {ex}", LogLevel.Debug);
+ }
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Get the valid save fix IDs.</summary>
+ private IEnumerable<string> GetSaveIds()
+ {
+ foreach (SaveGame.SaveFixes id in Enum.GetValues(typeof(SaveGame.SaveFixes)))
+ {
+ if (id == SaveGame.SaveFixes.MAX)
+ continue;
+
+ yield return id.ToString();
+ }
+ }
+ }
+}
diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json
index a1a137a1..61c610d0 100644
--- a/src/SMAPI.Mods.ConsoleCommands/manifest.json
+++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json
@@ -1,9 +1,9 @@
{
"Name": "Console Commands",
"Author": "SMAPI",
- "Version": "3.8.0",
+ "Version": "3.8.1",
"Description": "Adds SMAPI console commands that let you manipulate the game.",
"UniqueID": "SMAPI.ConsoleCommands",
"EntryDll": "ConsoleCommands.dll",
- "MinimumApiVersion": "3.8.0"
+ "MinimumApiVersion": "3.8.1"
}
diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json
index 96822f4a..7cf63e66 100644
--- a/src/SMAPI.Mods.SaveBackup/manifest.json
+++ b/src/SMAPI.Mods.SaveBackup/manifest.json
@@ -1,9 +1,9 @@
{
"Name": "Save Backup",
"Author": "SMAPI",
- "Version": "3.8.0",
+ "Version": "3.8.1",
"Description": "Automatically backs up all your saves once per day into its folder.",
"UniqueID": "SMAPI.SaveBackup",
"EntryDll": "SaveBackup.dll",
- "MinimumApiVersion": "3.8.0"
+ "MinimumApiVersion": "3.8.1"
}
diff --git a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
index f69d4b6f..84013ccc 100644
--- a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
+++ b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs
@@ -42,7 +42,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
private readonly Regex ModUpdateListStartPattern = new Regex(@"^You can update \d+ mods?:$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>A regex pattern matching an entry in SMAPI's mod update list.</summary>
- private readonly Regex ModUpdateListEntryPattern = new Regex(@"^ (?<name>.+?) (?<version>[^\s]+): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ private readonly Regex ModUpdateListEntryPattern = new Regex(@"^ (?<name>.+) (?<version>[^\s]+): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>A regex pattern matching SMAPI's update line.</summary>
private readonly Regex SmapiUpdatePattern = new Regex(@"^You can update SMAPI to (?<version>[^\s]+): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
@@ -109,12 +109,9 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
if (message.Mod == "SMAPI")
{
// update flags
- if (inModList && !this.ModListEntryPattern.IsMatch(message.Text))
- inModList = false;
- if (inContentPackList && !this.ContentPackListEntryPattern.IsMatch(message.Text))
- inContentPackList = false;
- if (inModUpdateList && !this.ModUpdateListEntryPattern.IsMatch(message.Text))
- inModUpdateList = false;
+ inModList = inModList && message.Level == LogLevel.Info && this.ModListEntryPattern.IsMatch(message.Text);
+ inContentPackList = inContentPackList && message.Level == LogLevel.Info && this.ContentPackListEntryPattern.IsMatch(message.Text);
+ inModUpdateList = inModUpdateList && message.Level == LogLevel.Alert && this.ModUpdateListEntryPattern.IsMatch(message.Text);
// mod list
if (!inModList && message.Level == LogLevel.Info && this.ModListStartPattern.IsMatch(message.Text))
diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs
index 98d0277b..9d5501a3 100644
--- a/src/SMAPI/Constants.cs
+++ b/src/SMAPI/Constants.cs
@@ -54,10 +54,10 @@ namespace StardewModdingAPI
** Public
****/
/// <summary>SMAPI's current semantic version.</summary>
- public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.8.0");
+ public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.8.1");
/// <summary>The minimum supported version of Stardew Valley.</summary>
- public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.5.0");
+ public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.5.1");
/// <summary>The maximum supported version of Stardew Valley.</summary>
public static ISemanticVersion MaximumGameVersion { get; } = null;
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs
index 93371415..f9027972 100644
--- a/src/SMAPI/Framework/ContentCoordinator.cs
+++ b/src/SMAPI/Framework/ContentCoordinator.cs
@@ -278,7 +278,7 @@ namespace StardewModdingAPI.Framework
return this.ContentManagerLock.InReadLock(() =>
{
List<object> values = new List<object>();
- foreach (IContentManager content in this.ContentManagers.Where(p => !p.IsNamespaced && p.IsLoaded(assetName)))
+ foreach (IContentManager content in this.ContentManagers.Where(p => !p.IsNamespaced && p.IsLoaded(assetName, p.Language)))
{
object value = content.Load<object>(assetName, this.Language, useCache: true);
values.Add(value);
diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
index 6bc3a505..92264f8c 100644
--- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs
@@ -169,10 +169,11 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <summary>Get whether the content manager has already loaded and cached the given asset.</summary>
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
- public bool IsLoaded(string assetName)
+ /// <param name="language">The language.</param>
+ public bool IsLoaded(string assetName, LanguageCode language)
{
assetName = this.Cache.NormalizeKey(assetName);
- return this.IsNormalizedKeyLoaded(assetName);
+ return this.IsNormalizedKeyLoaded(assetName, language);
}
/// <summary>Get the cached asset keys.</summary>
@@ -315,7 +316,8 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <summary>Get whether an asset has already been loaded.</summary>
/// <param name="normalizedAssetName">The normalized asset name.</param>
- protected abstract bool IsNormalizedKeyLoaded(string normalizedAssetName);
+ /// <param name="language">The language to check.</param>
+ protected abstract bool IsNormalizedKeyLoaded(string normalizedAssetName, LanguageCode language);
/// <summary>Get the locale codes (like <c>ja-JP</c>) used in asset keys.</summary>
private IDictionary<LanguageCode, string> GetKeyLocales()
diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
index 83a63986..ad8f2ef1 100644
--- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs
@@ -78,7 +78,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
return this.Load<T>(newAssetName, newLanguage, useCache);
// get from cache
- if (useCache && this.IsLoaded(assetName))
+ if (useCache && this.IsLoaded(assetName, language))
return this.RawLoad<T>(assetName, language, useCache: true);
// get managed asset
@@ -151,11 +151,12 @@ namespace StardewModdingAPI.Framework.ContentManagers
*********/
/// <summary>Get whether an asset has already been loaded.</summary>
/// <param name="normalizedAssetName">The normalized asset name.</param>
- protected override bool IsNormalizedKeyLoaded(string normalizedAssetName)
+ /// <param name="language">The language to check.</param>
+ protected override bool IsNormalizedKeyLoaded(string normalizedAssetName, LanguageCode language)
{
string cachedKey = null;
bool localized =
- this.Language != LocalizedContentManager.LanguageCode.en
+ language != LocalizedContentManager.LanguageCode.en
&& !this.Coordinator.IsManagedAssetKey(normalizedAssetName)
&& this.LocalizedAssetNames.TryGetValue(normalizedAssetName, out cachedKey);
@@ -214,7 +215,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
private T RawLoad<T>(string assetName, LanguageCode language, bool useCache)
{
// use cached key
- if (this.LocalizedAssetNames.TryGetValue(assetName, out string cachedKey))
+ if (language == this.Language && this.LocalizedAssetNames.TryGetValue(assetName, out string cachedKey))
return base.RawLoad<T>(cachedKey, useCache);
// try translated key
diff --git a/src/SMAPI/Framework/ContentManagers/IContentManager.cs b/src/SMAPI/Framework/ContentManagers/IContentManager.cs
index 8da9a777..0e7edd8f 100644
--- a/src/SMAPI/Framework/ContentManagers/IContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/IContentManager.cs
@@ -58,7 +58,8 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <summary>Get whether the content manager has already loaded and cached the given asset.</summary>
/// <param name="assetName">The asset path relative to the loader root directory, not including the <c>.xnb</c> extension.</param>
- bool IsLoaded(string assetName);
+ /// <param name="language">The language.</param>
+ bool IsLoaded(string assetName, LocalizedContentManager.LanguageCode language);
/// <summary>Get the cached asset keys.</summary>
IEnumerable<string> GetAssetKeys();
diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
index 127705ea..753ec188 100644
--- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
@@ -211,7 +211,8 @@ namespace StardewModdingAPI.Framework.ContentManagers
*********/
/// <summary>Get whether an asset has already been loaded.</summary>
/// <param name="normalizedAssetName">The normalized asset name.</param>
- protected override bool IsNormalizedKeyLoaded(string normalizedAssetName)
+ /// <param name="language">The language to check.</param>
+ protected override bool IsNormalizedKeyLoaded(string normalizedAssetName, LanguageCode language)
{
return this.Cache.ContainsKey(normalizedAssetName);
}
diff --git a/src/SMAPI/Framework/DeprecationManager.cs b/src/SMAPI/Framework/DeprecationManager.cs
index 94a2da85..c22b5718 100644
--- a/src/SMAPI/Framework/DeprecationManager.cs
+++ b/src/SMAPI/Framework/DeprecationManager.cs
@@ -35,19 +35,17 @@ namespace StardewModdingAPI.Framework
this.ModRegistry = modRegistry;
}
- /// <summary>Log a deprecation warning for the old-style events.</summary>
- public void WarnForOldEvents()
+ /// <summary>Get the source name for a mod from its unique ID.</summary>
+ public string GetSourceNameFromStack()
{
- this.Warn("legacy events", "2.9", DeprecationLevel.PendingRemoval);
+ return this.ModRegistry.GetFromStack()?.DisplayName;
}
- /// <summary>Log a deprecation warning.</summary>
- /// <param name="nounPhrase">A noun phrase describing what is deprecated.</param>
- /// <param name="version">The SMAPI version which deprecated it.</param>
- /// <param name="severity">How deprecated the code is.</param>
- public void Warn(string nounPhrase, string version, DeprecationLevel severity)
+ /// <summary>Get the source name for a mod from its unique ID.</summary>
+ /// <param name="modId">The mod's unique ID.</param>
+ public string GetSourceName(string modId)
{
- this.Warn(this.ModRegistry.GetFromStack()?.DisplayName, nounPhrase, version, severity);
+ return this.ModRegistry.Get(modId)?.DisplayName;
}
/// <summary>Log a deprecation warning.</summary>
@@ -58,7 +56,7 @@ namespace StardewModdingAPI.Framework
public void Warn(string source, string nounPhrase, string version, DeprecationLevel severity)
{
// ignore if already warned
- if (!this.MarkWarned(source ?? "<unknown>", nounPhrase, version))
+ if (!this.MarkWarned(source ?? this.GetSourceNameFromStack() ?? "<unknown>", nounPhrase, version))
return;
// queue warning
@@ -111,21 +109,16 @@ namespace StardewModdingAPI.Framework
this.QueuedWarnings.Clear();
}
- /// <summary>Mark a deprecation warning as already logged.</summary>
- /// <param name="nounPhrase">A noun phrase describing what is deprecated (e.g. "the Extensions.AsInt32 method").</param>
- /// <param name="version">The SMAPI version which deprecated it.</param>
- /// <returns>Returns whether the deprecation was successfully marked as warned. Returns <c>false</c> if it was already marked.</returns>
- public bool MarkWarned(string nounPhrase, string version)
- {
- return this.MarkWarned(this.ModRegistry.GetFromStack()?.DisplayName, nounPhrase, version);
- }
+ /*********
+ ** Private methods
+ *********/
/// <summary>Mark a deprecation warning as already logged.</summary>
/// <param name="source">The friendly name of the assembly which used the deprecated code.</param>
/// <param name="nounPhrase">A noun phrase describing what is deprecated (e.g. "the Extensions.AsInt32 method").</param>
/// <param name="version">The SMAPI version which deprecated it.</param>
/// <returns>Returns whether the deprecation was successfully marked as warned. Returns <c>false</c> if it was already marked.</returns>
- public bool MarkWarned(string source, string nounPhrase, string version)
+ private bool MarkWarned(string source, string nounPhrase, string version)
{
if (string.IsNullOrWhiteSpace(source))
throw new InvalidOperationException("The deprecation source cannot be empty.");
diff --git a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs
index 600f867f..69382009 100644
--- a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs
@@ -36,8 +36,16 @@ namespace StardewModdingAPI.Framework.ModHelpers
}
/// <inheritdoc />
+ [Obsolete]
public bool Trigger(string name, string[] arguments)
{
+ SCore.DeprecationManager.Warn(
+ source: SCore.DeprecationManager.GetSourceName(this.ModID),
+ nounPhrase: $"{nameof(IModHelper)}.{nameof(IModHelper.ConsoleCommands)}.{nameof(ICommandHelper.Trigger)}",
+ version: "3.8.1",
+ severity: DeprecationLevel.Notice
+ );
+
return this.CommandManager.Trigger(name, arguments);
}
}
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index a7f8fbed..e05213f0 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -765,6 +765,9 @@ namespace StardewModdingAPI.Framework
this.Monitor.Log(context);
+ // apply save fixes
+ this.ApplySaveFixes();
+
// raise events
this.OnLoadStageChanged(LoadStage.Ready);
events.SaveLoaded.RaiseEmpty();
@@ -1054,6 +1057,40 @@ namespace StardewModdingAPI.Framework
this.EventManager.ReturnedToTitle.RaiseEmpty();
}
+ /// <summary>Apply fixes to the save after it's loaded.</summary>
+ private void ApplySaveFixes()
+ {
+ // get last SMAPI version used with this save
+ const string migrationKey = "Pathoschild.SMAPI/api-version";
+ if (!Game1.CustomData.TryGetValue(migrationKey, out string rawVersion) || !SemanticVersion.TryParse(rawVersion, out ISemanticVersion lastVersion))
+ lastVersion = new SemanticVersion(3, 8, 0);
+
+ // fix bundle corruption in SMAPI 3.8.0
+ // For non-English players who created a new save in SMAPI 3.8.0, bundle data was
+ // incorrectly translated which caused the code to crash whenever the game tried to
+ // read it.
+ if (lastVersion.IsOlderThan(new SemanticVersion(3, 8, 1)) && Game1.netWorldState?.Value?.BundleData != null)
+ {
+ var oldData = new Dictionary<string, string>(Game1.netWorldState.Value.BundleData);
+
+ try
+ {
+ Game1.applySaveFix(SaveGame.SaveFixes.FixBotchedBundleData);
+ bool changed = Game1.netWorldState.Value.BundleData.Any(p => oldData.TryGetValue(p.Key, out string oldValue) && oldValue != p.Value);
+ if (changed)
+ this.Monitor.Log("Found broken community center bundles and fixed them automatically.", LogLevel.Info);
+ }
+ catch (Exception ex)
+ {
+ this.Monitor.Log("Failed to verify community center data.", LogLevel.Error); // should never happen
+ this.Monitor.Log($"Technical details: {ex}");
+ }
+ }
+
+ // update last run
+ Game1.CustomData[migrationKey] = Constants.ApiVersion.ToString();
+ }
+
/// <summary>Raised after custom content is removed from the save data to avoid a crash.</summary>
internal void OnSaveContentRemoved()
{
diff --git a/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs b/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs
index 303a4f3a..e968d79c 100644
--- a/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs
+++ b/src/SMAPI/Framework/StateTracking/WorldLocationsTracker.cs
@@ -21,6 +21,9 @@ namespace StardewModdingAPI.Framework.StateTracking
/// <summary>Tracks changes to the list of active mine locations.</summary>
private readonly ICollectionWatcher<MineShaft> MineLocationListWatcher;
+ /// <summary>Tracks changes to the list of active volcano locations.</summary>
+ private readonly ICollectionWatcher<GameLocation> VolcanoLocationListWatcher;
+
/// <summary>A lookup of the tracked locations.</summary>
private IDictionary<GameLocation, LocationTracker> LocationDict { get; } = new Dictionary<GameLocation, LocationTracker>(new ObjectReferenceComparer<GameLocation>());
@@ -53,10 +56,12 @@ namespace StardewModdingAPI.Framework.StateTracking
/// <summary>Construct an instance.</summary>
/// <param name="locations">The game's list of locations.</param>
/// <param name="activeMineLocations">The game's list of active mine locations.</param>
- public WorldLocationsTracker(ObservableCollection<GameLocation> locations, IList<MineShaft> activeMineLocations)
+ /// <param name="activeVolcanoLocations">The game's list of active volcano locations.</param>
+ public WorldLocationsTracker(ObservableCollection<GameLocation> locations, IList<MineShaft> activeMineLocations, IList<VolcanoDungeon> activeVolcanoLocations)
{
this.LocationListWatcher = WatcherFactory.ForObservableCollection(locations);
this.MineLocationListWatcher = WatcherFactory.ForReferenceList(activeMineLocations);
+ this.VolcanoLocationListWatcher = WatcherFactory.ForReferenceList(activeVolcanoLocations);
}
/// <summary>Update the current value if needed.</summary>
@@ -65,6 +70,7 @@ namespace StardewModdingAPI.Framework.StateTracking
// update watchers
this.LocationListWatcher.Update();
this.MineLocationListWatcher.Update();
+ this.VolcanoLocationListWatcher.Update();
foreach (LocationTracker watcher in this.Locations)
watcher.Update();
@@ -79,6 +85,11 @@ namespace StardewModdingAPI.Framework.StateTracking
this.Remove(this.MineLocationListWatcher.Removed);
this.Add(this.MineLocationListWatcher.Added);
}
+ if (this.VolcanoLocationListWatcher.IsChanged)
+ {
+ this.Remove(this.VolcanoLocationListWatcher.Removed);
+ this.Add(this.VolcanoLocationListWatcher.Added);
+ }
// detect building changed
foreach (LocationTracker watcher in this.Locations.Where(p => p.BuildingsWatcher.IsChanged).ToArray())
@@ -107,6 +118,7 @@ namespace StardewModdingAPI.Framework.StateTracking
this.Added.Clear();
this.LocationListWatcher.Reset();
this.MineLocationListWatcher.Reset();
+ this.VolcanoLocationListWatcher.Reset();
}
/// <summary>Set the current value as the baseline.</summary>
@@ -243,6 +255,7 @@ namespace StardewModdingAPI.Framework.StateTracking
{
yield return this.LocationListWatcher;
yield return this.MineLocationListWatcher;
+ yield return this.VolcanoLocationListWatcher;
foreach (LocationTracker watcher in this.Locations)
yield return watcher;
}
diff --git a/src/SMAPI/Framework/WatcherCore.cs b/src/SMAPI/Framework/WatcherCore.cs
index 393f6a37..62a0c3b8 100644
--- a/src/SMAPI/Framework/WatcherCore.cs
+++ b/src/SMAPI/Framework/WatcherCore.cs
@@ -66,7 +66,7 @@ namespace StardewModdingAPI.Framework
this.WindowSizeWatcher = WatcherFactory.ForEquatable(() => new Point(Game1.viewport.Width, Game1.viewport.Height));
this.TimeWatcher = WatcherFactory.ForEquatable(() => Game1.timeOfDay);
this.ActiveMenuWatcher = WatcherFactory.ForReference(() => Game1.activeClickableMenu);
- this.LocationsWatcher = new WorldLocationsTracker(gameLocations, MineShaft.activeMines);
+ this.LocationsWatcher = new WorldLocationsTracker(gameLocations, MineShaft.activeMines, VolcanoDungeon.activeLevels);
this.LocaleWatcher = WatcherFactory.ForGenericEquality(() => LocalizedContentManager.CurrentLanguageCode);
this.Watchers.AddRange(new IWatcher[]
{