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:
@@ -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();
|
||||
|
@@ -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,13 +18,25 @@ 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)
|
||||
Control = p.GetControl();
|
||||
|
||||
{
|
||||
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})";
|
||||
|
||||
ThemeControl.UpdateDynamicControls += UpdateResourceDict;
|
||||
|
272
Torch/Collections/BinaryMinHeap.cs
Normal file
272
Torch/Collections/BinaryMinHeap.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
134
Torch/Collections/SystemSortedView.cs
Normal file
134
Torch/Collections/SystemSortedView.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
@@ -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" />
|
||||
|
Reference in New Issue
Block a user