diff options
| author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2018-12-07 13:40:44 -0500 |
|---|---|---|
| committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2018-12-07 13:40:44 -0500 |
| commit | a78b1935928919694dfe8de823a1accd6d222732 (patch) | |
| tree | 3f17b6087cf2749e52c1e237de17e2e9addb6c06 /src/SMAPI/Framework | |
| parent | 4cd9eda1591c3908bf80b60c2902491a7595ee27 (diff) | |
| parent | 8901218418693d610a17b22fe789ba6279f63446 (diff) | |
| download | SMAPI-a78b1935928919694dfe8de823a1accd6d222732.tar.gz SMAPI-a78b1935928919694dfe8de823a1accd6d222732.tar.bz2 SMAPI-a78b1935928919694dfe8de823a1accd6d222732.zip | |
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI/Framework')
22 files changed, 423 insertions, 101 deletions
diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index 9eb7b5f9..08a32a9b 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -238,28 +238,30 @@ namespace StardewModdingAPI.Framework public IEnumerable<string> InvalidateCache(Func<string, Type, bool> predicate, bool dispose = false) { // invalidate cache - HashSet<string> removedAssetNames = new HashSet<string>(); + IDictionary<string, Type> removedAssetNames = new Dictionary<string, Type>(StringComparer.InvariantCultureIgnoreCase); foreach (IContentManager contentManager in this.ContentManagers) { - foreach (string name in contentManager.InvalidateCache(predicate, dispose)) - removedAssetNames.Add(name); + foreach (Tuple<string, Type> asset in contentManager.InvalidateCache(predicate, dispose)) + removedAssetNames[asset.Item1] = asset.Item2; } // reload core game assets int reloaded = 0; - foreach (string key in removedAssetNames) + foreach (var pair in removedAssetNames) { - if (this.CoreAssets.Propagate(this.MainContentManager, key)) // use an intercepted content manager + string key = pair.Key; + Type type = pair.Value; + if (this.CoreAssets.Propagate(this.MainContentManager, key, type)) // use an intercepted content manager reloaded++; } // report result if (removedAssetNames.Any()) - this.Monitor.Log($"Invalidated {removedAssetNames.Count} asset names: {string.Join(", ", removedAssetNames.OrderBy(p => p, StringComparer.InvariantCultureIgnoreCase))}. Reloaded {reloaded} core assets.", LogLevel.Trace); + this.Monitor.Log($"Invalidated {removedAssetNames.Count} asset names: {string.Join(", ", removedAssetNames.Keys.OrderBy(p => p, StringComparer.InvariantCultureIgnoreCase))}. Reloaded {reloaded} core assets.", LogLevel.Trace); else this.Monitor.Log("Invalidated 0 cache entries.", LogLevel.Trace); - return removedAssetNames; + return removedAssetNames.Keys; } /// <summary>Dispose held resources.</summary> diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs index 18aae05b..724a6e1c 100644 --- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs @@ -32,12 +32,12 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <summary>Whether the content coordinator has been disposed.</summary> private bool IsDisposed; - /// <summary>The language enum values indexed by locale code.</summary> - private readonly IDictionary<string, LanguageCode> LanguageCodes; - /// <summary>A callback to invoke when the content manager is being disposed.</summary> private readonly Action<BaseContentManager> OnDisposing; + /// <summary>The language enum values indexed by locale code.</summary> + protected IDictionary<string, LanguageCode> LanguageCodes { get; } + /********* ** Accessors @@ -200,23 +200,25 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <summary>Purge matched assets from the cache.</summary> /// <param name="predicate">Matches the asset keys to invalidate.</param> /// <param name="dispose">Whether to dispose invalidated assets. This should only be <c>true</c> when they're being invalidated as part of a dispose, to avoid crashing the game.</param> - /// <returns>Returns the number of invalidated assets.</returns> - public IEnumerable<string> InvalidateCache(Func<string, Type, bool> predicate, bool dispose = false) + /// <returns>Returns the invalidated asset names and types.</returns> + public IEnumerable<Tuple<string, Type>> InvalidateCache(Func<string, Type, bool> predicate, bool dispose = false) { - HashSet<string> removeAssetNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase); + Dictionary<string, Type> removeAssetNames = new Dictionary<string, Type>(StringComparer.InvariantCultureIgnoreCase); this.Cache.Remove((key, type) => { this.ParseCacheKey(key, out string assetName, out _); - if (removeAssetNames.Contains(assetName) || predicate(assetName, type)) + if (removeAssetNames.ContainsKey(assetName)) + return true; + if (predicate(assetName, type)) { - removeAssetNames.Add(assetName); + removeAssetNames[assetName] = type; return true; } return false; }); - return removeAssetNames; + return removeAssetNames.Select(p => Tuple.Create(p.Key, p.Value)); } /// <summary>Dispose held resources.</summary> diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index a53840bc..4f3b6fbc 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using StardewModdingAPI.Framework.Content; +using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.Utilities; using StardewValley; @@ -52,7 +53,10 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <param name="language">The language code for which to load content.</param> public override T Load<T>(string assetName, LanguageCode language) { + // normalise asset name assetName = this.AssertAndNormaliseAssetName(assetName); + if (this.TryParseExplicitLanguageAssetKey(assetName, out string newAssetName, out LanguageCode newLanguage)) + return this.Load<T>(newAssetName, newLanguage); // get from cache if (this.IsLoaded(assetName)) @@ -124,6 +128,29 @@ namespace StardewModdingAPI.Framework.ContentManagers return false; } + /// <summary>Parse an asset key that contains an explicit language into its asset name and language, if applicable.</summary> + /// <param name="rawAsset">The asset key to parse.</param> + /// <param name="assetName">The asset name without the language code.</param> + /// <param name="language">The language code removed from the asset name.</param> + private bool TryParseExplicitLanguageAssetKey(string rawAsset, out string assetName, out LanguageCode language) + { + if (string.IsNullOrWhiteSpace(rawAsset)) + throw new SContentLoadException("The asset key is empty."); + + // extract language code + int splitIndex = rawAsset.LastIndexOf('.'); + if (splitIndex != -1 && this.LanguageCodes.TryGetValue(rawAsset.Substring(splitIndex + 1), out language)) + { + assetName = rawAsset.Substring(0, splitIndex); + return true; + } + + // no explicit language code found + assetName = rawAsset; + language = this.Language; + return false; + } + /// <summary>Load the initial asset from the registered <see cref="Loaders"/>.</summary> /// <param name="info">The basic asset metadata.</param> /// <returns>Returns the loaded asset metadata, or <c>null</c> if no loader matched.</returns> diff --git a/src/SMAPI/Framework/ContentManagers/IContentManager.cs b/src/SMAPI/Framework/ContentManagers/IContentManager.cs index 1eb8b0ac..17618edd 100644 --- a/src/SMAPI/Framework/ContentManagers/IContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/IContentManager.cs @@ -80,7 +80,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <summary>Purge matched assets from the cache.</summary> /// <param name="predicate">Matches the asset keys to invalidate.</param> /// <param name="dispose">Whether to dispose invalidated assets. This should only be <c>true</c> when they're being invalidated as part of a dispose, to avoid crashing the game.</param> - /// <returns>Returns the number of invalidated assets.</returns> - IEnumerable<string> InvalidateCache(Func<string, Type, bool> predicate, bool dispose = false); + /// <returns>Returns the invalidated asset names and types.</returns> + IEnumerable<Tuple<string, Type>> InvalidateCache(Func<string, Type, bool> predicate, bool dispose = false); } } diff --git a/src/SMAPI/Framework/DeprecationManager.cs b/src/SMAPI/Framework/DeprecationManager.cs index 0fde67ee..be564c22 100644 --- a/src/SMAPI/Framework/DeprecationManager.cs +++ b/src/SMAPI/Framework/DeprecationManager.cs @@ -35,6 +35,12 @@ namespace StardewModdingAPI.Framework this.ModRegistry = modRegistry; } + /// <summary>Log a deprecation warning for the old-style events.</summary> + public void WarnForOldEvents() + { + this.Warn("legacy events", "2.9", DeprecationLevel.Notice); + } + /// <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> diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index b9d1c453..0ad85adf 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -1,5 +1,7 @@ using System.Diagnostics.CodeAnalysis; +#if !SMAPI_3_0_STRICT using Microsoft.Xna.Framework.Input; +#endif using StardewModdingAPI.Events; namespace StardewModdingAPI.Framework.Events @@ -156,6 +158,7 @@ namespace StardewModdingAPI.Framework.Events public readonly ManagedEvent<UnvalidatedUpdateTickedEventArgs> UnvalidatedUpdateTicked; +#if !SMAPI_3_0_STRICT /********* ** Events (old) *********/ @@ -342,6 +345,7 @@ namespace StardewModdingAPI.Framework.Events /// <summary>Raised after the in-game clock changes.</summary> public readonly ManagedEvent<EventArgsIntChanged> Legacy_TimeOfDayChanged; +#endif /********* @@ -354,7 +358,9 @@ namespace StardewModdingAPI.Framework.Events { // create shortcut initialisers 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); +#endif // init events (new) 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.UnvalidatedUpdateTicked = ManageEventOf<UnvalidatedUpdateTickedEventArgs>(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicked)); +#if !SMAPI_3_0_STRICT // init events (old) 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_TimeOfDayChanged = ManageEventOf<EventArgsIntChanged>(nameof(TimeEvents), nameof(TimeEvents.TimeOfDayChanged)); +#endif } } } diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs index 5e190e55..070d9c65 100644 --- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs @@ -21,8 +21,10 @@ namespace StardewModdingAPI.Framework.ModHelpers /// <summary>Create a transitional content pack.</summary> private readonly Func<string, IManifest, IContentPack> CreateContentPack; +#if !SMAPI_3_0_STRICT /// <summary>Manages deprecation warnings.</summary> private readonly DeprecationManager DeprecationManager; +#endif /********* @@ -31,8 +33,10 @@ namespace StardewModdingAPI.Framework.ModHelpers /// <summary>The full path to the mod's folder.</summary> public string DirectoryPath { get; } +#if !SMAPI_3_0_STRICT /// <summary>Encapsulates SMAPI's JSON file parsing.</summary> private readonly JsonHelper JsonHelper; +#endif /// <summary>Manages access to events raised by SMAPI, which let your mod react when something happens in the game.</summary> public IModEvents Events { get; } @@ -94,7 +98,6 @@ namespace StardewModdingAPI.Framework.ModHelpers // initialise this.DirectoryPath = modDirectory; - this.JsonHelper = jsonHelper ?? throw new ArgumentNullException(nameof(jsonHelper)); this.Content = contentHelper ?? throw new ArgumentNullException(nameof(contentHelper)); this.Data = dataHelper ?? throw new ArgumentNullException(nameof(dataHelper)); this.Input = new InputHelper(modID, inputState); @@ -105,8 +108,11 @@ namespace StardewModdingAPI.Framework.ModHelpers this.Translation = translationHelper ?? throw new ArgumentNullException(nameof(translationHelper)); this.ContentPacks = new Lazy<IContentPack[]>(contentPacks); this.CreateContentPack = createContentPack; - this.DeprecationManager = deprecationManager; this.Events = events; +#if !SMAPI_3_0_STRICT + this.JsonHelper = jsonHelper ?? throw new ArgumentNullException(nameof(jsonHelper)); + this.DeprecationManager = deprecationManager; +#endif } /**** @@ -131,6 +137,7 @@ namespace StardewModdingAPI.Framework.ModHelpers this.Data.WriteJsonFile("config.json", config); } +#if !SMAPI_3_0_STRICT /**** ** Generic JSON files ****/ @@ -159,23 +166,20 @@ namespace StardewModdingAPI.Framework.ModHelpers path = Path.Combine(this.DirectoryPath, PathUtilities.NormalisePathSeparators(path)); this.JsonHelper.WriteJsonFile(path, model); } +#endif /**** ** Content packs ****/ - /// <summary>Manually create a transitional content pack to support pre-SMAPI content packs. This provides a way to access legacy content packs using the SMAPI content pack APIs, but the content pack will not be visible in the log or validated by SMAPI.</summary> + /// <summary>Create a temporary content pack to read files from a directory. Temporary content packs will not appear in the SMAPI log and update checks will not be performed.</summary> /// <param name="directoryPath">The absolute directory path containing the content pack files.</param> /// <param name="id">The content pack's unique ID.</param> /// <param name="name">The content pack name.</param> /// <param name="description">The content pack description.</param> /// <param name="author">The content pack author's name.</param> /// <param name="version">The content pack version.</param> - [Obsolete("This method supports mods which previously had their own content packs, and shouldn't be used by new mods. It will be removed in SMAPI 3.0.")] - public IContentPack CreateTransitionalContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version) + public IContentPack CreateTemporaryContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version) { - // raise deprecation notice - this.DeprecationManager.Warn($"{nameof(IModHelper)}.{nameof(IModHelper.CreateTransitionalContentPack)}", "2.5", DeprecationLevel.Notice); - // validate if (string.IsNullOrWhiteSpace(directoryPath)) throw new ArgumentNullException(nameof(directoryPath)); @@ -200,6 +204,22 @@ namespace StardewModdingAPI.Framework.ModHelpers return this.CreateContentPack(directoryPath, manifest); } +#if !SMAPI_3_0_STRICT + /// <summary>Manually create a transitional content pack to support pre-SMAPI content packs. This provides a way to access legacy content packs using the SMAPI content pack APIs, but the content pack will not be visible in the log or validated by SMAPI.</summary> + /// <param name="directoryPath">The absolute directory path containing the content pack files.</param> + /// <param name="id">The content pack's unique ID.</param> + /// <param name="name">The content pack name.</param> + /// <param name="description">The content pack description.</param> + /// <param name="author">The content pack author's name.</param> + /// <param name="version">The content pack version.</param> + [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.CreateTemporaryContentPack) + " instead")] + public IContentPack CreateTransitionalContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version) + { + this.DeprecationManager.Warn($"{nameof(IModHelper)}.{nameof(IModHelper.CreateTransitionalContentPack)}", "2.5", DeprecationLevel.Notice); + return this.CreateTemporaryContentPack(directoryPath, id, name, description, author, version); + } +#endif + /// <summary>Get all content packs loaded for this mod.</summary> public IEnumerable<IContentPack> GetContentPacks() { diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index fdbfdd8d..7292cf3f 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -20,6 +20,9 @@ namespace StardewModdingAPI.Framework.ModLoading /// <summary>Encapsulates monitoring and logging.</summary> private readonly IMonitor Monitor; + /// <summary>Whether to detect paranoid mode issues.</summary> + private readonly bool ParanoidMode; + /// <summary>Metadata for mapping assemblies to the current platform.</summary> private readonly PlatformAssemblyMap AssemblyMap; @@ -39,9 +42,11 @@ namespace StardewModdingAPI.Framework.ModLoading /// <summary>Construct an instance.</summary> /// <param name="targetPlatform">The current game platform.</param> /// <param name="monitor">Encapsulates monitoring and logging.</param> - public AssemblyLoader(Platform targetPlatform, IMonitor monitor) + /// <param name="paranoidMode">Whether to detect paranoid mode issues.</param> + public AssemblyLoader(Platform targetPlatform, IMonitor monitor, bool paranoidMode) { this.Monitor = monitor; + this.ParanoidMode = paranoidMode; this.AssemblyMap = this.TrackForDisposal(Constants.GetAssemblyMap(targetPlatform)); this.AssemblyDefinitionResolver = this.TrackForDisposal(new AssemblyDefinitionResolver()); this.AssemblyDefinitionResolver.AddSearchDirectory(Constants.ExecutionPath); @@ -275,7 +280,7 @@ namespace StardewModdingAPI.Framework.ModLoading // find (and optionally rewrite) incompatible instructions bool anyRewritten = false; - IInstructionHandler[] handlers = new InstructionMetadata().GetHandlers().ToArray(); + IInstructionHandler[] handlers = new InstructionMetadata().GetHandlers(this.ParanoidMode).ToArray(); foreach (MethodDefinition method in this.GetMethods(module)) { // check method definition diff --git a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs index f3555c2d..6592760e 100644 --- a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs +++ b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs @@ -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> 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, /// <summary>The instruction accesses the filesystem directly.</summary> diff --git a/src/SMAPI/Framework/ModLoading/ModWarning.cs b/src/SMAPI/Framework/ModLoading/ModWarning.cs index c62199b2..e643cb05 100644 --- a/src/SMAPI/Framework/ModLoading/ModWarning.cs +++ b/src/SMAPI/Framework/ModLoading/ModWarning.cs @@ -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> 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, /// <summary>The mod has no update keys set.</summary> diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 4b95917b..800b9c09 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -99,11 +99,25 @@ namespace StardewModdingAPI.Framework new Regex(@"^static SerializableDictionary<.+>\(\) called\.$", RegexOptions.Compiled | RegexOptions.CultureInvariant), }; + /// <summary>Regex patterns which match console messages to show a more friendly error for.</summary> + private readonly Tuple<Regex, string, LogLevel>[] ReplaceConsolePatterns = + { + Tuple.Create( + new Regex(@"^System\.InvalidOperationException: Steamworks is not initialized\.", RegexOptions.Compiled | RegexOptions.CultureInvariant), +#if SMAPI_FOR_WINDOWS + "Oops! Steam achievements won't work because Steam isn't loaded. You can launch the game through Steam to fix that (see 'Part 2: Configure Steam' in the install guide for more info: https://smapi.io/install).", +#else + "Oops! Steam achievements won't work because Steam isn't loaded. You can launch the game through Steam to fix that.", +#endif + LogLevel.Error + ) + }; + /// <summary>The mod toolkit used for generic mod interactions.</summary> private readonly ModToolkit Toolkit = new ModToolkit(); /// <summary>The path to search for mods.</summary> - private readonly string ModsPath; + private string ModsPath => Constants.ModsPath; /********* @@ -117,7 +131,7 @@ namespace StardewModdingAPI.Framework // init paths this.VerifyPath(modsPath); this.VerifyPath(Constants.LogDir); - this.ModsPath = modsPath; + Constants.ModsPath = modsPath; // init log file this.PurgeNormalLogs(); @@ -180,20 +194,22 @@ namespace StardewModdingAPI.Framework // initialise SMAPI try { +#if !SMAPI_3_0_STRICT // hook up events - ContentEvents.Init(this.EventManager); - ControlEvents.Init(this.EventManager); - GameEvents.Init(this.EventManager); - GraphicsEvents.Init(this.EventManager); - InputEvents.Init(this.EventManager); - LocationEvents.Init(this.EventManager); - MenuEvents.Init(this.EventManager); - MineEvents.Init(this.EventManager); - MultiplayerEvents.Init(this.EventManager); - PlayerEvents.Init(this.EventManager); - SaveEvents.Init(this.EventManager); - SpecialisedEvents.Init(this.EventManager); - TimeEvents.Init(this.EventManager); + ContentEvents.Init(this.EventManager, this.DeprecationManager); + ControlEvents.Init(this.EventManager, this.DeprecationManager); + GameEvents.Init(this.EventManager, this.DeprecationManager); + GraphicsEvents.Init(this.EventManager, this.DeprecationManager); + InputEvents.Init(this.EventManager, this.DeprecationManager); + LocationEvents.Init(this.EventManager, this.DeprecationManager); + MenuEvents.Init(this.EventManager, this.DeprecationManager); + MineEvents.Init(this.EventManager, this.DeprecationManager); + MultiplayerEvents.Init(this.EventManager, this.DeprecationManager); + PlayerEvents.Init(this.EventManager, this.DeprecationManager); + SaveEvents.Init(this.EventManager, this.DeprecationManager); + SpecialisedEvents.Init(this.EventManager, this.DeprecationManager); + TimeEvents.Init(this.EventManager, this.DeprecationManager); +#endif // init JSON parser JsonConverter[] converters = { @@ -216,7 +232,7 @@ namespace StardewModdingAPI.Framework // override game 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; // add exit handler @@ -239,12 +255,13 @@ namespace StardewModdingAPI.Framework } }).Start(); - // hook into game events - ContentEvents.AfterLocaleChanged += (sender, e) => this.OnLocaleChanged(); - // set window titles this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion}"; 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) { @@ -348,8 +365,11 @@ namespace StardewModdingAPI.Framework private void InitialiseAfterGameStart() { // 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) - 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) 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) @@ -409,6 +429,11 @@ namespace StardewModdingAPI.Framework int modsLoaded = this.ModRegistry.GetAll().Count(); 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"; +#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 new Thread(this.RunConsoleLoop).Start(); @@ -701,7 +726,7 @@ namespace StardewModdingAPI.Framework // load mods IDictionary<IModMetadata, Tuple<string, string>> skippedMods = new Dictionary<IModMetadata, Tuple<string, string>>(); - using (AssemblyLoader modAssemblyLoader = new AssemblyLoader(Constants.Platform, this.Monitor)) + using (AssemblyLoader modAssemblyLoader = new AssemblyLoader(Constants.Platform, this.Monitor, this.Settings.ParanoidWarnings)) { // init HashSet<string> suppressUpdateChecks = new HashSet<string>(this.Settings.SuppressUpdateChecks, StringComparer.InvariantCultureIgnoreCase); @@ -891,11 +916,13 @@ namespace StardewModdingAPI.Framework return false; } +#if !SMAPI_3_0_STRICT // add deprecation warning for old version format { if (mod.Manifest?.Version is Toolkit.SemanticVersion version && version.IsLegacyFormat) this.DeprecationManager.Warn(mod.DisplayName, "non-string manifest version", "2.8", DeprecationLevel.Notice); } +#endif // validate dependencies // Although dependences are validated before mods are loaded, a dependency may have failed to load. @@ -1262,9 +1289,9 @@ namespace StardewModdingAPI.Framework } /// <summary>Redirect messages logged directly to the console to the given monitor.</summary> - /// <param name="monitor">The monitor with which to log messages.</param> + /// <param name="gameMonitor">The monitor with which to log messages as the game.</param> /// <param name="message">The message to log.</param> - private void HandleConsoleMessage(IMonitor monitor, string message) + private void HandleConsoleMessage(IMonitor gameMonitor, string message) { // detect exception LogLevel level = message.Contains("Exception") ? LogLevel.Error : LogLevel.Trace; @@ -1273,8 +1 |
