From 1251b945bcd43715478c524859765adcd1be8f7d Mon Sep 17 00:00:00 2001 From: Alexander Qvist-Hellum Date: Thu, 6 Jul 2017 16:18:10 +0200 Subject: [PATCH 1/2] Added async /save command for admins+ and server console. Redesigned TorchBase.SaveGameAsync to take a callback function for error/success handling. Also removed local host checks as we are hosting a dedicated server. --- Torch.API/ITorchBase.cs | 1 + Torch.Server/TorchServer.cs | 30 ++++++++++++++++++++++++++ Torch/Commands/TorchCommands.cs | 9 +++++++- Torch/TorchBase.cs | 38 ++++++++++++++++++++++++--------- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/Torch.API/ITorchBase.cs b/Torch.API/ITorchBase.cs index e83aa63..e550fe4 100644 --- a/Torch.API/ITorchBase.cs +++ b/Torch.API/ITorchBase.cs @@ -25,6 +25,7 @@ namespace Torch.API bool IsOnGameThread(); void Start(); void Stop(); + void Save(long callerId); void Init(); T GetManager() where T : class, IManager; } diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs index a41eed5..3e9934d 100644 --- a/Torch.Server/TorchServer.cs +++ b/Torch.Server/TorchServer.cs @@ -221,5 +221,35 @@ namespace Torch.Server _stopHandle.Set(); State = ServerState.Stopped; } + + public override void Save(long callerId) + { + base.SaveGameAsync((statusCode) => SaveCompleted(statusCode, callerId)); + } + + private void SaveCompleted(SaveGameStatus statusCode, long callerId) + { + switch (statusCode) + { + case SaveGameStatus.Success: + Log.Info("Save completed."); + Multiplayer.SendMessage("Saved game.", playerId: callerId); + break; + case SaveGameStatus.SaveInProgress: + Log.Error("Save failed, a save is already in progress."); + Multiplayer.SendMessage("Save failed, a save is already in progress.", playerId: callerId, font: MyFontEnum.Red); + break; + case SaveGameStatus.GameNotReady: + Log.Error("Save failed, game was not ready."); + Multiplayer.SendMessage("Save failed, game was not ready.", playerId: callerId, font: MyFontEnum.Red); + break; + case SaveGameStatus.TimedOut: + Log.Error("Save failed, save timed out."); + Multiplayer.SendMessage("Save failed, save timed out.", playerId: callerId, font: MyFontEnum.Red); + break; + default: + break; + } + } } } diff --git a/Torch/Commands/TorchCommands.cs b/Torch/Commands/TorchCommands.cs index 08cae6b..378d173 100644 --- a/Torch/Commands/TorchCommands.cs +++ b/Torch/Commands/TorchCommands.cs @@ -67,5 +67,12 @@ namespace Torch.Commands Context.Respond("Stopping server."); Context.Torch.Stop(); } + + [Command("save", "Saves the game.")] + public void Save() + { + Context.Respond("Saving game."); + Context.Torch.Save(Context.Player?.IdentityId ?? 0); + } } -} +} \ No newline at end of file diff --git a/Torch/TorchBase.cs b/Torch/TorchBase.cs index 7f3f471..e167cf0 100644 --- a/Torch/TorchBase.cs +++ b/Torch/TorchBase.cs @@ -31,6 +31,14 @@ using VRage.Utils; namespace Torch { + public enum SaveGameStatus : byte + { + Success = 0, + SaveInProgress = 1, + GameNotReady = 2, + TimedOut = 3 + }; + /// /// Base class for code shared between the Torch client and server. /// @@ -109,10 +117,19 @@ namespace Torch return Thread.CurrentThread.ManagedThreadId == MySandboxGame.Static.UpdateThread.ManagedThreadId; } - public async Task SaveGameAsync() + public async Task SaveGameAsync(Action callback) { Log.Info("Saving game"); - if (MySandboxGame.IsGameReady && !MyAsyncSaving.InProgress && Sync.IsServer && !(MySession.Static.LocalCharacter?.IsDead ?? true)) + + if (!MySandboxGame.IsGameReady) + { + callback(SaveGameStatus.GameNotReady); + } + else if(MyAsyncSaving.InProgress) + { + callback(SaveGameStatus.SaveInProgress); + } + else { using (var e = new AutoResetEvent(false)) { @@ -125,17 +142,13 @@ namespace Torch await Task.Run(() => { if (e.WaitOne(60000)) - return; - - Log.Error("Save failed!"); - Multiplayer.SendMessage("Save timed out!", "Error"); + callback(SaveGameStatus.Success); + return; + + callback(SaveGameStatus.TimedOut); }).ConfigureAwait(false); } } - else - { - Log.Error("Cannot save"); - } } #region Game Actions @@ -279,6 +292,11 @@ namespace Torch pluginList.Add(this); } + public virtual void Save(long callerId) + { + + } + public virtual void Start() { From 8ab16c3d30bb14ed6fd3997dcf950fe0a7e6558b Mon Sep 17 00:00:00 2001 From: Alexander Qvist-Hellum Date: Fri, 7 Jul 2017 00:34:45 +0200 Subject: [PATCH 2/2] Moved SaveGameStatus to seperate file, guarded against null callbacks and added documentation --- Torch.API/ITorchBase.cs | 4 ++++ Torch.Server/TorchServer.cs | 6 ++++++ Torch/Commands/TorchCommands.cs | 6 +++++- Torch/SaveGameStatus.cs | 13 +++++++++++++ Torch/Torch.csproj | 1 + Torch/TorchBase.cs | 21 ++++++++------------- 6 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 Torch/SaveGameStatus.cs diff --git a/Torch.API/ITorchBase.cs b/Torch.API/ITorchBase.cs index e550fe4..97ef817 100644 --- a/Torch.API/ITorchBase.cs +++ b/Torch.API/ITorchBase.cs @@ -25,6 +25,10 @@ namespace Torch.API bool IsOnGameThread(); void Start(); void Stop(); + /// + /// Initializes a save of the game. + /// + /// Id of the player who initiated the save. void Save(long callerId); void Init(); T GetManager() where T : class, IManager; diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs index 3e9934d..4d02fab 100644 --- a/Torch.Server/TorchServer.cs +++ b/Torch.Server/TorchServer.cs @@ -222,11 +222,17 @@ namespace Torch.Server State = ServerState.Stopped; } + /// public override void Save(long callerId) { base.SaveGameAsync((statusCode) => SaveCompleted(statusCode, callerId)); } + /// + /// Callback for when save has finished. + /// + /// Return code of the save operation + /// Caller of the save operation private void SaveCompleted(SaveGameStatus statusCode, long callerId) { switch (statusCode) diff --git a/Torch/Commands/TorchCommands.cs b/Torch/Commands/TorchCommands.cs index 378d173..5643ce2 100644 --- a/Torch/Commands/TorchCommands.cs +++ b/Torch/Commands/TorchCommands.cs @@ -67,7 +67,11 @@ namespace Torch.Commands Context.Respond("Stopping server."); Context.Torch.Stop(); } - + + /// + /// Initializes a save of the game. + /// Caller id defaults to 0 in the case of triggering the chat command from server. + /// [Command("save", "Saves the game.")] public void Save() { diff --git a/Torch/SaveGameStatus.cs b/Torch/SaveGameStatus.cs new file mode 100644 index 0000000..0309212 --- /dev/null +++ b/Torch/SaveGameStatus.cs @@ -0,0 +1,13 @@ +namespace Torch +{ + /// + /// Describes the possible outcomes when attempting to save the game progress. + /// + public enum SaveGameStatus : byte + { + Success = 0, + SaveInProgress = 1, + GameNotReady = 2, + TimedOut = 3 + }; +} diff --git a/Torch/Torch.csproj b/Torch/Torch.csproj index 8803230..eb4c331 100644 --- a/Torch/Torch.csproj +++ b/Torch/Torch.csproj @@ -144,6 +144,7 @@ + diff --git a/Torch/TorchBase.cs b/Torch/TorchBase.cs index e167cf0..860f5d3 100644 --- a/Torch/TorchBase.cs +++ b/Torch/TorchBase.cs @@ -31,14 +31,6 @@ using VRage.Utils; namespace Torch { - public enum SaveGameStatus : byte - { - Success = 0, - SaveInProgress = 1, - GameNotReady = 2, - TimedOut = 3 - }; - /// /// Base class for code shared between the Torch client and server. /// @@ -123,11 +115,11 @@ namespace Torch if (!MySandboxGame.IsGameReady) { - callback(SaveGameStatus.GameNotReady); + callback?.Invoke(SaveGameStatus.GameNotReady); } else if(MyAsyncSaving.InProgress) { - callback(SaveGameStatus.SaveInProgress); + callback?.Invoke(SaveGameStatus.SaveInProgress); } else { @@ -142,10 +134,12 @@ namespace Torch await Task.Run(() => { if (e.WaitOne(60000)) - callback(SaveGameStatus.Success); - return; + { + callback?.Invoke(SaveGameStatus.Success); + return; + } - callback(SaveGameStatus.TimedOut); + callback?.Invoke(SaveGameStatus.TimedOut); }).ConfigureAwait(false); } } @@ -292,6 +286,7 @@ namespace Torch pluginList.Add(this); } + /// public virtual void Save(long callerId) {