Log errors when a plugin's control throws exceptions instead of just letting WPF die.

Also add some new types for Essentials
This commit is contained in:
Brant Martin
2019-06-25 16:47:54 -04:00
parent ae3d1262f5
commit 3f7e95b502
6 changed files with 450 additions and 4 deletions

View File

@@ -55,6 +55,15 @@ quit";
AppDomain.CurrentDomain.UnhandledException += HandleException;
#endif
#if DEBUG
//enables logging debug messages when built in debug mode. Amazing.
LogManager.Configuration.AddRule(LogLevel.Debug, LogLevel.Debug, "main");
LogManager.Configuration.AddRule(LogLevel.Debug, LogLevel.Debug, "console");
LogManager.Configuration.AddRule(LogLevel.Debug, LogLevel.Debug, "wpf");
LogManager.ReconfigExistingLoggers();
Log.Debug("Debug logging enabled.");
#endif
// This is what happens when Keen is bad and puts extensions into the System namespace.
if (!Enumerable.Contains(args, "-noupdate"))
RunSteamCmd();

View File

@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using NLog;
using Torch.API;
using Torch.API.Plugins;
using Torch.Server.Views;
@@ -17,12 +18,24 @@ namespace Torch.Server.ViewModels
public string Name { get; }
public ITorchPlugin Plugin { get; }
private static Logger _log = LogManager.GetCurrentClassLogger();
public PluginViewModel(ITorchPlugin plugin)
{
Plugin = plugin;
if (Plugin is IWpfPlugin p)
{
try
{
Control = p.GetControl();
}
catch (Exception ex)
{
_log.Error(ex, $"Exception loading interface for plugin {Plugin.Name}! Plugin interface will not be available!");
Control = null;
}
}
Name = $"{plugin.Name} ({plugin.Version})";

View File

@@ -0,0 +1,272 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Torch.Collections
{
public class BinaryMinHeap<TKey, TValue> where TKey : IComparable
{
private struct HeapItem
{
public TKey Key { get; }
public TValue Value { get; }
public HeapItem(TKey key, TValue value)
{
Key = key;
Value = value;
}
}
private HeapItem[] _store;
private readonly IComparer<TKey> _comparer;
public int Capacity { get; private set; }
public int Count { get; private set; }
public bool Full => Count == Capacity;
public BinaryMinHeap(int initialCapacity = 32, IComparer<TKey> comparer = null)
{
_store = new HeapItem[initialCapacity];
Count = 0;
Capacity = initialCapacity;
_comparer = comparer ?? Comparer<TKey>.Default;
}
public void Insert(TValue value, TKey key)
{
EnsureCapacity(Capacity + 1);
var item = new HeapItem(key, value);
_store[Count] = item;
Up(Count);
Count++;
}
public TValue Min()
{
return _store[0].Value;
}
public TKey MinKey()
{
return _store[0].Key;
}
public TValue RemoveMin()
{
TValue toReturn = _store[0].Value;
if (Count != 1)
{
SwapIndices(Count - 1, 0);
_store[Count - 1] = default(HeapItem);
Count--;
Down(0);
}
else
{
Count--;
_store[0] = default(HeapItem);
}
return toReturn;
}
public TValue RemoveMax()
{
Debug.Assert(Count > 0);
var maxIndex = 0;
var maxItem = _store[0];
for (var i = 1; i < Count; ++i)
{
var c = _store[i];
if (_comparer.Compare(maxItem.Key, c.Key) < 0)
{
maxIndex = i;
maxItem = c;
}
}
if (maxIndex != Count)
{
SwapIndices(Count - 1, maxIndex);
Up(maxIndex);
}
Count--;
return maxItem.Value;
}
public TValue Remove(TValue value, IEqualityComparer<TValue> comparer = null)
{
if (Count == 0)
return default(TValue);
if (comparer == null)
comparer = EqualityComparer<TValue>.Default;
var itemIndex = -1;
for (var i = 0; i < Count; ++i)
{
if (comparer.Equals(value, _store[i].Value))
{
itemIndex = i;
break;
}
}
if (itemIndex != Count && itemIndex != -1)
{
TValue removed = _store[itemIndex].Value;
SwapIndices(Count - 1, itemIndex);
Up(itemIndex);
Down(itemIndex);
Count--;
return removed;
}
else
return default(TValue);
}
public TValue Remove(TKey key)
{
Debug.Assert(Count > 0);
var itemIndex = 0;
for (var i = 1; i < Count; ++i)
{
if (_comparer.Compare(key, _store[i].Key) == 0)
itemIndex = i;
}
TValue removed;
if (itemIndex != Count)
{
removed = _store[itemIndex].Value;
SwapIndices(Count - 1, itemIndex);
Up(itemIndex);
Down(itemIndex);
}
else
removed = default(TValue);
Count--;
return removed;
}
public void Clear()
{
Array.Clear(_store, 0, Capacity);
Count = 0;
}
private void Up(int index)
{
if (index == 0)
return;
int parentIndex = (index - 1) / 2;
HeapItem swap = _store[index];
if (_comparer.Compare(_store[parentIndex].Key, swap.Key) <= 0)
return;
while (true)
{
SwapIndices(parentIndex, index);
index = parentIndex;
if (index == 0)
break;
parentIndex = (index - 1) / 2;
if (_comparer.Compare(_store[parentIndex].Key, swap.Key) <= 0)
break;
}
InsertItem(ref swap, index);
}
private void Down(int index)
{
if (Count == index + 1)
return;
int left = index * 2 + 1;
int right = left + 1;
HeapItem swap = _store[index];
while (right <= Count) // While the current node has children
{
var nLeft = _store[left];
var nRight = _store[right];
if (right == Count || _comparer.Compare(nLeft.Key, nRight.Key) < 0) // Only the left child exists or the left child is smaller
{
if (_comparer.Compare(swap.Key, nLeft.Key) <= 0)
break;
SwapIndices(left, index);
index = left;
left = index * 2 + 1;
right = left + 1;
}
else // Right child exists and is smaller
{
if (_comparer.Compare(swap.Key, nRight.Key) <= 0)
break;
SwapIndices(right, index);
index = right;
left = index * 2 + 1;
right = left + 1;
}
}
InsertItem(ref swap, index);
}
private void SwapIndices(int fromIndex, int toIndex)
{
_store[toIndex] = _store[fromIndex];
}
private void InsertItem(ref HeapItem fromItem, int toIndex)
{
_store[toIndex] = fromItem;
}
public void EnsureCapacity(int capacity)
{
if (_store.Length >= capacity)
return;
//double capacity until we reach the minimum requested capacity (or greater)
int newcap = Capacity * 2;
while (newcap < capacity)
newcap *= 2;
var newArray = new HeapItem[newcap];
Array.Copy(_store, newArray, Capacity);
_store = newArray;
Capacity = newcap;
}
}
}

View File

@@ -2,13 +2,16 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Torch.Annotations;
namespace Torch.Collections
{
public class SortedView<T>: IReadOnlyCollection<T>, INotifyCollectionChanged
public class SortedView<T>: IReadOnlyCollection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
private readonly MtObservableCollectionBase<T> _backing;
private IComparer<T> _comparer;
@@ -21,9 +24,15 @@ namespace Torch.Collections
_store = new List<T>(_backing.Count);
_store.AddRange(_backing);
_backing.CollectionChanged += backing_CollectionChanged;
_backing.PropertyChanged += backing_PropertyChanged;
}
private void backing_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
private void backing_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(e.PropertyName);
}
private void backing_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
@@ -122,5 +131,12 @@ namespace Torch.Collections
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Torch.Annotations;
namespace Torch.Collections
{
public class SystemSortedView<T> : IReadOnlyCollection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
private readonly ObservableCollection<T> _backing;
private IComparer<T> _comparer;
private readonly List<T> _store;
public SystemSortedView(ObservableCollection<T> backing, IComparer<T> comparer)
{
_comparer = comparer;
_backing = backing;
_store = new List<T>(_backing.Count);
_store.AddRange(_backing);
_backing.CollectionChanged += backing_CollectionChanged;
}
private void backing_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
InsertSorted(e.NewItems);
CollectionChanged?.Invoke(this, e);
break;
case NotifyCollectionChangedAction.Remove:
_store.RemoveAll(r => e.OldItems.Contains(r));
CollectionChanged?.Invoke(this, e);
break;
case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Reset:
Refresh();
break;
default:
throw new ArgumentOutOfRangeException();
}
}
public IEnumerator<T> GetEnumerator()
{
return _store.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count => _backing.Count;
private void InsertSorted(IEnumerable items)
{
foreach (var t in items)
InsertSorted((T)t);
}
private int InsertSorted(T item, IComparer<T> comparer = null)
{
if (comparer == null)
comparer = _comparer;
if (_store.Count == 0 || comparer == null)
{
_store.Add(item);
return 0;
}
if (comparer.Compare(_store[_store.Count - 1], item) <= 0)
{
_store.Add(item);
return _store.Count - 1;
}
if (comparer.Compare(_store[0], item) >= 0)
{
_store.Insert(0, item);
return 0;
}
int index = _store.BinarySearch(item);
if (index < 0)
index = ~index;
_store.Insert(index, item);
return index;
}
public void Sort(IComparer<T> comparer = null)
{
if (comparer == null)
comparer = _comparer;
if (comparer == null)
return;
_store.Sort(comparer);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public void Refresh()
{
_store.Clear();
_store.AddRange(_backing);
Sort();
}
public void SetComparer(IComparer<T> comparer, bool resort = true)
{
_comparer = comparer;
if (resort)
Sort();
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@@ -193,12 +193,14 @@
<Compile Include="..\Versioning\AssemblyVersion.cs">
<Link>Properties\AssemblyVersion.cs</Link>
</Compile>
<Compile Include="Collections\BinaryMinHeap.cs" />
<Compile Include="Collections\MtObservableCollection.cs" />
<Compile Include="Collections\MtObservableCollectionBase.cs" />
<Compile Include="Collections\MtObservableSortedDictionary.cs" />
<Compile Include="Collections\MtObservableEvent.cs" />
<Compile Include="Collections\MtObservableList.cs" />
<Compile Include="Collections\SortedView.cs" />
<Compile Include="Collections\SystemSortedView.cs" />
<Compile Include="Collections\TransformComparer.cs" />
<Compile Include="Collections\TransformEnumerator.cs" />
<Compile Include="Commands\ConsoleCommandContext.cs" />