From 929dccb75a1405737975d76648e015a3e7c00177 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 7 Oct 2017 23:07:10 -0400 Subject: reorganise repo structure --- src/SMAPI/Framework/InternalExtensions.cs | 131 ++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/SMAPI/Framework/InternalExtensions.cs (limited to 'src/SMAPI/Framework/InternalExtensions.cs') diff --git a/src/SMAPI/Framework/InternalExtensions.cs b/src/SMAPI/Framework/InternalExtensions.cs new file mode 100644 index 00000000..3709e05d --- /dev/null +++ b/src/SMAPI/Framework/InternalExtensions.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Microsoft.Xna.Framework.Graphics; +using StardewModdingAPI.Framework.Reflection; +using StardewValley; + +namespace StardewModdingAPI.Framework +{ + /// Provides extension methods for SMAPI's internal use. + internal static class InternalExtensions + { + /**** + ** IMonitor + ****/ + /// Safely raise an event, and intercept any exceptions thrown by its handlers. + /// Encapsulates monitoring and logging. + /// The event name for error messages. + /// The event handlers. + /// The event sender. + /// The event arguments (or null to pass ). + public static void SafelyRaisePlainEvent(this IMonitor monitor, string name, IEnumerable handlers, object sender = null, EventArgs args = null) + { + if (handlers == null) + return; + + foreach (EventHandler handler in handlers.Cast()) + { + // handle SMAPI exiting + if (monitor.IsExiting) + { + monitor.Log($"SMAPI shutting down: aborting {name} event.", LogLevel.Warn); + return; + } + + // raise event + try + { + handler.Invoke(sender, args ?? EventArgs.Empty); + } + catch (Exception ex) + { + monitor.Log($"A mod failed handling the {name} event:\n{ex.GetLogSummary()}", LogLevel.Error); + } + } + } + + /// Safely raise an event, and intercept any exceptions thrown by its handlers. + /// The event argument object type. + /// Encapsulates monitoring and logging. + /// The event name for error messages. + /// The event handlers. + /// The event sender. + /// The event arguments. + public static void SafelyRaiseGenericEvent(this IMonitor monitor, string name, IEnumerable handlers, object sender, TEventArgs args) + { + if (handlers == null) + return; + + foreach (EventHandler handler in handlers.Cast>()) + { + try + { + handler.Invoke(sender, args); + } + catch (Exception ex) + { + monitor.Log($"A mod failed handling the {name} event:\n{ex.GetLogSummary()}", LogLevel.Error); + } + } + } + + /// Log a message for the player or developer the first time it occurs. + /// The monitor through which to log the message. + /// The hash of logged messages. + /// The message to log. + /// The log severity level. + public static void LogOnce(this IMonitor monitor, HashSet hash, string message, LogLevel level = LogLevel.Trace) + { + if (!hash.Contains(message)) + { + monitor.Log(message, level); + hash.Add(message); + } + } + + /**** + ** Exceptions + ****/ + /// Get a string representation of an exception suitable for writing to the error log. + /// The error to summarise. + public static string GetLogSummary(this Exception exception) + { + switch (exception) + { + case TypeLoadException ex: + return $"Failed loading type '{ex.TypeName}': {exception}"; + + case ReflectionTypeLoadException ex: + string summary = exception.ToString(); + foreach (Exception childEx in ex.LoaderExceptions) + summary += $"\n\n{childEx.GetLogSummary()}"; + return summary; + + default: + return exception.ToString(); + } + } + + /**** + ** Sprite batch + ****/ + /// Get whether the sprite batch is between a begin and end pair. + /// The sprite batch to check. + /// The reflection helper with which to access private fields. + public static bool IsOpen(this SpriteBatch spriteBatch, Reflector reflection) + { + // get field name + const string fieldName = +#if SMAPI_FOR_WINDOWS + "inBeginEndPair"; +#else + "_beginCalled"; +#endif + + // get result + return reflection.GetPrivateField(Game1.spriteBatch, fieldName).GetValue(); + } + } +} -- cgit