Optimize UI, add easily accessible restart code, fix bug in network manager RaiseEvent
This commit is contained in:
@@ -74,12 +74,17 @@ namespace Torch.API
|
|||||||
/// Stop the Torch instance.
|
/// Stop the Torch instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restart the Torch instance.
|
||||||
|
/// </summary>
|
||||||
|
void Restart();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a save of the game.
|
/// Initializes a save of the game.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="callerId">Id of the player who initiated the save.</param>
|
/// <param name="callerId">Id of the player who initiated the save.</param>
|
||||||
void Save(long callerId);
|
Task Save(long callerId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize the Torch instance.
|
/// Initialize the Torch instance.
|
||||||
|
@@ -14,12 +14,12 @@ namespace Torch.API.Managers
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when plugins are loaded.
|
/// Fired when plugins are loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event Action<List<ITorchPlugin>> PluginsLoaded;
|
event Action<IList<ITorchPlugin>> PluginsLoaded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Collection of loaded plugins.
|
/// Collection of loaded plugins.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ObservableCollection<ITorchPlugin> Plugins { get; }
|
IList<ITorchPlugin> Plugins { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates all loaded plugins.
|
/// Updates all loaded plugins.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.0.186.642")]
|
[assembly: AssemblyVersion("1.0.195.514")]
|
||||||
[assembly: AssemblyFileVersion("1.0.186.642")]
|
[assembly: AssemblyFileVersion("1.0.195.514")]
|
@@ -100,6 +100,8 @@ namespace Torch.Server
|
|||||||
var waitProc = Process.GetProcessById(pid);
|
var waitProc = Process.GetProcessById(pid);
|
||||||
_log.Warn($"Waiting for process {pid} to exit.");
|
_log.Warn($"Waiting for process {pid} to exit.");
|
||||||
waitProc.WaitForExit();
|
waitProc.WaitForExit();
|
||||||
|
_log.Info("Continuing in 5 seconds.");
|
||||||
|
Thread.Sleep(5000);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -245,8 +247,8 @@ quit";
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
_server = new TorchServer(config);
|
_server = new TorchServer(config);
|
||||||
_server.Init();
|
|
||||||
|
|
||||||
|
_server.Init();
|
||||||
if (config.NoGui || config.Autostart)
|
if (config.NoGui || config.Autostart)
|
||||||
{
|
{
|
||||||
new Thread(() => _server.Start()).Start();
|
new Thread(() => _server.Start()).Start();
|
||||||
@@ -255,7 +257,6 @@ quit";
|
|||||||
if (!config.NoGui)
|
if (!config.NoGui)
|
||||||
{
|
{
|
||||||
var ui = new TorchUI((TorchServer)_server);
|
var ui = new TorchUI((TorchServer)_server);
|
||||||
ui.LoadConfig(config);
|
|
||||||
ui.ShowDialog();
|
ui.ShowDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.0.186.642")]
|
[assembly: AssemblyVersion("1.0.195.514")]
|
||||||
[assembly: AssemblyFileVersion("1.0.186.642")]
|
[assembly: AssemblyFileVersion("1.0.195.514")]
|
@@ -24,7 +24,7 @@ namespace Torch.Server
|
|||||||
public bool Update { get; set; }
|
public bool Update { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[XmlIgnore, Arg("autostart", "Start the server immediately.")]
|
[Arg("autostart", "Start the server immediately.")]
|
||||||
public bool Autostart { get; set; }
|
public bool Autostart { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -32,7 +32,7 @@ namespace Torch.Server
|
|||||||
public bool RestartOnCrash { get; set; }
|
public bool RestartOnCrash { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[XmlIgnore, Arg("nogui", "Do not show the Torch UI.")]
|
[Arg("nogui", "Do not show the Torch UI.")]
|
||||||
public bool NoGui { get; set; }
|
public bool NoGui { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -10,6 +10,7 @@ using System.Reflection;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Xml.Serialization.GeneratedAssembly;
|
using Microsoft.Xml.Serialization.GeneratedAssembly;
|
||||||
using Sandbox.Engine.Analytics;
|
using Sandbox.Engine.Analytics;
|
||||||
using Sandbox.Game.Multiplayer;
|
using Sandbox.Game.Multiplayer;
|
||||||
@@ -20,6 +21,7 @@ using Torch.Managers;
|
|||||||
using VRage.Dedicated;
|
using VRage.Dedicated;
|
||||||
using VRage.FileSystem;
|
using VRage.FileSystem;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
using VRage.Game.ObjectBuilder;
|
using VRage.Game.ObjectBuilder;
|
||||||
using VRage.Game.SessionComponents;
|
using VRage.Game.SessionComponents;
|
||||||
using VRage.Library;
|
using VRage.Library;
|
||||||
@@ -49,6 +51,7 @@ namespace Torch.Server
|
|||||||
private float _simRatio;
|
private float _simRatio;
|
||||||
private readonly AutoResetEvent _stopHandle = new AutoResetEvent(false);
|
private readonly AutoResetEvent _stopHandle = new AutoResetEvent(false);
|
||||||
private Timer _watchdog;
|
private Timer _watchdog;
|
||||||
|
private Stopwatch _uptime;
|
||||||
|
|
||||||
public TorchServer(TorchConfig config = null)
|
public TorchServer(TorchConfig config = null)
|
||||||
{
|
{
|
||||||
@@ -133,6 +136,7 @@ namespace Torch.Server
|
|||||||
if (State != ServerState.Stopped)
|
if (State != ServerState.Stopped)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_uptime = Stopwatch.StartNew();
|
||||||
IsRunning = true;
|
IsRunning = true;
|
||||||
GameThread = Thread.CurrentThread;
|
GameThread = Thread.CurrentThread;
|
||||||
Config.Save();
|
Config.Save();
|
||||||
@@ -166,7 +170,8 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
SimulationRatio = Sync.ServerSimulationRatio;
|
SimulationRatio = Sync.ServerSimulationRatio;
|
||||||
ElapsedPlayTime = MySession.Static?.ElapsedPlayTime ?? default(TimeSpan);
|
var elapsed = TimeSpan.FromSeconds(Math.Floor(_uptime.Elapsed.TotalSeconds));
|
||||||
|
ElapsedPlayTime = elapsed;
|
||||||
|
|
||||||
if (_watchdog == null && Instance.Config.TickTimeout > 0)
|
if (_watchdog == null && Instance.Config.TickTimeout > 0)
|
||||||
{
|
{
|
||||||
@@ -215,15 +220,21 @@ namespace Torch.Server
|
|||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Restart()
|
/// <summary>
|
||||||
|
/// Restart the program. DOES NOT SAVE!
|
||||||
|
/// </summary>
|
||||||
|
public override void Restart()
|
||||||
{
|
{
|
||||||
|
var exe = Assembly.GetExecutingAssembly().Location;
|
||||||
|
((TorchConfig)Config).WaitForPID = Process.GetCurrentProcess().Id.ToString();
|
||||||
|
Process.Start(exe, Config.ToString());
|
||||||
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Save(long callerId)
|
public override Task Save(long callerId)
|
||||||
{
|
{
|
||||||
base.SaveGameAsync((statusCode) => SaveCompleted(statusCode, callerId));
|
return SaveGameAsync(statusCode => SaveCompleted(statusCode, callerId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -231,7 +242,7 @@ namespace Torch.Server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="statusCode">Return code of the save operation</param>
|
/// <param name="statusCode">Return code of the save operation</param>
|
||||||
/// <param name="callerId">Caller of the save operation</param>
|
/// <param name="callerId">Caller of the save operation</param>
|
||||||
private void SaveCompleted(SaveGameStatus statusCode, long callerId)
|
private void SaveCompleted(SaveGameStatus statusCode, long callerId = 0)
|
||||||
{
|
{
|
||||||
switch (statusCode)
|
switch (statusCode)
|
||||||
{
|
{
|
||||||
|
@@ -56,7 +56,7 @@ namespace Torch.Server.ViewModels
|
|||||||
|
|
||||||
public SessionSettingsViewModel SessionSettings { get; }
|
public SessionSettingsViewModel SessionSettings { get; }
|
||||||
|
|
||||||
public ObservableCollection<string> WorldPaths { get; } = new ObservableCollection<string>();
|
public ObservableList<string> WorldPaths { get; } = new ObservableList<string>();
|
||||||
private string _administrators;
|
private string _administrators;
|
||||||
public string Administrators { get => _administrators; set { _administrators = value; OnPropertyChanged(); } }
|
public string Administrators { get => _administrators; set { _administrators = value; OnPropertyChanged(); } }
|
||||||
private string _banned;
|
private string _banned;
|
||||||
|
@@ -15,7 +15,7 @@ namespace Torch.Server.ViewModels.Blocks
|
|||||||
public class BlockViewModel : EntityViewModel
|
public class BlockViewModel : EntityViewModel
|
||||||
{
|
{
|
||||||
public IMyTerminalBlock Block { get; }
|
public IMyTerminalBlock Block { get; }
|
||||||
public MTObservableCollection<PropertyViewModel> Properties { get; } = new MTObservableCollection<PropertyViewModel>();
|
public ObservableList<PropertyViewModel> Properties { get; } = new ObservableList<PropertyViewModel>();
|
||||||
|
|
||||||
public string FullName => $"{Block.CubeGrid.CustomName} - {Block.CustomName}";
|
public string FullName => $"{Block.CubeGrid.CustomName} - {Block.CustomName}";
|
||||||
|
|
||||||
@@ -24,8 +24,11 @@ namespace Torch.Server.ViewModels.Blocks
|
|||||||
get => Block?.CustomName ?? "null";
|
get => Block?.CustomName ?? "null";
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
TorchBase.Instance.InvokeBlocking(() => Block.CustomName = value);
|
TorchBase.Instance.Invoke(() =>
|
||||||
OnPropertyChanged();
|
{
|
||||||
|
Block.CustomName = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,8 +40,11 @@ namespace Torch.Server.ViewModels.Blocks
|
|||||||
get => ((MySlimBlock)Block.SlimBlock).BuiltBy;
|
get => ((MySlimBlock)Block.SlimBlock).BuiltBy;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
TorchBase.Instance.InvokeBlocking(() => ((MySlimBlock)Block.SlimBlock).TransferAuthorship(value));
|
TorchBase.Instance.Invoke(() =>
|
||||||
OnPropertyChanged();
|
{
|
||||||
|
((MySlimBlock)Block.SlimBlock).TransferAuthorship(value);
|
||||||
|
OnPropertyChanged();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,17 +16,15 @@ namespace Torch.Server.ViewModels.Blocks
|
|||||||
|
|
||||||
public T Value
|
public T Value
|
||||||
{
|
{
|
||||||
get
|
get => _prop.GetValue(Block.Block);
|
||||||
{
|
|
||||||
var val = default(T);
|
|
||||||
TorchBase.Instance.InvokeBlocking(() => val = _prop.GetValue(Block.Block));
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
TorchBase.Instance.InvokeBlocking(() => _prop.SetValue(Block.Block, value));
|
TorchBase.Instance.Invoke(() =>
|
||||||
OnPropertyChanged();
|
{
|
||||||
Block.RefreshModel();
|
_prop.SetValue(Block.Block, value);
|
||||||
|
OnPropertyChanged();
|
||||||
|
Block.RefreshModel();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -40,6 +40,7 @@ namespace Torch.Server.ViewModels.Entities
|
|||||||
public EntityViewModel(IMyEntity entity, EntityTreeViewModel tree)
|
public EntityViewModel(IMyEntity entity, EntityTreeViewModel tree)
|
||||||
{
|
{
|
||||||
Entity = entity;
|
Entity = entity;
|
||||||
|
Tree = tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityViewModel()
|
public EntityViewModel()
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox.Game.Entities;
|
using Sandbox.Game.Entities;
|
||||||
|
using Sandbox.Game.Multiplayer;
|
||||||
|
using Sandbox.Game.World;
|
||||||
using Sandbox.ModAPI;
|
using Sandbox.ModAPI;
|
||||||
using Torch.Server.ViewModels.Blocks;
|
using Torch.Server.ViewModels.Blocks;
|
||||||
|
|
||||||
@@ -9,17 +12,16 @@ namespace Torch.Server.ViewModels.Entities
|
|||||||
public class GridViewModel : EntityViewModel, ILazyLoad
|
public class GridViewModel : EntityViewModel, ILazyLoad
|
||||||
{
|
{
|
||||||
private MyCubeGrid Grid => (MyCubeGrid)Entity;
|
private MyCubeGrid Grid => (MyCubeGrid)Entity;
|
||||||
public MTObservableCollection<BlockViewModel> Blocks { get; } = new MTObservableCollection<BlockViewModel>();
|
public ObservableList<BlockViewModel> Blocks { get; } = new ObservableList<BlockViewModel>();
|
||||||
private static readonly Logger Log = LogManager.GetLogger(nameof(GridViewModel));
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string DescriptiveName => $"{Name} ({Grid.BlocksCount} blocks)";
|
public string DescriptiveName { get; }
|
||||||
|
|
||||||
public GridViewModel() { }
|
public GridViewModel() { }
|
||||||
|
|
||||||
public GridViewModel(MyCubeGrid grid, EntityTreeViewModel tree) : base(grid, tree)
|
public GridViewModel(MyCubeGrid grid, EntityTreeViewModel tree) : base(grid, tree)
|
||||||
{
|
{
|
||||||
Log.Debug($"Creating model {Grid.DisplayName}");
|
DescriptiveName = $"{grid.DisplayName} ({grid.BlocksCount} blocks)";
|
||||||
Blocks.Add(new BlockViewModel(null, Tree));
|
Blocks.Add(new BlockViewModel(null, Tree));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +30,6 @@ namespace Torch.Server.ViewModels.Entities
|
|||||||
if (obj.FatBlock != null)
|
if (obj.FatBlock != null)
|
||||||
Blocks.RemoveWhere(b => b.Block.EntityId == obj.FatBlock?.EntityId);
|
Blocks.RemoveWhere(b => b.Block.EntityId == obj.FatBlock?.EntityId);
|
||||||
|
|
||||||
Blocks.Sort(b => b.Block.GetType().AssemblyQualifiedName);
|
|
||||||
OnPropertyChanged(nameof(Name));
|
OnPropertyChanged(nameof(Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,9 +37,8 @@ namespace Torch.Server.ViewModels.Entities
|
|||||||
{
|
{
|
||||||
var block = obj.FatBlock as IMyTerminalBlock;
|
var block = obj.FatBlock as IMyTerminalBlock;
|
||||||
if (block != null)
|
if (block != null)
|
||||||
Blocks.Add(new BlockViewModel(block, Tree));
|
Blocks.Insert(new BlockViewModel(block, Tree), b => b.Name);
|
||||||
|
|
||||||
Blocks.Sort(b => b.Block.GetType().AssemblyQualifiedName);
|
|
||||||
OnPropertyChanged(nameof(Name));
|
OnPropertyChanged(nameof(Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,20 +48,23 @@ namespace Torch.Server.ViewModels.Entities
|
|||||||
if (_load)
|
if (_load)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Log.Debug($"Loading model {Grid.DisplayName}");
|
|
||||||
_load = true;
|
_load = true;
|
||||||
Blocks.Clear();
|
Blocks.Clear();
|
||||||
TorchBase.Instance.InvokeBlocking(() =>
|
TorchBase.Instance.Invoke(() =>
|
||||||
{
|
{
|
||||||
foreach (var block in Grid.GetFatBlocks().Where(b => b is IMyTerminalBlock))
|
foreach (var block in Grid.GetFatBlocks().Where(b => b is IMyTerminalBlock))
|
||||||
{
|
{
|
||||||
Blocks.Add(new BlockViewModel((IMyTerminalBlock)block, Tree));
|
Blocks.Add(new BlockViewModel((IMyTerminalBlock)block, Tree));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
Blocks.Sort(b => b.Block.GetType().AssemblyQualifiedName);
|
|
||||||
|
|
||||||
Grid.OnBlockAdded += Grid_OnBlockAdded;
|
Grid.OnBlockAdded += Grid_OnBlockAdded;
|
||||||
Grid.OnBlockRemoved += Grid_OnBlockRemoved;
|
Grid.OnBlockRemoved += Grid_OnBlockRemoved;
|
||||||
|
|
||||||
|
Tree.ControlDispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
Blocks.Sort(b => b.Block.CustomName);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,7 @@ namespace Torch.Server.ViewModels.Entities
|
|||||||
|
|
||||||
public override bool CanStop => false;
|
public override bool CanStop => false;
|
||||||
|
|
||||||
public MTObservableCollection<GridViewModel> AttachedGrids { get; } = new MTObservableCollection<GridViewModel>();
|
public ObservableList<GridViewModel> AttachedGrids { get; } = new ObservableList<GridViewModel>();
|
||||||
|
|
||||||
public async Task UpdateAttachedGrids()
|
public async Task UpdateAttachedGrids()
|
||||||
{
|
{
|
||||||
|
@@ -3,22 +3,28 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Controls;
|
||||||
using Sandbox.Game.Entities;
|
using Sandbox.Game.Entities;
|
||||||
using Sandbox.Game.Entities.Character;
|
using Sandbox.Game.Entities.Character;
|
||||||
using Torch.Server.ViewModels.Entities;
|
using Torch.Server.ViewModels.Entities;
|
||||||
using VRage.Game.ModAPI;
|
using VRage.Game.ModAPI;
|
||||||
using VRage.ModAPI;
|
using VRage.ModAPI;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
namespace Torch.Server.ViewModels
|
namespace Torch.Server.ViewModels
|
||||||
{
|
{
|
||||||
public class EntityTreeViewModel : ViewModel
|
public class EntityTreeViewModel : ViewModel
|
||||||
{
|
{
|
||||||
public MTObservableCollection<GridViewModel> Grids { get; set; } = new MTObservableCollection<GridViewModel>();
|
//TODO: these should be sorted sets for speed
|
||||||
public MTObservableCollection<CharacterViewModel> Characters { get; set; } = new MTObservableCollection<CharacterViewModel>();
|
public ObservableList<GridViewModel> Grids { get; set; } = new ObservableList<GridViewModel>();
|
||||||
public MTObservableCollection<EntityViewModel> FloatingObjects { get; set; } = new MTObservableCollection<EntityViewModel>();
|
public ObservableList<CharacterViewModel> Characters { get; set; } = new ObservableList<CharacterViewModel>();
|
||||||
public MTObservableCollection<VoxelMapViewModel> VoxelMaps { get; set; } = new MTObservableCollection<VoxelMapViewModel>();
|
public ObservableList<EntityViewModel> FloatingObjects { get; set; } = new ObservableList<EntityViewModel>();
|
||||||
|
public ObservableList<VoxelMapViewModel> VoxelMaps { get; set; } = new ObservableList<VoxelMapViewModel>();
|
||||||
|
public Dispatcher ControlDispatcher => _control.Dispatcher;
|
||||||
|
|
||||||
private EntityViewModel _currentEntity;
|
private EntityViewModel _currentEntity;
|
||||||
|
private UserControl _control;
|
||||||
|
|
||||||
public EntityViewModel CurrentEntity
|
public EntityViewModel CurrentEntity
|
||||||
{
|
{
|
||||||
@@ -26,7 +32,12 @@ namespace Torch.Server.ViewModels
|
|||||||
set { _currentEntity = value; OnPropertyChanged(); }
|
set { _currentEntity = value; OnPropertyChanged(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityTreeViewModel()
|
public EntityTreeViewModel(UserControl control)
|
||||||
|
{
|
||||||
|
_control = control;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init()
|
||||||
{
|
{
|
||||||
MyEntities.OnEntityAdd += MyEntities_OnEntityAdd;
|
MyEntities.OnEntityAdd += MyEntities_OnEntityAdd;
|
||||||
MyEntities.OnEntityRemove += MyEntities_OnEntityRemove;
|
MyEntities.OnEntityRemove += MyEntities_OnEntityRemove;
|
||||||
@@ -56,20 +67,16 @@ namespace Torch.Server.ViewModels
|
|||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case MyCubeGrid grid:
|
case MyCubeGrid grid:
|
||||||
if (Grids.All(g => g.Entity.EntityId != obj.EntityId))
|
Grids.Insert(new GridViewModel(grid, this), g => g.Name);
|
||||||
Grids.Add(new GridViewModel(grid, this));
|
|
||||||
break;
|
break;
|
||||||
case MyCharacter character:
|
case MyCharacter character:
|
||||||
if (Characters.All(g => g.Entity.EntityId != obj.EntityId))
|
Characters.Insert(new CharacterViewModel(character, this), c => c.Name);
|
||||||
Characters.Add(new CharacterViewModel(character, this));
|
|
||||||
break;
|
break;
|
||||||
case MyFloatingObject floating:
|
case MyFloatingObject floating:
|
||||||
if (FloatingObjects.All(g => g.Entity.EntityId != obj.EntityId))
|
FloatingObjects.Insert(new FloatingObjectViewModel(floating, this), f => f.Name);
|
||||||
FloatingObjects.Add(new FloatingObjectViewModel(floating, this));
|
|
||||||
break;
|
break;
|
||||||
case MyVoxelBase voxel:
|
case MyVoxelBase voxel:
|
||||||
if (VoxelMaps.All(g => g.Entity.EntityId != obj.EntityId))
|
VoxelMaps.Insert(new VoxelMapViewModel(voxel, this), v => v.Name);
|
||||||
VoxelMaps.Add(new VoxelMapViewModel(voxel, this));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ namespace Torch.Server.ViewModels
|
|||||||
{
|
{
|
||||||
public class PluginManagerViewModel : ViewModel
|
public class PluginManagerViewModel : ViewModel
|
||||||
{
|
{
|
||||||
public MTObservableCollection<PluginViewModel> Plugins { get; } = new MTObservableCollection<PluginViewModel>();
|
public ObservableList<PluginViewModel> Plugins { get; } = new ObservableList<PluginViewModel>();
|
||||||
|
|
||||||
private PluginViewModel _selectedPlugin;
|
private PluginViewModel _selectedPlugin;
|
||||||
public PluginViewModel SelectedPlugin
|
public PluginViewModel SelectedPlugin
|
||||||
@@ -24,10 +24,12 @@ namespace Torch.Server.ViewModels
|
|||||||
|
|
||||||
public PluginManagerViewModel(IPluginManager pluginManager)
|
public PluginManagerViewModel(IPluginManager pluginManager)
|
||||||
{
|
{
|
||||||
|
foreach (var plugin in pluginManager)
|
||||||
|
Plugins.Add(new PluginViewModel(plugin));
|
||||||
pluginManager.PluginsLoaded += PluginManager_PluginsLoaded;
|
pluginManager.PluginsLoaded += PluginManager_PluginsLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PluginManager_PluginsLoaded(List<ITorchPlugin> obj)
|
private void PluginManager_PluginsLoaded(IList<ITorchPlugin> obj)
|
||||||
{
|
{
|
||||||
Plugins.Clear();
|
Plugins.Clear();
|
||||||
foreach (var plugin in obj)
|
foreach (var plugin in obj)
|
||||||
|
@@ -35,7 +35,7 @@ namespace Torch.Server.ViewModels
|
|||||||
BlockLimits.Add(new BlockLimitViewModel(this, limit.Key, limit.Value));
|
BlockLimits.Add(new BlockLimitViewModel(this, limit.Key, limit.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MTObservableCollection<BlockLimitViewModel> BlockLimits { get; } = new MTObservableCollection<BlockLimitViewModel>();
|
public ObservableList<BlockLimitViewModel> BlockLimits { get; } = new ObservableList<BlockLimitViewModel>();
|
||||||
|
|
||||||
#region Multipliers
|
#region Multipliers
|
||||||
|
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
<TextBox x:Name="Message" DockPanel.Dock="Left" Margin="5,5,5,5" KeyDown="Message_OnKeyDown"></TextBox>
|
<TextBox x:Name="Message" DockPanel.Dock="Left" Margin="5,5,5,5" KeyDown="Message_OnKeyDown"></TextBox>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<ListView x:Name="ChatItems" ItemsSource="{Binding ChatHistory}" Margin="5,5,5,5">
|
<ListView x:Name="ChatItems" ItemsSource="{Binding ChatHistory}" Margin="5,5,5,5">
|
||||||
|
<ScrollViewer HorizontalScrollBarVisibility="Disabled"/>
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<WrapPanel>
|
<WrapPanel>
|
||||||
|
@@ -41,8 +41,10 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
_server = (TorchBase)server;
|
_server = (TorchBase)server;
|
||||||
_multiplayer = (MultiplayerManager)server.Multiplayer;
|
_multiplayer = (MultiplayerManager)server.Multiplayer;
|
||||||
|
ChatItems.Items.Clear();
|
||||||
DataContext = _multiplayer;
|
DataContext = _multiplayer;
|
||||||
_multiplayer.ChatHistory.CollectionChanged += ChatHistory_CollectionChanged;
|
if (_multiplayer.ChatHistory is INotifyCollectionChanged ncc)
|
||||||
|
ncc.CollectionChanged += ChatHistory_CollectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChatHistory_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
private void ChatHistory_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
@@ -74,22 +76,26 @@ namespace Torch.Server
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var commands = _server.Commands;
|
var commands = _server.Commands;
|
||||||
string response = null;
|
|
||||||
if (commands.IsCommand(text))
|
if (commands.IsCommand(text))
|
||||||
{
|
{
|
||||||
_multiplayer.ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", text));
|
_multiplayer.ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", text));
|
||||||
_server.InvokeBlocking(() =>
|
_server.Invoke(() =>
|
||||||
{
|
{
|
||||||
response = commands.HandleCommandFromServer(text);
|
var response = commands.HandleCommandFromServer(text);
|
||||||
|
Dispatcher.BeginInvoke(() => OnMessageEntered_Callback(response));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_server.Multiplayer.SendMessage(text);
|
_server.Multiplayer.SendMessage(text);
|
||||||
}
|
}
|
||||||
|
Message.Text = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMessageEntered_Callback(string response)
|
||||||
|
{
|
||||||
if (!string.IsNullOrEmpty(response))
|
if (!string.IsNullOrEmpty(response))
|
||||||
_multiplayer.ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", response));
|
_multiplayer.ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", response));
|
||||||
Message.Text = "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,7 +80,7 @@
|
|||||||
</DockPanel>
|
</DockPanel>
|
||||||
<Button Content="Add" Margin="3" Click="AddLimit_OnClick" />
|
<Button Content="Add" Margin="3" Click="AddLimit_OnClick" />
|
||||||
<ListView ItemsSource="{Binding BlockLimits}" Margin="3">
|
<ListView ItemsSource="{Binding BlockLimits}" Margin="3">
|
||||||
<ListBox.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBox Text="{Binding BlockType}" Width="150" Margin="3" />
|
<TextBox Text="{Binding BlockType}" Width="150" Margin="3" />
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
<Button Content=" X " Margin="3" Click="RemoveLimit_OnClick" />
|
<Button Content=" X " Margin="3" Click="RemoveLimit_OnClick" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListView.ItemTemplate>
|
||||||
</ListView>
|
</ListView>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Expander>
|
</Expander>
|
||||||
|
@@ -53,7 +53,6 @@ namespace Torch.Server.Views
|
|||||||
Log.Info("Saved DS config.");
|
Log.Info("Saved DS config.");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//var checkpoint = MyLocalCache.LoadCheckpoint(Config.LoadWorld, out _);
|
|
||||||
MyObjectBuilderSerializer.DeserializeXML(Path.Combine(Config.LoadWorld, "Sandbox.sbc"), out MyObjectBuilder_Checkpoint checkpoint, out ulong sizeInBytes);
|
MyObjectBuilderSerializer.DeserializeXML(Path.Combine(Config.LoadWorld, "Sandbox.sbc"), out MyObjectBuilder_Checkpoint checkpoint, out ulong sizeInBytes);
|
||||||
if (checkpoint == null)
|
if (checkpoint == null)
|
||||||
{
|
{
|
||||||
|
@@ -8,9 +8,6 @@
|
|||||||
xmlns:entities="clr-namespace:Torch.Server.ViewModels.Entities"
|
xmlns:entities="clr-namespace:Torch.Server.ViewModels.Entities"
|
||||||
xmlns:blocks="clr-namespace:Torch.Server.ViewModels.Blocks"
|
xmlns:blocks="clr-namespace:Torch.Server.ViewModels.Blocks"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<UserControl.DataContext>
|
|
||||||
<viewModels:EntityTreeViewModel />
|
|
||||||
</UserControl.DataContext>
|
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<DockPanel DockPanel.Dock="Left">
|
<DockPanel DockPanel.Dock="Left">
|
||||||
<StackPanel DockPanel.Dock="Bottom">
|
<StackPanel DockPanel.Dock="Bottom">
|
||||||
|
@@ -27,12 +27,14 @@ namespace Torch.Server.Views
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class EntitiesControl : UserControl
|
public partial class EntitiesControl : UserControl
|
||||||
{
|
{
|
||||||
public EntityTreeViewModel Entities { get; set; } = new EntityTreeViewModel();
|
public EntityTreeViewModel Entities { get; set; }
|
||||||
|
|
||||||
public EntitiesControl()
|
public EntitiesControl()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
Entities = new EntityTreeViewModel(this);
|
||||||
DataContext = Entities;
|
DataContext = Entities;
|
||||||
|
Entities.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||||
|
@@ -47,6 +47,7 @@ namespace Torch.Server
|
|||||||
Chat.BindServer(server);
|
Chat.BindServer(server);
|
||||||
PlayerList.BindServer(server);
|
PlayerList.BindServer(server);
|
||||||
Plugins.BindServer(server);
|
Plugins.BindServer(server);
|
||||||
|
LoadConfig((TorchConfig)server.Config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadConfig(TorchConfig config)
|
public void LoadConfig(TorchConfig config)
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
@@ -10,15 +9,18 @@ using System.Windows.Threading;
|
|||||||
|
|
||||||
namespace Torch
|
namespace Torch
|
||||||
{
|
{
|
||||||
|
[Obsolete("Use ObservableList<T>.")]
|
||||||
public class MTObservableCollection<T> : ObservableCollection<T>
|
public class MTObservableCollection<T> : ObservableCollection<T>
|
||||||
{
|
{
|
||||||
public override event NotifyCollectionChangedEventHandler CollectionChanged;
|
public override event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||||
|
|
||||||
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged;
|
NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged;
|
||||||
if (collectionChanged != null)
|
if (collectionChanged != null)
|
||||||
foreach (NotifyCollectionChangedEventHandler nh in collectionChanged.GetInvocationList())
|
foreach (var del in collectionChanged.GetInvocationList())
|
||||||
{
|
{
|
||||||
|
var nh = (NotifyCollectionChangedEventHandler)del;
|
||||||
var dispObj = nh.Target as DispatcherObject;
|
var dispObj = nh.Target as DispatcherObject;
|
||||||
|
|
||||||
var dispatcher = dispObj?.Dispatcher;
|
var dispatcher = dispObj?.Dispatcher;
|
||||||
|
186
Torch/Collections/ObservableList.cs
Normal file
186
Torch/Collections/ObservableList.cs
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace Torch
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An observable version of <see cref="List{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class ObservableList<T> : IList<T>, INotifyCollectionChanged, INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private List<T> _internalList = new List<T>();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_internalList.Clear();
|
||||||
|
OnPropertyChanged(nameof(Count));
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Contains(T item)
|
||||||
|
{
|
||||||
|
return _internalList.Contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void CopyTo(T[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
_internalList.CopyTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Remove(T item)
|
||||||
|
{
|
||||||
|
var oldIndex = _internalList.IndexOf(item);
|
||||||
|
if (!_internalList.Remove(item))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
OnPropertyChanged(nameof(Count));
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, oldIndex));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int Count => _internalList.Count;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Add(T item)
|
||||||
|
{
|
||||||
|
_internalList.Add(item);
|
||||||
|
OnPropertyChanged(nameof(Count));
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, Count - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int IndexOf(T item) => _internalList.IndexOf(item);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Insert(int index, T item)
|
||||||
|
{
|
||||||
|
_internalList.Insert(index, item);
|
||||||
|
OnPropertyChanged(nameof(Count));
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts an item in order based on the provided selector and comparer. This will only work properly on a pre-sorted list.
|
||||||
|
/// </summary>
|
||||||
|
public void Insert<TKey>(T item, Func<T, TKey> selector, IComparer<TKey> comparer = null)
|
||||||
|
{
|
||||||
|
comparer = comparer ?? Comparer<TKey>.Default;
|
||||||
|
var key1 = selector(item);
|
||||||
|
for (var i = 0; i < _internalList.Count; i++)
|
||||||
|
{
|
||||||
|
var key2 = selector(_internalList[i]);
|
||||||
|
if (comparer.Compare(key1, key2) < 1)
|
||||||
|
{
|
||||||
|
Insert(i, item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
var old = this[index];
|
||||||
|
_internalList.RemoveAt(index);
|
||||||
|
OnPropertyChanged(nameof(Count));
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, old, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
public T this[int index]
|
||||||
|
{
|
||||||
|
get => _internalList[index];
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var old = _internalList[index];
|
||||||
|
if (old.Equals(value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_internalList[index] = value;
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, old, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sorts the list using the given selector and comparer./>
|
||||||
|
/// </summary>
|
||||||
|
public void Sort<TKey>(Func<T, TKey> selector, IComparer<TKey> comparer = null)
|
||||||
|
{
|
||||||
|
comparer = comparer ?? Comparer<TKey>.Default;
|
||||||
|
var sortedItems = _internalList.OrderBy(selector, comparer).ToList();
|
||||||
|
|
||||||
|
_internalList = sortedItems;
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all items that satisfy the given condition.
|
||||||
|
/// </summary>
|
||||||
|
public void RemoveWhere(Func<T, bool> condition)
|
||||||
|
{
|
||||||
|
for (var i = Count - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
if (condition?.Invoke(this[i]) ?? false)
|
||||||
|
RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var collectionChanged = CollectionChanged;
|
||||||
|
if (collectionChanged != null)
|
||||||
|
foreach (var del in collectionChanged.GetInvocationList())
|
||||||
|
{
|
||||||
|
var nh = (NotifyCollectionChangedEventHandler)del;
|
||||||
|
var dispObj = nh.Target as DispatcherObject;
|
||||||
|
|
||||||
|
var dispatcher = dispObj?.Dispatcher;
|
||||||
|
if (dispatcher != null && !dispatcher.CheckAccess())
|
||||||
|
{
|
||||||
|
dispatcher.BeginInvoke(() => nh.Invoke(this, e), DispatcherPriority.DataBind);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nh.Invoke(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _internalList.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable)_internalList).GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -6,7 +6,10 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Torch
|
namespace Torch
|
||||||
{
|
{
|
||||||
public class CommandLine
|
/// <summary>
|
||||||
|
/// Base class that adds tools for setting type properties through the command line.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class CommandLine
|
||||||
{
|
{
|
||||||
private readonly string _argPrefix;
|
private readonly string _argPrefix;
|
||||||
private readonly Dictionary<ArgAttribute, PropertyInfo> _args = new Dictionary<ArgAttribute, PropertyInfo>();
|
private readonly Dictionary<ArgAttribute, PropertyInfo> _args = new Dictionary<ArgAttribute, PropertyInfo>();
|
||||||
|
@@ -21,7 +21,7 @@ namespace Torch.Commands
|
|||||||
public CommandTree Commands { get; set; } = new CommandTree();
|
public CommandTree Commands { get; set; } = new CommandTree();
|
||||||
private Logger _log = LogManager.GetLogger(nameof(CommandManager));
|
private Logger _log = LogManager.GetLogger(nameof(CommandManager));
|
||||||
|
|
||||||
public CommandManager(ITorchBase torch, char prefix = '/') : base(torch)
|
public CommandManager(ITorchBase torch, char prefix = '!') : base(torch)
|
||||||
{
|
{
|
||||||
Prefix = prefix;
|
Prefix = prefix;
|
||||||
}
|
}
|
||||||
|
@@ -45,6 +45,42 @@ namespace Torch.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Command("longhelp", "Get verbose help. Will send a long message, check the Comms tab.")]
|
||||||
|
public void LongHelp()
|
||||||
|
{
|
||||||
|
var commandManager = Context.Torch.GetManager<CommandManager>();
|
||||||
|
commandManager.Commands.GetNode(Context.Args, out CommandTree.CommandNode node);
|
||||||
|
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
var command = node.Command;
|
||||||
|
var children = node.Subcommands.Select(x => x.Key);
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
if (command != null)
|
||||||
|
{
|
||||||
|
sb.AppendLine($"Syntax: {command.SyntaxHelp}");
|
||||||
|
sb.Append(command.HelpText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.Subcommands.Count() != 0)
|
||||||
|
sb.Append($"\nSubcommands: {string.Join(", ", children)}");
|
||||||
|
|
||||||
|
Context.Respond(sb.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder("Available commands:\n");
|
||||||
|
foreach (var command in commandManager.Commands.WalkTree())
|
||||||
|
{
|
||||||
|
if (command.IsCommand)
|
||||||
|
sb.AppendLine($"{command.Command.SyntaxHelp}\n {command.Command.HelpText}");
|
||||||
|
}
|
||||||
|
Context.Respond(sb.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Command("ver", "Shows the running Torch version.")]
|
[Command("ver", "Shows the running Torch version.")]
|
||||||
[Permission(MyPromoteLevel.None)]
|
[Permission(MyPromoteLevel.None)]
|
||||||
public void Version()
|
public void Version()
|
||||||
@@ -62,11 +98,22 @@ namespace Torch.Commands
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Command("stop", "Stops the server.")]
|
[Command("stop", "Stops the server.")]
|
||||||
public void Stop()
|
public void Stop(bool save = true)
|
||||||
{
|
{
|
||||||
Context.Respond("Stopping server.");
|
Context.Respond("Stopping server.");
|
||||||
|
if (save)
|
||||||
|
Context.Torch.Save(Context.Player?.IdentityId ?? 0).Wait();
|
||||||
Context.Torch.Stop();
|
Context.Torch.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Command("restart", "Restarts the server.")]
|
||||||
|
public void Restart(bool save = true)
|
||||||
|
{
|
||||||
|
Context.Respond("Restarting server.");
|
||||||
|
if (save)
|
||||||
|
Context.Torch.Save(Context.Player?.IdentityId ?? 0).Wait();
|
||||||
|
Context.Torch.Restart();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a save of the game.
|
/// Initializes a save of the game.
|
||||||
|
17
Torch/DispatcherExtensions.cs
Normal file
17
Torch/DispatcherExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace Torch
|
||||||
|
{
|
||||||
|
public static class DispatcherExtensions
|
||||||
|
{
|
||||||
|
public static DispatcherOperation BeginInvoke(this Dispatcher dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal)
|
||||||
|
{
|
||||||
|
return dispatcher.BeginInvoke(priority, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,7 @@ using NLog;
|
|||||||
using Torch;
|
using Torch;
|
||||||
using Sandbox;
|
using Sandbox;
|
||||||
using Sandbox.Engine.Multiplayer;
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Sandbox.Game.Entities.Character;
|
||||||
using Sandbox.Game.Multiplayer;
|
using Sandbox.Game.Multiplayer;
|
||||||
using Sandbox.Game.World;
|
using Sandbox.Game.World;
|
||||||
using Sandbox.ModAPI;
|
using Sandbox.ModAPI;
|
||||||
@@ -43,7 +44,7 @@ namespace Torch.Managers
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public event MessageReceivedDel MessageReceived;
|
public event MessageReceivedDel MessageReceived;
|
||||||
|
|
||||||
public MTObservableCollection<IChatMessage> ChatHistory { get; } = new MTObservableCollection<IChatMessage>();
|
public IList<IChatMessage> ChatHistory { get; } = new ObservableList<IChatMessage>();
|
||||||
public ObservableDictionary<ulong, PlayerViewModel> Players { get; } = new ObservableDictionary<ulong, PlayerViewModel>();
|
public ObservableDictionary<ulong, PlayerViewModel> Players { get; } = new ObservableDictionary<ulong, PlayerViewModel>();
|
||||||
public IMyPlayer LocalPlayer => MySession.Static.LocalHumanPlayer;
|
public IMyPlayer LocalPlayer => MySession.Static.LocalHumanPlayer;
|
||||||
private static readonly Logger Log = LogManager.GetLogger(nameof(MultiplayerManager));
|
private static readonly Logger Log = LogManager.GetLogger(nameof(MultiplayerManager));
|
||||||
@@ -99,6 +100,17 @@ namespace Torch.Managers
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ulong GetSteamId(long identityId)
|
||||||
|
{
|
||||||
|
foreach (var kv in _onlinePlayers)
|
||||||
|
{
|
||||||
|
if (kv.Value.Identity.IdentityId == identityId)
|
||||||
|
return kv.Key.SteamId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetSteamUsername(ulong steamId)
|
public string GetSteamUsername(ulong steamId)
|
||||||
{
|
{
|
||||||
@@ -108,17 +120,24 @@ namespace Torch.Managers
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Red)
|
public void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Red)
|
||||||
{
|
{
|
||||||
ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", message));
|
ChatHistory.Add(new ChatMessage(DateTime.Now, 0, author, message));
|
||||||
var commands = Torch.GetManager<CommandManager>();
|
var commands = Torch.GetManager<CommandManager>();
|
||||||
if (commands.IsCommand(message))
|
if (commands.IsCommand(message))
|
||||||
{
|
{
|
||||||
var response = commands.HandleCommandFromServer(message);
|
var response = commands.HandleCommandFromServer(message);
|
||||||
ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", response));
|
ChatHistory.Add(new ChatMessage(DateTime.Now, 0, author, response));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var msg = new ScriptedChatMsg { Author = author, Font = font, Target = playerId, Text = message };
|
var msg = new ScriptedChatMsg { Author = author, Font = font, Target = playerId, Text = message };
|
||||||
MyMultiplayerBase.SendScriptedChatMessage(ref msg);
|
MyMultiplayerBase.SendScriptedChatMessage(ref msg);
|
||||||
|
var character = MySession.Static.Players.TryGetIdentity(playerId)?.Character;
|
||||||
|
var steamId = GetSteamId(playerId);
|
||||||
|
if (character == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var addToGlobalHistoryMethod = typeof(MyCharacter).GetMethod("OnGlobalMessageSuccess", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
Torch.GetManager<NetworkManager>().RaiseEvent(addToGlobalHistoryMethod, character, steamId, steamId, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -311,7 +311,7 @@ namespace Torch.Managers
|
|||||||
var parameters = method.GetParameters();
|
var parameters = method.GetParameters();
|
||||||
for (var i = 0; i < parameters.Length; i++)
|
for (var i = 0; i < parameters.Length; i++)
|
||||||
{
|
{
|
||||||
if (argTypes[i] != parameters[i].ParameterType)
|
if (argTypes[i + 1] != parameters[i].ParameterType)
|
||||||
throw new TypeLoadException($"Type mismatch on method parameters. Expected {string.Join(", ", parameters.Select(p => p.ParameterType.ToString()))} got {string.Join(", ", argTypes.Select(t => t.ToString()))}");
|
throw new TypeLoadException($"Type mismatch on method parameters. Expected {string.Join(", ", parameters.Select(p => p.ParameterType.ToString()))} got {string.Join(", ", argTypes.Select(t => t.ToString()))}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,9 +23,9 @@ namespace Torch.Managers
|
|||||||
private UpdateManager _updateManager;
|
private UpdateManager _updateManager;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ObservableCollection<ITorchPlugin> Plugins { get; } = new ObservableCollection<ITorchPlugin>();
|
public IList<ITorchPlugin> Plugins { get; } = new ObservableList<ITorchPlugin>();
|
||||||
|
|
||||||
public event Action<List<ITorchPlugin>> PluginsLoaded;
|
public event Action<IList<ITorchPlugin>> PluginsLoaded;
|
||||||
|
|
||||||
public PluginManager(ITorchBase torchInstance) : base(torchInstance)
|
public PluginManager(ITorchBase torchInstance) : base(torchInstance)
|
||||||
{
|
{
|
||||||
|
@@ -5,9 +5,24 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum SaveGameStatus : byte
|
public enum SaveGameStatus : byte
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The game was saved.
|
||||||
|
/// </summary>
|
||||||
Success = 0,
|
Success = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A save operation is already in progress.
|
||||||
|
/// </summary>
|
||||||
SaveInProgress = 1,
|
SaveInProgress = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The game is not in a save-able state.
|
||||||
|
/// </summary>
|
||||||
GameNotReady = 2,
|
GameNotReady = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The save operation timed out.
|
||||||
|
/// </summary>
|
||||||
TimedOut = 3
|
TimedOut = 3
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -146,6 +146,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ChatMessage.cs" />
|
<Compile Include="ChatMessage.cs" />
|
||||||
|
<Compile Include="Collections\ObservableList.cs" />
|
||||||
|
<Compile Include="DispatcherExtensions.cs" />
|
||||||
<Compile Include="SaveGameStatus.cs" />
|
<Compile Include="SaveGameStatus.cs" />
|
||||||
<Compile Include="Collections\KeyTree.cs" />
|
<Compile Include="Collections\KeyTree.cs" />
|
||||||
<Compile Include="Collections\ObservableDictionary.cs" />
|
<Compile Include="Collections\ObservableDictionary.cs" />
|
||||||
|
@@ -128,7 +128,7 @@ namespace Torch
|
|||||||
return Thread.CurrentThread.ManagedThreadId == MySandboxGame.Static.UpdateThread.ManagedThreadId;
|
return Thread.CurrentThread.ManagedThreadId == MySandboxGame.Static.UpdateThread.ManagedThreadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveGameAsync(Action<SaveGameStatus> callback)
|
public Task SaveGameAsync(Action<SaveGameStatus> callback)
|
||||||
{
|
{
|
||||||
Log.Info("Saving game");
|
Log.Info("Saving game");
|
||||||
|
|
||||||
@@ -142,26 +142,17 @@ namespace Torch
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using (var e = new AutoResetEvent(false))
|
var e = new AutoResetEvent(false);
|
||||||
{
|
MyAsyncSaving.Start(() => e.Set());
|
||||||
MyAsyncSaving.Start(() =>
|
|
||||||
{
|
|
||||||
MySector.ResetEyeAdaptation = true;
|
|
||||||
e.Set();
|
|
||||||
});
|
|
||||||
|
|
||||||
await Task.Run(() =>
|
return Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (e.WaitOne(60000))
|
callback?.Invoke(e.WaitOne(5000) ? SaveGameStatus.Success : SaveGameStatus.TimedOut);
|
||||||
{
|
e.Dispose();
|
||||||
callback?.Invoke(SaveGameStatus.Success);
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback?.Invoke(SaveGameStatus.TimedOut);
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Game Actions
|
#region Game Actions
|
||||||
@@ -306,19 +297,28 @@ namespace Torch
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual void Save(long callerId)
|
public virtual Task Save(long callerId)
|
||||||
{
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc
|
/// <inheritdoc/>
|
||||||
public virtual void Start()
|
public virtual void Start()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual void Stop() { }
|
public virtual void Stop()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void Restart()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
|
Reference in New Issue
Block a user