diff --git a/.gitignore b/.gitignore index 717f1a0..e6bc0c6 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ Thumbs.db *.log [Bb]in [Dd]ebug*/ +![Dd]ebugging*/ *.lib *.sbr obj/ diff --git a/Source/MDK/Debugging/TriggerTracing.cs b/Source/MDK/Debugging/TriggerTracing.cs new file mode 100644 index 0000000..6ebccab --- /dev/null +++ b/Source/MDK/Debugging/TriggerTracing.cs @@ -0,0 +1,211 @@ +using System.Diagnostics; +using System.Windows; +using System.Windows.Markup; +using System.Windows.Media.Animation; + +// Code from http://www.wpfmentor.com/2009/01/how-to-debug-triggers-using-trigger.html +// No license specified - this code is trimmed out from Release build anyway so it should be ok using it this way + +// HOWTO: add the following attached property to any trigger and you will see when it is activated/deactivated in the output window +// TriggerTracing.TriggerName="your debug name" +// TriggerTracing.TraceEnabled="True" + +// Example: +// +// +// +// +// As this works on anything that inherits from TriggerBase, it will also work on . + +namespace MDK.Debugging +{ +#if DEBUG + + /// + /// Contains attached properties to activate Trigger Tracing on the specified Triggers. + /// This file alone should be dropped into your app. + /// + public static class TriggerTracing + { + static TriggerTracing() + { + // Initialise WPF Animation tracing and add a TriggerTraceListener + PresentationTraceSources.Refresh(); + PresentationTraceSources.AnimationSource.Listeners.Clear(); + PresentationTraceSources.AnimationSource.Listeners.Add(new TriggerTraceListener()); + PresentationTraceSources.AnimationSource.Switch.Level = SourceLevels.All; + } + + #region TriggerName attached property + + /// + /// Gets the trigger name for the specified trigger. This will be used + /// to identify the trigger in the debug output. + /// + /// The trigger. + /// + public static string GetTriggerName(TriggerBase trigger) + { + return (string)trigger.GetValue(TriggerNameProperty); + } + + /// + /// Sets the trigger name for the specified trigger. This will be used + /// to identify the trigger in the debug output. + /// + /// The trigger. + /// + /// + public static void SetTriggerName(TriggerBase trigger, string value) + { + trigger.SetValue(TriggerNameProperty, value); + } + + /// + /// + /// + public static readonly DependencyProperty TriggerNameProperty = + DependencyProperty.RegisterAttached( + "TriggerName", + typeof(string), + typeof(TriggerTracing), + new UIPropertyMetadata(string.Empty)); + + #endregion + + #region TraceEnabled attached property + + /// + /// Gets a value indication whether trace is enabled for the specified trigger. + /// + /// The trigger. + /// + public static bool GetTraceEnabled(TriggerBase trigger) + { + return (bool)trigger.GetValue(TraceEnabledProperty); + } + + /// + /// Sets a value specifying whether trace is enabled for the specified trigger + /// + /// + /// + public static void SetTraceEnabled(TriggerBase trigger, bool value) + { + trigger.SetValue(TraceEnabledProperty, value); + } + + /// + /// + /// + public static readonly DependencyProperty TraceEnabledProperty = + DependencyProperty.RegisterAttached( + "TraceEnabled", + typeof(bool), + typeof(TriggerTracing), + new UIPropertyMetadata(false, OnTraceEnabledChanged)); + + private static void OnTraceEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var triggerBase = d as TriggerBase; + + if (triggerBase == null) + return; + + if (!(e.NewValue is bool)) + return; + + if ((bool)e.NewValue) + { + // insert dummy story-boards which can later be traced using WPF animation tracing + + var storyboard = new TriggerTraceStoryboard(triggerBase, TriggerTraceStoryboardType.Enter); + triggerBase.EnterActions.Insert(0, new BeginStoryboard() { Storyboard = storyboard }); + + storyboard = new TriggerTraceStoryboard(triggerBase, TriggerTraceStoryboardType.Exit); + triggerBase.ExitActions.Insert(0, new BeginStoryboard() { Storyboard = storyboard }); + } + else + { + // remove the dummy storyboards + + foreach (var actionCollection in new[] { triggerBase.EnterActions, triggerBase.ExitActions }) + { + foreach (var triggerAction in actionCollection) + { + if (triggerAction is BeginStoryboard bsb && bsb.Storyboard is TriggerTraceStoryboard) + { + actionCollection.Remove(bsb); + break; + } + } + } + } + } + + #endregion + + private enum TriggerTraceStoryboardType + { + Enter, Exit + } + + /// + /// A dummy storyboard for tracing purposes + /// + private class TriggerTraceStoryboard : Storyboard + { + public TriggerTraceStoryboardType StoryboardType { get; } + public TriggerBase TriggerBase { get; } + + public TriggerTraceStoryboard(TriggerBase triggerBase, TriggerTraceStoryboardType storyboardType) + { + TriggerBase = triggerBase; + StoryboardType = storyboardType; + } + } + + /// + /// A custom tracelistener. + /// + private class TriggerTraceListener : TraceListener + { + public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args) + { + base.TraceEvent(eventCache, source, eventType, id, format, args); + + if (format.StartsWith("Storyboard has begun;")) + { + if (args[1] is TriggerTraceStoryboard storyboard) + { + // add a breakpoint here to see when your trigger has been + // entered or exited + + // the element being acted upon + var targetElement = args[5]; + + // the namescope of the element being acted upon + var namescope = (INameScope)args[7]; + + var triggerBase = storyboard.TriggerBase; + var triggerName = GetTriggerName(storyboard.TriggerBase); + + Debug.WriteLine($"Element: {targetElement}, {triggerBase.GetType().Name}: {triggerName}: {storyboard.StoryboardType}"); + } + } + } + + public override void Write(string message) + { + } + + public override void WriteLine(string message) + { + } + } + } +#endif +} \ No newline at end of file diff --git a/Source/changelog.1.2.0.md b/Source/changelog.1.2.0.md index aec1425..34a3858 100644 --- a/Source/changelog.1.2.0.md +++ b/Source/changelog.1.2.0.md @@ -1,5 +1,21 @@ -Changed how script options are stored in order to make it easier to work on projects on multiple computers -Renamed Blueprint Manager to Script Manager -Deprecated Readme.cs (more or less), changed to Instructions.readme and added item template for it -Fixed crash while VS is trying to read a project from a network (MDK will ignore this case) -Added project template for ingame script mixin (shared project) \ No newline at end of file + +- #111 thumb.jpg in existing scripts not recognized in blueprint manager +- #124 [PRE] [VS2019] Error when attempting to create a new Project +- #125 [PRE] [VS2019] New projects default to C# 7 or higher. +- #130 Suggestion: Refreshing whitelist runs SE; Add -skipintro to not show intro video + +- Changed how script options are stored in order to make it easier to work on projects on multiple computers +- Renamed Blueprint Manager to Script Manager +- Deprecated Readme.cs (more or less), changed to Instructions.readme and added item template for it +- Fixed crash while VS is trying to read a project from a network (MDK will ignore this case) +- Added project template for ingame script mixin (shared project) +- MDK is now more code repository (for example git) friendly. + - The paths are now stored in a separate file, MDK.paths.props, which should not be checked in. + The file should be restored on the other side. +- Backup zips are made before any project upgrades or repairs are made +- Finalizers are reported as prohibited +- Experimental VS2019 support +- Proper install-time version checking, finally +- Fixed #98 Unimportant Non-SE Project Error +- Added #99 Include "Do not deploy" option in MDK Script Options window / #79 Deploy option in files. + "Exclude from Deploy All" checkbox \ No newline at end of file