diff --git a/Torch.Server/CommandLine.cs b/Torch.Server/CommandLine.cs new file mode 100644 index 0000000..8567d38 --- /dev/null +++ b/Torch.Server/CommandLine.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Torch.Server +{ + public class CommandLine + { + public TorchConfig Config { get; } + private string _argPrefix; + + [Arg("instancepath", "Server data folder where saves and mods are stored")] + public string InstancePath { get => Config.InstancePath; set => Config.InstancePath = value; } + + public CommandLine(TorchConfig config, string argPrefix) + { + Config = config; + _argPrefix = argPrefix; + } + + public PropertyInfo[] GetArgs() + { + return typeof(CommandLine).GetProperties().Where(p => p.HasAttribute()).ToArray(); + } + + public string GetHelp() + { + var sb = new StringBuilder(); + + foreach (var property in GetArgs()) + { + var attr = property.GetCustomAttribute(); + sb.AppendLine($"{_argPrefix}{attr.Name.PadRight(20)}{attr.Description}"); + } + + return sb.ToString(); + } + + public void Run(string[] args) + { + if (args[0] == $"{_argPrefix}help") + { + Console.WriteLine(GetHelp()); + return; + } + + var properties = GetArgs(); + + for (var i = 0; i < args.Length; i++) + { + if (!args[i].StartsWith(_argPrefix)) + continue; + + foreach (var property in properties) + { + var argName = property.GetCustomAttribute()?.Name; + if (argName == null) + continue; + + try + { + if (string.Compare(argName, 0, args[i], 1, argName.Length, StringComparison.InvariantCultureIgnoreCase) == 0) + { + if (property.PropertyType == typeof(bool)) + property.SetValue(this, true); + + if (property.PropertyType == typeof(string)) + property.SetValue(this, args[++i]); + } + } + catch (Exception e) + { + Console.WriteLine($"Error parsing arg {argName}"); + } + } + } + + } + + private class ArgAttribute : Attribute + { + public string Name { get; } + public string Description { get; } + public ArgAttribute(string name, string description) + { + Name = name; + Description = description; + } + } + } +} diff --git a/Torch.Server/Torch.Server.csproj b/Torch.Server/Torch.Server.csproj index 3cceeb1..8a41e24 100644 --- a/Torch.Server/Torch.Server.csproj +++ b/Torch.Server/Torch.Server.csproj @@ -160,6 +160,7 @@ + True @@ -178,19 +179,18 @@ + + AddWorkshopItemsDialog.xaml ChatControl.xaml - - CollectionEditor.xaml - ConfigControl.xaml @@ -255,10 +255,6 @@ MSBuild:Compile Designer - - Designer - MSBuild:Compile - Designer MSBuild:Compile diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs index 03bef53..3236d26 100644 --- a/Torch.Server/TorchServer.cs +++ b/Torch.Server/TorchServer.cs @@ -67,7 +67,7 @@ namespace Torch.Server /// public override void Start() { - if (State > 0) + if (State != ServerState.Stopped) throw new InvalidOperationException("Server is already running."); Config.Save(); @@ -115,14 +115,12 @@ namespace Torch.Server Log.Info("Stopping server."); MySession.Static.Save(); MySession.Static.Unload(); - MySandboxGame.Static.Exit(); //Unload all the static junk. //TODO: Finish unloading all server data so it's in a completely clean state. MyFileSystem.Reset(); VRage.Input.MyGuiGameControlsHelpers.Reset(); VRage.Input.MyInput.UnloadData(); - //CleanupProfilers(); Log.Info("Server stopped."); _stopHandle.Set(); diff --git a/Torch.Server/ViewModels/CharacterViewModel.cs b/Torch.Server/ViewModels/CharacterViewModel.cs index f9c3bf3..fa392df 100644 --- a/Torch.Server/ViewModels/CharacterViewModel.cs +++ b/Torch.Server/ViewModels/CharacterViewModel.cs @@ -3,11 +3,16 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Sandbox.Game.Entities.Character; +using VRage.Game.ModAPI; namespace Torch.Server.ViewModels { - /* public class CharacterViewModel : EntityViewModel { - }*/ + public CharacterViewModel(MyCharacter character) : base(character) + { + + } + } } diff --git a/Torch.Server/ViewModels/EntityTreeViewModel.cs b/Torch.Server/ViewModels/EntityTreeViewModel.cs index 46ef9fc..34c0c43 100644 --- a/Torch.Server/ViewModels/EntityTreeViewModel.cs +++ b/Torch.Server/ViewModels/EntityTreeViewModel.cs @@ -3,18 +3,71 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Sandbox.Game.Entities; +using Sandbox.Game.Entities.Character; +using VRage.Game.ModAPI; +using VRage.ModAPI; namespace Torch.Server.ViewModels { - /* public class EntityTreeViewModel : ViewModel { - public string GridsHeader => null; - public MTObservableCollection<> + public MTObservableCollection Grids { get; set; } = new MTObservableCollection(); + public MTObservableCollection Characters { get; set; } = new MTObservableCollection(); + public MTObservableCollection FloatingObjects { get; set; } = new MTObservableCollection(); + public MTObservableCollection VoxelMaps { get; set; } = new MTObservableCollection(); - public void Refresh() + private EntityViewModel _currentEntity; + + public EntityViewModel CurrentEntity { - + get => _currentEntity; + set { _currentEntity = value; OnPropertyChanged(); } } - }*/ + + public EntityTreeViewModel() + { + MyEntities.OnEntityAdd += MyEntities_OnEntityAdd; + MyEntities.OnEntityRemove += MyEntities_OnEntityRemove; + } + + private void MyEntities_OnEntityRemove(VRage.Game.Entity.MyEntity obj) + { + switch (obj) + { + case MyCubeGrid grid: + Grids.RemoveWhere(m => m.Id == grid.EntityId); + break; + case MyCharacter character: + Characters.RemoveWhere(m => m.Id == character.EntityId); + break; + case MyFloatingObject floating: + FloatingObjects.RemoveWhere(m => m.Id == floating.EntityId); + break; + case MyVoxelBase voxel: + VoxelMaps.RemoveWhere(m => m.Id == voxel.EntityId); + break; + } + } + + private void MyEntities_OnEntityAdd(VRage.Game.Entity.MyEntity obj) + { + //TODO: make view models + switch (obj) + { + case MyCubeGrid grid: + Grids.Add(new GridViewModel(grid)); + break; + case MyCharacter character: + Characters.Add(new CharacterViewModel(character)); + break; + case MyFloatingObject floating: + FloatingObjects.Add(new FloatingObjectViewModel(floating)); + break; + case MyVoxelBase voxel: + VoxelMaps.Add(new VoxelMapViewModel(voxel)); + break; + } + } + } } diff --git a/Torch.Server/ViewModels/EntityViewModel.cs b/Torch.Server/ViewModels/EntityViewModel.cs index 31c9f65..a973653 100644 --- a/Torch.Server/ViewModels/EntityViewModel.cs +++ b/Torch.Server/ViewModels/EntityViewModel.cs @@ -3,29 +3,47 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using VRage.Game.ModAPI; using VRage.ModAPI; using VRageMath; namespace Torch.Server.ViewModels { - /* public class EntityViewModel : ViewModel { public IMyEntity Entity { get; } + public long Id => Entity.EntityId; - public string Name + public virtual string Name { - get { return Entity.DisplayName; } - set { TorchBase.Instance.i} + get => Entity.DisplayName; + set + { + TorchBase.Instance.InvokeBlocking(() => Entity.DisplayName = value); + OnPropertyChanged(); + } } - public string Position { get; } + public virtual string Position + { + get => Entity.GetPosition().ToString(); + set + { + if (!Vector3D.TryParse(value, out Vector3D v)) + return; + + TorchBase.Instance.InvokeBlocking(() => Entity.SetPosition(v)); + OnPropertyChanged(); + } + } + + public virtual bool CanStop => Entity.Physics?.Enabled ?? false; + + public virtual bool CanDelete => !(Entity is IMyCharacter); public EntityViewModel(IMyEntity entity) { Entity = entity; - Name = entity.DisplayName; - Position } - }*/ + } } diff --git a/Torch.Server/ViewModels/FloatingObjectViewModel.cs b/Torch.Server/ViewModels/FloatingObjectViewModel.cs new file mode 100644 index 0000000..f63df6c --- /dev/null +++ b/Torch.Server/ViewModels/FloatingObjectViewModel.cs @@ -0,0 +1,13 @@ +using Sandbox.Game.Entities; + +namespace Torch.Server.ViewModels +{ + public class FloatingObjectViewModel : EntityViewModel + { + private MyFloatingObject Floating => (MyFloatingObject)Entity; + + public override string Name => $"{base.Name} ({Floating.Amount})"; + + public FloatingObjectViewModel(MyFloatingObject floating) : base(floating) { } + } +} diff --git a/Torch.Server/ViewModels/GridViewModel.cs b/Torch.Server/ViewModels/GridViewModel.cs index e5ae6ba..259f15b 100644 --- a/Torch.Server/ViewModels/GridViewModel.cs +++ b/Torch.Server/ViewModels/GridViewModel.cs @@ -3,11 +3,21 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Sandbox.Game.Entities; +using VRage.Game.ModAPI; namespace Torch.Server.ViewModels { - /* public class GridViewModel : EntityViewModel { - }*/ + private MyCubeGrid Grid => (MyCubeGrid)Entity; + + /// + public override string Name => $"{base.Name} ({Grid.BlocksCount} blocks)"; + + public GridViewModel(MyCubeGrid grid) : base(grid) + { + + } + } } diff --git a/Torch.Server/ViewModels/VoxelMapViewModel.cs b/Torch.Server/ViewModels/VoxelMapViewModel.cs new file mode 100644 index 0000000..5f6bd0c --- /dev/null +++ b/Torch.Server/ViewModels/VoxelMapViewModel.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Medieval.ObjectBuilders.Definitions; +using Sandbox.Game.Entities; +using VRage.ModAPI; + +namespace Torch.Server.ViewModels +{ + public class VoxelMapViewModel : EntityViewModel + { + private MyVoxelBase Voxel => (MyVoxelBase)Entity; + + public override string Name => Voxel.StorageName; + + public override bool CanStop => false; + + public VoxelMapViewModel(MyVoxelBase e) : base(e) { } + } +} diff --git a/Torch.Server/Views/ConfigControl.xaml b/Torch.Server/Views/ConfigControl.xaml index 0bf2f5e..319622f 100644 --- a/Torch.Server/Views/ConfigControl.xaml +++ b/Torch.Server/Views/ConfigControl.xaml @@ -16,6 +16,7 @@ + @@ -47,6 +48,8 @@ + + diff --git a/Torch.Server/Views/ConfigControl.xaml.cs b/Torch.Server/Views/ConfigControl.xaml.cs index 56ee760..106c649 100644 --- a/Torch.Server/Views/ConfigControl.xaml.cs +++ b/Torch.Server/Views/ConfigControl.xaml.cs @@ -20,6 +20,7 @@ using Sandbox; using Sandbox.Engine.Networking; using Sandbox.Engine.Utils; using Torch.Server.ViewModels; +using Torch.Views; using VRage.Dedicated; using VRage.Game; using Path = System.IO.Path; @@ -43,18 +44,14 @@ namespace Torch.Server.Views public void SaveConfig() { Config.Save(_configPath); - //TODO: make this work try { var checkpoint = MyLocalCache.LoadCheckpoint(_viewModel.LoadWorld, out ulong size); - checkpoint.SessionName = _viewModel.WorldName; checkpoint.Settings = _viewModel.SessionSettings; checkpoint.Mods.Clear(); foreach (var modId in _viewModel.Mods) checkpoint.Mods.Add(new MyObjectBuilder_Checkpoint.ModItem(modId)); - Debug.Assert(checkpoint != null); - Debug.Assert(_viewModel.LoadWorld != null); MyLocalCache.SaveCheckpoint(checkpoint, _viewModel.LoadWorld); } catch (Exception e) @@ -106,5 +103,10 @@ namespace Torch.Server.Views var editor = new CollectionEditor { Owner = Window.GetWindow(this) }; editor.Edit(_viewModel.Mods, "Mods"); } + + private void Save_OnClick(object sender, RoutedEventArgs e) + { + SaveConfig(); + } } } diff --git a/Torch.Server/Views/EntitiesControl.xaml b/Torch.Server/Views/EntitiesControl.xaml index e03e46f..48f7be4 100644 --- a/Torch.Server/Views/EntitiesControl.xaml +++ b/Torch.Server/Views/EntitiesControl.xaml @@ -1,22 +1,64 @@  + + + - - +