diff --git a/Torch.Server/FlowDocumentTarget.cs b/Torch.Server/FlowDocumentTarget.cs
index daef655..353dcf7 100644
--- a/Torch.Server/FlowDocumentTarget.cs
+++ b/Torch.Server/FlowDocumentTarget.cs
@@ -10,6 +10,9 @@ using NLog.Targets;
namespace Torch.Server
{
+ ///
+ /// NLog target that writes to a .
+ ///
[Target("flowDocument")]
public sealed class FlowDocumentTarget : TargetWithLayout
{
diff --git a/Torch.Server/Initializer.cs b/Torch.Server/Initializer.cs
index d3f9205..1a36e4c 100644
--- a/Torch.Server/Initializer.cs
+++ b/Torch.Server/Initializer.cs
@@ -86,30 +86,21 @@ quit";
public void Run()
{
_server = new TorchServer(_config);
- try
+ var init = Task.Run(() => _server.Init());
+ if (!_config.NoGui)
{
- var init = Task.Run(() => _server.Init());
- if (!_config.NoGui)
- {
- if (_config.Autostart)
- init.ContinueWith(x => _server.Start());
+ if (_config.Autostart)
+ init.ContinueWith(x => _server.Start());
- Log.Info("Showing UI");
- Console.SetOut(TextWriter.Null);
- NativeMethods.FreeConsole();
- new TorchUI(_server).ShowDialog();
- }
- else
- {
- init.Wait();
- _server.Start();
- }
+ Log.Info("Showing UI");
+ Console.SetOut(TextWriter.Null);
+ NativeMethods.FreeConsole();
+ new TorchUI(_server).ShowDialog();
}
- catch
+ else
{
- if (_server.IsRunning)
- _server.Stop();
- _server.Destroy();
+ init.Wait();
+ _server.Start();
}
}
diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs
index 0e76378..fe67436 100644
--- a/Torch.Server/TorchServer.cs
+++ b/Torch.Server/TorchServer.cs
@@ -1,20 +1,31 @@
-using NLog;
-using Sandbox;
-using Sandbox.Game.Multiplayer;
-using Sandbox.Game.World;
+#region
+
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Net;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using System.Windows.Forms;
+using NLog;
+using Sandbox;
+using Sandbox.Engine.Networking;
+using Sandbox.Game.Multiplayer;
+using Sandbox.Game.World;
using Torch.API;
using Torch.API.Managers;
using Torch.API.Session;
using Torch.Server.Managers;
using Torch.Utils;
-using VRage.Game;
+using VRage;
+using VRage.Dedicated;
+using VRage.GameServices;
+using VRage.Steam;
+using Timer = System.Threading.Timer;
+
+#endregion
#pragma warning disable 618
@@ -22,76 +33,14 @@ namespace Torch.Server
{
public class TorchServer : TorchBase, ITorchServer
{
- //public MyConfigDedicated DedicatedConfig { get; set; }
- ///
- public float SimulationRatio
- {
- get => _simRatio;
- set
- {
- _simRatio = value;
- OnPropertyChanged();
- }
- }
-
- ///
- public TimeSpan ElapsedPlayTime
- {
- get => _elapsedPlayTime;
- set
- {
- _elapsedPlayTime = value;
- OnPropertyChanged();
- }
- }
-
- ///
- public Thread GameThread { get; private set; }
-
- ///
- public ServerState State
- {
- get => _state;
- private set
- {
- _state = value;
- OnPropertyChanged();
- }
- }
-
- ///
- public bool IsRunning
- {
- get => _isRunning;
- set
- {
- _isRunning = value;
- OnPropertyChanged();
- }
- }
-
private bool _canRun;
- public bool CanRun { get => _canRun; set => SetValue(ref _canRun, value); }
-
- private bool _hasRun;
-
- public event Action Initialized;
-
- ///
- public InstanceManager DedicatedInstance { get; }
-
- ///
- public string InstanceName => Config?.InstanceName;
-
- ///
- public string InstancePath => Config?.InstancePath;
-
- private bool _isRunning;
- private ServerState _state;
private TimeSpan _elapsedPlayTime;
+ private bool _hasRun;
+ private bool _isRunning;
private float _simRatio;
- private Timer _watchdog;
+ private ServerState _state;
private Stopwatch _uptime;
+ private Timer _watchdog;
///
public TorchServer(TorchConfig config = null)
@@ -102,22 +51,50 @@ namespace Torch.Server
Config = config ?? new TorchConfig();
var sessionManager = Managers.GetManager();
- sessionManager.AddFactory((x) => new MultiplayerManagerDedicated(this));
+ sessionManager.AddFactory(x => new MultiplayerManagerDedicated(this));
}
- ///
+ //public MyConfigDedicated DedicatedConfig { get; set; }
+ ///
+ public float SimulationRatio { get => _simRatio; set => SetValue(ref _simRatio, value); }
+
+ ///
+ public TimeSpan ElapsedPlayTime { get => _elapsedPlayTime; set => SetValue(ref _elapsedPlayTime, value); }
+
+ ///
+ public Thread GameThread { get; private set; }
+
+ ///
+ public bool IsRunning { get => _isRunning; set => SetValue(ref _isRunning, value); }
+
+ public bool CanRun { get => _canRun; set => SetValue(ref _canRun, value); }
+
+ ///
+ public InstanceManager DedicatedInstance { get; }
+
+ ///
+ public string InstanceName => Config?.InstanceName;
+
+ ///
protected override uint SteamAppId => 244850;
- ///
+ ///
protected override string SteamAppName => "SpaceEngineersDedicated";
+ ///
+ public ServerState State { get => _state; private set => SetValue(ref _state, value); }
+
+ public event Action Initialized;
+
+ ///
+ public string InstancePath => Config?.InstancePath;
+
///
public override void Init()
{
Log.Info("Initializing server");
- Sandbox.Engine.Platform.Game.IsDedicated = true;
+ MySandboxGame.IsDedicated = true;
base.Init();
-
Managers.GetManager().SessionStateChanged += OnSessionStateChanged;
GetManager().LoadInstance(Config.InstancePath);
CanRun = true;
@@ -125,15 +102,6 @@ namespace Torch.Server
Log.Info($"Initialized server '{Config.InstanceName}' at '{Config.InstancePath}'");
}
- private void OnSessionStateChanged(ITorchSession session, TorchSessionState newState)
- {
- if (newState == TorchSessionState.Unloading || newState == TorchSessionState.Unloaded)
- {
- _watchdog?.Dispose();
- _watchdog = null;
- }
- }
-
///
public override void Start()
{
@@ -173,7 +141,7 @@ namespace Torch.Server
}
///
- /// Restart the program.
+ /// Restart the program.
///
public override void Restart()
{
@@ -200,20 +168,24 @@ namespace Torch.Server
}
}
+ private void OnSessionStateChanged(ITorchSession session, TorchSessionState newState)
+ {
+ if (newState == TorchSessionState.Unloading || newState == TorchSessionState.Unloaded)
+ {
+ _watchdog?.Dispose();
+ _watchdog = null;
+ }
+ }
+
///
public override void Init(object gameInstance)
{
base.Init(gameInstance);
var game = gameInstance as MySandboxGame;
if (game != null && MySession.Static != null)
- {
State = ServerState.Running;
-// SteamServerAPI.Instance.GameServer.SetKeyValue("SM", "Torch");
- }
else
- {
State = ServerState.Stopped;
- }
}
///
@@ -238,7 +210,7 @@ namespace Torch.Server
private static void CheckServerResponding(object state)
{
var mre = new ManualResetEvent(false);
- ((TorchServer) state).Invoke(() => mre.Set());
+ ((TorchServer)state).Invoke(() => mre.Set());
if (!mre.WaitOne(TimeSpan.FromSeconds(Instance.Config.TickTimeout)))
{
#if DEBUG
@@ -250,10 +222,8 @@ namespace Torch.Server
throw new TimeoutException($"Server watchdog detected that the server was frozen for at least {((TorchServer)state).Config.TickTimeout} seconds.");
#endif
}
- else
- {
- Log.Debug("Server watchdog responded");
- }
+
+ Log.Debug("Server watchdog responded");
}
private static string DumpFrozenThread(Thread thread, int traces = 3, int pause = 5000)
@@ -267,6 +237,7 @@ namespace Torch.Server
stacks.Add(dump);
Thread.Sleep(pause);
}
+
string commonPrefix = StringUtils.CommonSuffix(stacks);
// Advance prefix to include the line terminator.
commonPrefix = commonPrefix.Substring(commonPrefix.IndexOf('\n') + 1);
@@ -280,6 +251,7 @@ namespace Torch.Server
result.AppendLine($"Suffix {i}");
result.AppendLine(stacks[i].Substring(0, stacks[i].Length - commonPrefix.Length));
}
+
return result.ToString();
}
@@ -293,6 +265,7 @@ namespace Torch.Server
{
// ignored
}
+
var stack = new StackTrace(thread, true);
try
{
@@ -302,6 +275,7 @@ namespace Torch.Server
{
// ignored
}
+
return stack;
}
diff --git a/Torch.Server/Views/ConfigControl.xaml b/Torch.Server/Views/ConfigControl.xaml
index 22fa24b..06ee641 100644
--- a/Torch.Server/Views/ConfigControl.xaml
+++ b/Torch.Server/Views/ConfigControl.xaml
@@ -13,7 +13,7 @@
-
+
@@ -38,8 +38,8 @@
-
-
+
+
@@ -50,74 +50,77 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
\ No newline at end of file
diff --git a/Torch.Server/Views/Entities/Blocks/BlockView.xaml b/Torch.Server/Views/Entities/Blocks/BlockView.xaml
index 53cca60..7bd42e7 100644
--- a/Torch.Server/Views/Entities/Blocks/BlockView.xaml
+++ b/Torch.Server/Views/Entities/Blocks/BlockView.xaml
@@ -14,8 +14,8 @@
-
+
@@ -25,7 +25,7 @@
-
+
diff --git a/Torch.Server/Views/EntitiesControl.xaml b/Torch.Server/Views/EntitiesControl.xaml
index 43e642e..39c508f 100644
--- a/Torch.Server/Views/EntitiesControl.xaml
+++ b/Torch.Server/Views/EntitiesControl.xaml
@@ -16,8 +16,8 @@
-
-
+
+
@@ -92,5 +92,6 @@
+
\ No newline at end of file
diff --git a/Torch.Server/Views/TorchUI.xaml b/Torch.Server/Views/TorchUI.xaml
index bdda27d..309840f 100644
--- a/Torch.Server/Views/TorchUI.xaml
+++ b/Torch.Server/Views/TorchUI.xaml
@@ -55,13 +55,18 @@
+
-
+
@@ -72,7 +77,7 @@
-
+
diff --git a/Torch.Server/Views/TorchUI.xaml.cs b/Torch.Server/Views/TorchUI.xaml.cs
index a274676..1524afe 100644
--- a/Torch.Server/Views/TorchUI.xaml.cs
+++ b/Torch.Server/Views/TorchUI.xaml.cs
@@ -16,9 +16,9 @@ using System.Windows.Shapes;
using NLog;
using Sandbox;
using Torch.API;
+using Torch.API.Managers;
using Torch.Server.Managers;
using MessageBoxResult = System.Windows.MessageBoxResult;
-using Timer = System.Timers.Timer;
namespace Torch.Server
{
@@ -93,7 +93,7 @@ namespace Torch.Server
if (_server?.State == ServerState.Running)
_server.Stop();
- Environment.Exit(0);
+ Process.GetCurrentProcess().Kill();
}
private void BtnRestart_Click(object sender, RoutedEventArgs e)
@@ -109,7 +109,7 @@ namespace Torch.Server
return;
_config.InstancePath = name;
- _server.GetManager().LoadInstance(_config.InstancePath);
+ _server.Managers.GetManager().LoadInstance(_config.InstancePath);
}
}
}
diff --git a/Torch/Torch.csproj b/Torch/Torch.csproj
index 0d00c1f..b5352d4 100644
--- a/Torch/Torch.csproj
+++ b/Torch/Torch.csproj
@@ -257,6 +257,9 @@
CollectionEditor.xaml
+
+ DictionaryEditor.xaml
+
PropertyGrid.xaml
@@ -277,6 +280,10 @@
MSBuild:Compile
Designer
+
+ MSBuild:Compile
+ Designer
+
MSBuild:Compile
Designer
diff --git a/Torch/Views/DictionaryEditor.xaml b/Torch/Views/DictionaryEditor.xaml
new file mode 100644
index 0000000..f1a1d69
--- /dev/null
+++ b/Torch/Views/DictionaryEditor.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Torch/Views/DictionaryEditor.xaml.cs b/Torch/Views/DictionaryEditor.xaml.cs
new file mode 100644
index 0000000..a81a034
--- /dev/null
+++ b/Torch/Views/DictionaryEditor.xaml.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using NLog;
+using Torch.Collections;
+
+namespace Torch.Views
+{
+ ///
+ /// Interaction logic for DictionaryEditorDialog.xaml
+ ///
+ public partial class DictionaryEditorDialog : Window
+ {
+ public DictionaryEditorDialog()
+ {
+ InitializeComponent();
+ DataContext = Items;
+ }
+
+ public ObservableCollection Items { get; } = new ObservableCollection();
+ private Type _itemType;
+
+ private Action _commitChanges;
+
+ public void Edit(IDictionary dict)
+ {
+ Items.Clear();
+ var dictType = dict.GetType();
+ _itemType = typeof(DictionaryItem<,>).MakeGenericType(dictType.GenericTypeArguments[0], dictType.GenericTypeArguments[1]);
+
+ foreach (var key in dict.Keys)
+ {
+ Items.Add((IDictionaryItem)Activator.CreateInstance(_itemType, key, dict[key]));
+ }
+
+ ItemGrid.ItemsSource = Items;
+
+ _commitChanges = () =>
+ {
+ dict.Clear();
+ foreach (var item in Items)
+ {
+ dict[item.Key] = item.Value;
+ }
+ };
+
+ Show();
+ }
+
+ private void Cancel_OnClick(object sender, RoutedEventArgs e)
+ {
+ Close();
+ }
+
+ private void Ok_OnClick(object sender, RoutedEventArgs e)
+ {
+ _commitChanges?.Invoke();
+ Close();
+ }
+
+ public interface IDictionaryItem
+ {
+ object Key { get; set; }
+ object Value { get; set; }
+ }
+
+ public class DictionaryItem : ViewModel, IDictionaryItem
+ {
+ private TKey _key;
+ private TValue _value;
+
+ object IDictionaryItem.Key { get => _key; set => SetValue(ref _key, (TKey)value); }
+ object IDictionaryItem.Value { get => _value; set => SetValue(ref _value, (TValue)value); }
+
+ public TKey Key { get => _key; set => SetValue(ref _key, value); }
+ public TValue Value { get => _value; set => SetValue(ref _value, value); }
+
+ public DictionaryItem()
+ {
+ _key = default(TKey);
+ _value = default(TValue);
+ }
+
+ public DictionaryItem(TKey key, TValue value)
+ {
+ _key = key;
+ _value = value;
+ }
+ }
+
+ private void AddNew_OnClick(object sender, RoutedEventArgs e)
+ {
+ Items.Add((IDictionaryItem)Activator.CreateInstance(_itemType));
+ }
+ }
+}
diff --git a/Torch/Views/PropertyGrid.xaml.cs b/Torch/Views/PropertyGrid.xaml.cs
index 422a80a..3439a7d 100644
--- a/Torch/Views/PropertyGrid.xaml.cs
+++ b/Torch/Views/PropertyGrid.xaml.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@@ -15,6 +16,7 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VRage.Game;
+using VRage.Serialization;
namespace Torch.Views
{
@@ -52,8 +54,8 @@ namespace Torch.Views
var properties = t.GetProperties(BindingFlags.Instance | BindingFlags.Public);
var grid = new Grid();
- grid.ColumnDefinitions.Add(new ColumnDefinition());
- grid.ColumnDefinitions.Add(new ColumnDefinition());
+ grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(2, GridUnitType.Star) });
+ grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
var curRow = 0;
foreach (var property in properties.OrderBy(x => x.Name))
@@ -64,6 +66,7 @@ namespace Torch.Views
grid.RowDefinitions.Add(new RowDefinition());
var displayName = property.GetCustomAttribute()?.Name;
+ var propertyType = property.PropertyType;
var text = new TextBlock
{
@@ -86,12 +89,12 @@ namespace Torch.Views
};
valueControl.SetBinding(TextBlock.TextProperty, binding);
}
- else if (property.PropertyType == typeof(bool) || property.PropertyType == typeof(bool?))
+ else if (propertyType == typeof(bool) || propertyType == typeof(bool?))
{
valueControl = new CheckBox();
valueControl.SetBinding(CheckBox.IsCheckedProperty, property.Name);
}
- else if (property.PropertyType.IsEnum)
+ else if (propertyType.IsEnum)
{
valueControl = new ComboBox
{
@@ -99,6 +102,28 @@ namespace Torch.Views
};
valueControl.SetBinding(ComboBox.SelectedItemProperty, property.Name);
}
+ else if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
+ {
+ var button = new Button
+ {
+ Content = "Edit Collection"
+ };
+ button.SetBinding(Button.DataContextProperty, property.Name);
+ button.Click += (sender, args) => EditDictionary(((Button)sender).DataContext);
+
+ valueControl = button;
+ }
+ else if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(SerializableDictionary<,>))
+ {
+ var button = new Button
+ {
+ Content = "Edit Collection"
+ };
+ button.SetBinding(Button.DataContextProperty, $"{property.Name}.Dictionary");
+ button.Click += (sender, args) => EditDictionary(((Button)sender).DataContext);
+
+ valueControl = button;
+ }
else
{
valueControl = new TextBox();
@@ -118,6 +143,12 @@ namespace Torch.Views
return grid;
}
+ private void EditDictionary(object dict)
+ {
+ var dic = (IDictionary)dict;
+ new DictionaryEditorDialog().Edit(dic);
+ }
+
private void UpdateFilter(object sender, TextChangedEventArgs e)
{
var filterText = ((TextBox)sender).Text;