diff --git a/src/ARKServerManager/ARKServerManager.csproj b/src/ARKServerManager/ARKServerManager.csproj index 22b8ccaa..b505318f 100644 --- a/src/ARKServerManager/ARKServerManager.csproj +++ b/src/ARKServerManager/ARKServerManager.csproj @@ -366,6 +366,7 @@ + Always diff --git a/src/ARKServerManager/Art/Restart.ico b/src/ARKServerManager/Art/Restart.ico new file mode 100644 index 00000000..3e07dd1e Binary files /dev/null and b/src/ARKServerManager/Art/Restart.ico differ diff --git a/src/ARKServerManager/Globalization/en-US/en-US.xaml b/src/ARKServerManager/Globalization/en-US/en-US.xaml index dc7d809c..c2a65f54 100644 --- a/src/ARKServerManager/Globalization/en-US/en-US.xaml +++ b/src/ARKServerManager/Globalization/en-US/en-US.xaml @@ -440,6 +440,7 @@ Server Monitor + Selected Total Servers: Server Map @@ -449,6 +450,13 @@ Status Create a desktop shortcut to open this form directly. + Start the selected servers. + Stop the selected servers. + Restart the selected servers. + Update the selected servers. + Backup the selected servers. + Select all servers. + Unselect all servers. Open the Player List window. Open the RCON window. Start the server. @@ -459,7 +467,21 @@ Server Update Error Another server is being upgraded, wait until the upgrade has finished and try again. Confirm Window Close - You are currently perform a server update, closing the window with disconnect you from steamcmd. Do you want to continue closing the window? + You are currently performing a server update, closing the window will disconnect you from steamcmd. Do you want to continue closing the window? + Confirm Start Servers + You are about to start the selected servers. Do you want to continue? + Confirm Stop Servers + You are about to stop the selected servers. Do you want to continue? + Confirm Restart Servers + You are about to restart the selected servers. Do you want to continue? + Confirm Update Servers + You are about to update the selected servers. Do you want to continue? + Confirm Backup Servers + You are about to backup the selected servers. Do you want to continue? + Selected Servers Error + You have not selected any servers. Selected one or more servers in the list and try again. + Close Server Monitor Error + The server monitor window cannot be closed at this time. One or more of the servers is currently starting, shutting down or restarting. diff --git a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml index d2791ff9..95ff243c 100644 --- a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml +++ b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml @@ -4,6 +4,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:tb="http://www.hardcodet.net/taskbar" + xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" + xmlns:sm="clr-namespace:ServerManagerTool" + xmlns:smw="clr-namespace:ServerManagerTool.Windows" xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common" xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common" xmlns:enum="clr-namespace:ServerManagerTool.Enums" @@ -18,21 +21,31 @@ - + + - + - + + + - + + + + + + + + @@ -41,12 +54,95 @@ - + + + + + + + + + + + + + + + - - + + + + - + @@ -544,7 +664,7 @@ - + @@ -557,7 +677,7 @@ Visibility="{Binding IsStandAloneWindow, Converter={StaticResource BooleanToVisibilityConverter}}" ToolTipText="{Binding Title}" IconSource="../Art/favicon.ico" - LeftClickCommand="{Binding ShowWindowCommand, ElementName=ServerMonitorUI}"> + LeftClickCommand="{Binding ShowWindowCommand, ElementName=ServerMonitorUI}" Grid.ColumnSpan="2"> diff --git a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs index f23ac64e..34dd543b 100644 --- a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs +++ b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs @@ -2,6 +2,7 @@ using NLog; using ServerManagerTool.Common.Lib; using ServerManagerTool.Common.Utils; +using ServerManagerTool.DiscordBot.Enums; using ServerManagerTool.Enums; using ServerManagerTool.Lib; using ServerManagerTool.Plugin.Common; @@ -16,7 +17,9 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using System.Windows.Documents; using System.Windows.Input; +using System.Windows.Media; using WPFSharp.Globalizer; namespace ServerManagerTool.Windows @@ -26,17 +29,39 @@ namespace ServerManagerTool.Windows /// public partial class ServerMonitorWindow : Window { + public class ServerMonitorOutput_Error : Run + { + public ServerMonitorOutput_Error(string value) + : base(value) + { + Foreground = Brushes.Red; + } + } + + public class ServerMonitorOutput_Success : Run + { + public ServerMonitorOutput_Success(string value) + : base(value) + { + Foreground = Brushes.Green; + } + } + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly List Windows = new List(); private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance; private CancellationTokenSource _upgradeCancellationSource = null; private ActionQueue _versionChecker; + private readonly Dictionary _currentProfileCommands = new Dictionary(); + + private bool HasRunningCommands => _currentProfileCommands.Count > 0; public static readonly DependencyProperty ServerManagerProperty = DependencyProperty.Register(nameof(ServerManager), typeof(ServerManager), typeof(ServerMonitorWindow), new PropertyMetadata(null)); public static readonly DependencyProperty LatestServerManagerVersionProperty = DependencyProperty.Register(nameof(LatestServerManagerVersion), typeof(Version), typeof(ServerMonitorWindow), new PropertyMetadata(new Version())); public static readonly DependencyProperty ShowUpdateButtonProperty = DependencyProperty.Register(nameof(ShowUpdateButton), typeof(bool), typeof(ServerMonitorWindow), new PropertyMetadata(false)); public static readonly DependencyProperty IsStandAloneWindowProperty = DependencyProperty.Register(nameof(IsStandAloneWindow), typeof(bool), typeof(ServerMonitorWindow), new PropertyMetadata(false)); + public static readonly DependencyProperty CancellationTokenSourceProperty = DependencyProperty.Register(nameof(CancellationTokenSource), typeof(CancellationTokenSource), typeof(ServerMonitorWindow)); public ServerMonitorWindow() : this(null) { @@ -89,6 +114,12 @@ namespace ServerManagerTool.Windows set { SetValue(IsStandAloneWindowProperty, value); } } + public CancellationTokenSource CancellationTokenSource + { + get { return (CancellationTokenSource)GetValue(CancellationTokenSourceProperty); } + set { SetValue(CancellationTokenSourceProperty, value); } + } + private void ServerMonitorWindow_Loaded(object sender, RoutedEventArgs e) { if (ServerManager == null) @@ -156,6 +187,14 @@ namespace ServerManagerTool.Windows protected override void OnClosing(CancelEventArgs e) { + if (HasRunningCommands) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_RunningProcesses_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_RunningProcesses_ConfirmTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + + e.Cancel = true; + return; + } + if (this.OwnedWindows.OfType().Any()) { if (MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_CloseWindow_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_CloseWindow_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Warning) != MessageBoxResult.Yes) @@ -409,6 +448,29 @@ namespace ServerManagerTool.Windows } } + public void AddErrorBlockContent(string message) + { + var p = new Paragraph(); + + p.Inlines.Add(new ServerMonitorOutput_Error(message)); + + ConsoleContent.Blocks.Add(p); + } + + public void AddMessageBlockContent(string message) + { + var p = new Paragraph(); + + p.Inlines.Add(new ServerMonitorOutput_Success(message)); + + ConsoleContent.Blocks.Add(p); + } + + public void ClearBlockContents() + { + ConsoleContent.Blocks.Clear(); + } + private async Task CheckForUpdates() { string url = App.Instance.BetaVersion ? Config.Default.LatestASMBetaVersionUrl : Config.Default.LatestASMVersionUrl; @@ -816,5 +878,511 @@ namespace ServerManagerTool.Windows } #endregion + + private async void BackupServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_BackupServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_BackupServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Uninstalled: + case ServerStatus.Unknown: + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Backup); + profileList.Add(ServerProfileSnapshot.Create(server.Profile)); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Backup, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileBackup(profile, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_BackupRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private async void RestartServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_RestartServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_RestartServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Uninstalled: + case ServerStatus.Unknown: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Restart); + var profile = ServerProfileSnapshot.Create(server.Profile); + profile.AutoRestartIfShutdown = true; + profileList.Add(profile); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Restart, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileShutdown(profile, true, false, false, false, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_RestartRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private async void StartServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_StartServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_StartServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Running: + case ServerStatus.Uninstalled: + case ServerStatus.Unknown: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Start); + var profile = ServerProfileSnapshot.Create(server.Profile); + profile.AutoRestartIfShutdown = true; + profileList.Add(profile); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Restart, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileShutdown(profile, true, false, false, false, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_StartRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private async void StopServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_StopServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_StopServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Stopped: + case ServerStatus.Uninstalled: + case ServerStatus.Unknown: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Stop); + profileList.Add(ServerProfileSnapshot.Create(server.Profile)); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Shutdown, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileShutdown(profile, false, false, false, false, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ShutdownRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private async void UpdateServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_UpdateServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_UpdateServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + var performRestart = false; + + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Running: + performRestart = true; + break; + + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Unknown: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Update); + var profile = ServerProfileSnapshot.Create(server.Profile); + profile.RestartAfterShutdown1 = performRestart; // use this property to trigger a restart + profileList.Add(profile); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Update, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileShutdown(profile, profile.RestartAfterShutdown1, true, false, false, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_UpdateRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private void SelectAllServers_Click(object sender, RoutedEventArgs e) + { + foreach (var server in ServerManager.Servers) + { + server.Selected = true; + } + } + + private void UnselectAllServers_Click(object sender, RoutedEventArgs e) + { + foreach (var server in ServerManager.Servers) + { + server.Selected = false; + } + } } } diff --git a/src/ConanServerManager/Art/Restart.ico b/src/ConanServerManager/Art/Restart.ico new file mode 100644 index 00000000..3e07dd1e Binary files /dev/null and b/src/ConanServerManager/Art/Restart.ico differ diff --git a/src/ConanServerManager/ConanServerManager.csproj b/src/ConanServerManager/ConanServerManager.csproj index 467f0588..e1053835 100644 --- a/src/ConanServerManager/ConanServerManager.csproj +++ b/src/ConanServerManager/ConanServerManager.csproj @@ -297,6 +297,7 @@ + Designer PreserveNewest diff --git a/src/ConanServerManager/Globalization/en-US/en-US.xaml b/src/ConanServerManager/Globalization/en-US/en-US.xaml index 36c7d163..a55a7174 100644 --- a/src/ConanServerManager/Globalization/en-US/en-US.xaml +++ b/src/ConanServerManager/Globalization/en-US/en-US.xaml @@ -400,6 +400,7 @@ Server Monitor + Selected Total Servers: Server Map @@ -409,6 +410,13 @@ Status Create a desktop shortcut to open this form directly. + Start the selected servers. + Stop the selected servers. + Restart the selected servers. + Update the selected servers. + Backup the selected servers. + Select all servers. + Unselect all servers. Open the Player List window. Open the RCON window. Start the server. @@ -419,7 +427,21 @@ Server Update Error Another server is being upgraded, wait until the upgrade has finished and try again. Confirm Window Close - You are currently perform a server update, closing the window with disconnect you from steamcmd. Do you want to continue closing the window? + You are currently performing a server update, closing the window will disconnect you from steamcmd. Do you want to continue closing the window? + Confirm Start Servers + You are about to start the selected servers. Do you want to continue? + Confirm Stop Servers + You are about to stop the selected servers. Do you want to continue? + Confirm Restart Servers + You are about to restart the selected servers. Do you want to continue? + Confirm Update Servers + You are about to update the selected servers. Do you want to continue? + Confirm Backup Servers + You are about to backup the selected servers. Do you want to continue? + Selected Servers Error + You have not selected any servers. Selected one or more servers in the list and try again. + Close Server Monitor Error + The server monitor window cannot be closed at this time. One or more of the servers is currently starting, shutting down or restarting. diff --git a/src/ConanServerManager/Windows/ServerMonitorWindow.xaml b/src/ConanServerManager/Windows/ServerMonitorWindow.xaml index 8d28adf1..9c8b12f6 100644 --- a/src/ConanServerManager/Windows/ServerMonitorWindow.xaml +++ b/src/ConanServerManager/Windows/ServerMonitorWindow.xaml @@ -4,6 +4,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:tb="http://www.hardcodet.net/taskbar" + xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" + xmlns:sm="clr-namespace:ServerManagerTool" + xmlns:smw="clr-namespace:ServerManagerTool.Windows" xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common" xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common" xmlns:enum="clr-namespace:ServerManagerTool.Enums" @@ -19,6 +22,7 @@ + @@ -28,11 +32,20 @@ - + + + - + + + + + + + + @@ -41,12 +54,95 @@ - + + + + + + + + + + + + + + + -