using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using StardewModdingAPI.Framework; namespace StardewModdingAPI.Events { /// Events raised when the game loads content. public static class ContentEvents { /********* ** Properties *********/ /// Tracks the installed mods. private static ModRegistry ModRegistry; /// Encapsulates monitoring and logging. private static IMonitor Monitor; /// The mods using the experimental API for which a warning has been raised. private static readonly HashSet WarnedMods = new HashSet(); /// The backing field for . [SuppressMessage("ReSharper", "InconsistentNaming")] private static event EventHandler _AfterAssetLoaded; /********* ** Events *********/ /// Raised after the content language changes. public static event EventHandler> AfterLocaleChanged; /// Raised when an XNB file is being read into the cache. Mods can change the data here before it's cached. #if EXPERIMENTAL public #else internal #endif static event EventHandler AfterAssetLoaded { add { ContentEvents.RaiseContentExperimentalWarning(); ContentEvents._AfterAssetLoaded += value; } remove => ContentEvents._AfterAssetLoaded -= value; } /********* ** Internal methods *********/ /// Injects types required for backwards compatibility. /// Tracks the installed mods. /// Encapsulates monitoring and logging. internal static void Shim(ModRegistry modRegistry, IMonitor monitor) { ContentEvents.ModRegistry = modRegistry; ContentEvents.Monitor = monitor; } /// Raise an event. /// Encapsulates monitoring and logging. /// The previous locale. /// The current locale. internal static void InvokeAfterLocaleChanged(IMonitor monitor, string oldLocale, string newLocale) { monitor.SafelyRaiseGenericEvent($"{nameof(ContentEvents)}.{nameof(ContentEvents.AfterLocaleChanged)}", ContentEvents.AfterLocaleChanged?.GetInvocationList(), null, new EventArgsValueChanged(oldLocale, newLocale)); } /// Raise an event. /// Encapsulates monitoring and logging. /// Encapsulates access and changes to content being read from a data file. internal static void InvokeAfterAssetLoaded(IMonitor monitor, IContentEventHelper contentHelper) { monitor.SafelyRaiseGenericEvent($"{nameof(ContentEvents)}.{nameof(ContentEvents.AfterAssetLoaded)}", ContentEvents._AfterAssetLoaded?.GetInvocationList(), null, contentHelper); } /********* ** Private methods *********/ /// Raise an 'experimental API' warning for a mod using the content API. private static void RaiseContentExperimentalWarning() { string modName = ContentEvents.ModRegistry.GetModFromStack() ?? "An unknown mod"; if (!ContentEvents.WarnedMods.Contains(modName)) { ContentEvents.WarnedMods.Add(modName); ContentEvents.Monitor.Log($"{modName} used the undocumented and experimental content API, which may change or be removed without warning.", LogLevel.Warn); } } } }