mirror of
https://github.com/tribufu/ServerManagers
synced 2026-05-06 07:07:32 +00:00
commit
af7f3e8c64
67 changed files with 3908 additions and 358 deletions
|
|
@ -173,6 +173,7 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Delegates\ServerStatusChangeDelegate.cs" />
|
||||
<Compile Include="Enums\LevelProgression.cs" />
|
||||
<Compile Include="Enums\LogEventType.cs" />
|
||||
<Compile Include="Enums\NPCSpawnContainerType.cs" />
|
||||
|
|
@ -196,13 +197,15 @@
|
|||
<Compile Include="Lib\Serialization\IniSections.cs" />
|
||||
<Compile Include="Lib\Serialization\SystemIniFile.cs" />
|
||||
<Compile Include="Lib\Model\PlayerListParameters.cs" />
|
||||
<Compile Include="Lib\ServerBranchSnapshot.cs" />
|
||||
<Compile Include="Lib\BranchSnapshot.cs" />
|
||||
<Compile Include="Lib\ServerPlayers.cs" />
|
||||
<Compile Include="Lib\ServerProfileSnapshot.cs" />
|
||||
<Compile Include="Lib\ViewConverters\EnumDescriptionTypeConverter.cs" />
|
||||
<Compile Include="Lib\ViewConverters\MapNameValueConverter.cs" />
|
||||
<Compile Include="Lib\ViewModel\Engram.cs" />
|
||||
<Compile Include="Lib\ViewModel\EngramSettings.cs" />
|
||||
<Compile Include="Utils\DiscordBotHelper.cs" />
|
||||
<Compile Include="Utils\DiscordPluginHelper.cs" />
|
||||
<Compile Include="Utils\ModUtils.cs" />
|
||||
<Compile Include="Windows\AddUserWindow.xaml.cs">
|
||||
<DependentUpon>AddUserWindow.xaml</DependentUpon>
|
||||
|
|
|
|||
|
|
@ -347,6 +347,12 @@
|
|||
<setting name="DefaultDataDirectoryName" serializeAs="String">
|
||||
<value>asmdata</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotApplyUrl" serializeAs="String">
|
||||
<value>https://discord.com/developers/applications</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotHelpUrl" serializeAs="String">
|
||||
<value>https://arkservermanager.freeforums.net/thread/8764/get-own-discord-bot</value>
|
||||
</setting>
|
||||
</ServerManagerTool.Config>
|
||||
<ServerManagerTool.Common.CommonConfig>
|
||||
<setting name="DefaultSteamAPIKey" serializeAs="String">
|
||||
|
|
@ -804,6 +810,39 @@
|
|||
<setting name="MainWindow_Top" serializeAs="String">
|
||||
<value>50</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotEnabled" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotPrefix" serializeAs="String">
|
||||
<value>asm</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotToken" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="DiscordBotServerId" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="SectionDiscordBotIsExpanded" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordBackup" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordUpdate" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordStart" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordRestart" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordShutdown" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordStop" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
</ServerManagerTool.Config>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
using ArkData;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using NLog;
|
||||
using NLog.Config;
|
||||
using NLog.Targets;
|
||||
using ServerManagerTool.Common;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.DiscordBot;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using ServerManagerTool.Utils;
|
||||
using ServerManagerTool.Windows;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
|
@ -21,7 +21,6 @@ using System.Runtime.CompilerServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Xml;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
|
|
@ -39,6 +38,7 @@ namespace ServerManagerTool
|
|||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private CancellationTokenSource _tokenSource;
|
||||
private GlobalizedApplication _globalizer;
|
||||
private bool _applicationStarted;
|
||||
private string _args;
|
||||
|
|
@ -177,11 +177,6 @@ namespace ServerManagerTool
|
|||
}
|
||||
}
|
||||
|
||||
private IList<Plugin.Common.Lib.Profile> FetchProfiles()
|
||||
{
|
||||
return ServerManager.Instance.Servers.Select(s => new ServerManagerTool.Plugin.Common.Lib.Profile() { ProfileName = s?.Profile?.ProfileName ?? string.Empty, InstallationFolder = s?.Profile?.InstallDirectory ?? string.Empty }).ToList();
|
||||
}
|
||||
|
||||
public static string GetLogFolder() => IOUtils.NormalizePath(Path.Combine(Config.Default.DataDir, Config.Default.LogsDir));
|
||||
|
||||
public static string GetProfileLogFolder(string profileId) => IOUtils.NormalizePath(Path.Combine(Config.Default.DataDir, Config.Default.LogsDir, profileId.ToLower()));
|
||||
|
|
@ -312,7 +307,7 @@ namespace ServerManagerTool
|
|||
var installPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
PluginHelper.Instance.BetaEnabled = this.BetaVersion;
|
||||
PluginHelper.Instance.LoadPlugins(installPath, true);
|
||||
PluginHelper.Instance.SetFetchProfileCallback(FetchProfiles);
|
||||
PluginHelper.Instance.SetFetchProfileCallback(DiscordPluginHelper.FetchProfiles);
|
||||
OnResourceDictionaryChanged(Thread.CurrentThread.CurrentCulture.Name);
|
||||
|
||||
// check if we are starting ASM for the old server restart - no longer supported
|
||||
|
|
@ -412,6 +407,7 @@ namespace ServerManagerTool
|
|||
|
||||
ApplicationStarted = true;
|
||||
|
||||
var restartRequired = false;
|
||||
if (string.IsNullOrWhiteSpace(Config.Default.DataDir))
|
||||
{
|
||||
var dataDirectoryWindow = new DataDirectoryWindow();
|
||||
|
|
@ -422,6 +418,8 @@ namespace ServerManagerTool
|
|||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
restartRequired = true;
|
||||
}
|
||||
|
||||
Config.Default.ConfigDirectory = Path.Combine(Config.Default.DataDir, Config.Default.ProfilesDir);
|
||||
|
|
@ -429,6 +427,11 @@ namespace ServerManagerTool
|
|||
Config.Default.Save();
|
||||
CommonConfig.Default.Save();
|
||||
|
||||
if (restartRequired)
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
DataFileDetails.PlayerFileExtension = Config.Default.PlayerFileExtension;
|
||||
DataFileDetails.TribeFileExtension = Config.Default.TribeFileExtension;
|
||||
|
||||
|
|
@ -446,6 +449,25 @@ namespace ServerManagerTool
|
|||
|
||||
StartupUri = new Uri("Windows/AutoUpdateWindow.xaml", UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
|
||||
if (Config.Default.DiscordBotEnabled)
|
||||
{
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
|
||||
Task discordTask = Task.Run(async () =>
|
||||
{
|
||||
await ServerManagerBotFactory.GetServerManagerBot()?.StartAsync(Config.Default.DiscordBotToken, Config.Default.DiscordBotPrefix, Config.Default.DataDir, DiscordBotHelper.HandleDiscordCommand, DiscordBotHelper.HandleTranslation, _tokenSource.Token);
|
||||
}, _tokenSource.Token)
|
||||
.ContinueWith(t => {
|
||||
var message = t.Exception.InnerException is null ? t.Exception.Message : t.Exception.InnerException.Message;
|
||||
if (message.StartsWith("#"))
|
||||
{
|
||||
message = _globalizer.GetResourceString(message.Substring(1)) ?? message.Substring(1);
|
||||
}
|
||||
|
||||
MessageBox.Show(message, _globalizer.GetResourceString("DiscordBot_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
|
|
@ -486,6 +508,12 @@ namespace ServerManagerTool
|
|||
|
||||
private void ShutDownApplication()
|
||||
{
|
||||
if (!(_tokenSource is null))
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
_tokenSource.Dispose();
|
||||
}
|
||||
|
||||
if (ApplicationStarted)
|
||||
{
|
||||
foreach (var server in ServerManager.Instance.Servers)
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
150
src/ARKServerManager/Config.Designer.cs
generated
150
src/ARKServerManager/Config.Designer.cs
generated
|
|
@ -2812,5 +2812,155 @@ namespace ServerManagerTool {
|
|||
return ((string)(this["DefaultDataDirectoryName"]));
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool DiscordBotEnabled {
|
||||
get {
|
||||
return ((bool)(this["DiscordBotEnabled"]));
|
||||
}
|
||||
set {
|
||||
this["DiscordBotEnabled"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("asm")]
|
||||
public string DiscordBotPrefix {
|
||||
get {
|
||||
return ((string)(this["DiscordBotPrefix"]));
|
||||
}
|
||||
set {
|
||||
this["DiscordBotPrefix"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string DiscordBotToken {
|
||||
get {
|
||||
return ((string)(this["DiscordBotToken"]));
|
||||
}
|
||||
set {
|
||||
this["DiscordBotToken"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string DiscordBotServerId {
|
||||
get {
|
||||
return ((string)(this["DiscordBotServerId"]));
|
||||
}
|
||||
set {
|
||||
this["DiscordBotServerId"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("https://discord.com/developers/applications")]
|
||||
public string DiscordBotApplyUrl {
|
||||
get {
|
||||
return ((string)(this["DiscordBotApplyUrl"]));
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("https://arkservermanager.freeforums.net/thread/8764/get-own-discord-bot")]
|
||||
public string DiscordBotHelpUrl {
|
||||
get {
|
||||
return ((string)(this["DiscordBotHelpUrl"]));
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool SectionDiscordBotIsExpanded {
|
||||
get {
|
||||
return ((bool)(this["SectionDiscordBotIsExpanded"]));
|
||||
}
|
||||
set {
|
||||
this["SectionDiscordBotIsExpanded"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordBackup {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordBackup"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordBackup"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordUpdate {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordUpdate"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordUpdate"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordStart {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordStart"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordStart"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordRestart {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordRestart"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordRestart"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordShutdown {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordShutdown"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordShutdown"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordStop {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordStop"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordStop"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -779,5 +779,44 @@
|
|||
<Setting Name="DefaultDataDirectoryName" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">asmdata</Value>
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotEnabled" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotPrefix" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">asm</Value>
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotToken" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotServerId" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotApplyUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://discord.com/developers/applications</Value>
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotHelpUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://arkservermanager.freeforums.net/thread/8764/get-own-discord-bot</Value>
|
||||
</Setting>
|
||||
<Setting Name="SectionDiscordBotIsExpanded" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordBackup" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordUpdate" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordStart" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordRestart" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordShutdown" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordStop" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
using ServerManagerTool.Enums;
|
||||
|
||||
namespace ServerManagerTool.Delegates
|
||||
{
|
||||
public delegate void ServerStatusChangeDelegate(ServerStatus serverStatus);
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@
|
|||
public enum AvailabilityStatus
|
||||
{
|
||||
Unknown,
|
||||
NeedPublicIP,
|
||||
SetPublicIP,
|
||||
Unavailable,
|
||||
WaitingForPublication,
|
||||
Waiting,
|
||||
Available
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@
|
|||
Backup,
|
||||
Shutdown,
|
||||
Restart,
|
||||
Update,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -610,7 +610,24 @@
|
|||
<sys:String x:Key="GlobalSettings_ShutdownCancelTooltip">This message will be displayed when the server shutdown has been cancelled.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_ShutdownAllMessagesShowReasonLabel">Show shutdown reason with ALL shutdown messages</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_ShutdownAllMessagesShowReasonTooltip">If enabled, the shutdown reason will be shown with all shutdown message; otherwise it will only be shown at the start of the server shutdown.</sys:String>
|
||||
|
||||
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotLabel">Enable Discord Bot</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotInformationLabel">You will need to restart the server manager if you change any settings for the Discord Bot.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotTokenLabel">Token:</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotTokenTooltip">The token associated with the discord bot.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotServerLabel">Server Id:</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotServerTooltip">The id of the discord server the bot will listen to.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotPrefixLabel">Prefix:</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotPrefixTooltip">The prefix that must be used when sending a command via discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotApplyButtonLabel">Get Token...</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotHelpButtonLabel">Help...</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowBackupTooltip">If enabled, the backup command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowRestartTooltip">If enabled, the restart command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowShutdownTooltip">If enabled, the shutdown command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowStartTooltip">If enabled, the start command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowStopTooltip">If enabled, the stop command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowUpdateTooltip">If enabled, the update command can be sent from discord.</sys:String>
|
||||
|
||||
<sys:String x:Key="GlobalSettings_EmailSettingsLabel">SMTP Email Settings</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_EmailHostLabel">Host:</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_EmailHostTooltip">The name or IP address of the host used for SMTP transmissions.</sys:String>
|
||||
|
|
@ -775,6 +792,9 @@
|
|||
<sys:String x:Key="MainWindow_SteamCmd_FailedTitle">Reinstall SteamCMD Error</sys:String>
|
||||
<sys:String x:Key="MainWindow_SteamCmd_FailedLabel">An error occured while trying to reinstall SteamCMD. This has left SteamCmd in an unstable state, try reinstalling again or please report this.\r\nException: {0}</sys:String>
|
||||
|
||||
<sys:String x:Key="MainWindow_DiscordBot_RunningCommandsTitle">Discord Bot Running Commands</sys:String>
|
||||
<sys:String x:Key="MainWindow_DiscordBot_RunningCommandsLabel">The discord bot has one or more running commands, do you want to continue shutting down the server manager?</sys:String>
|
||||
|
||||
<sys:String x:Key="MainWindow_ServerStatus_StartServerActionTitle">Start Server Confirmation</sys:String>
|
||||
<sys:String x:Key="MainWindow_ServerStatus_StartServerActionLabel">You are about to start the server, do you want to continue?</sys:String>
|
||||
<sys:String x:Key="MainWindow_ServerStatus_ShutdownServerActionTitle">Shutdown Server Confirmation</sys:String>
|
||||
|
|
@ -1179,6 +1199,24 @@
|
|||
<sys:String x:Key="ServerSettings_RestartIfShutdownTooltip">If enabled, the server will be restarted even if shutdown for Auto-Restarts and Auto-Updates.</sys:String>
|
||||
<!--#endregion-->
|
||||
|
||||
<!--#region Server Settings - Discord Bot Details -->
|
||||
<sys:String x:Key="ServerSettings_DiscordBotLabel">Discord Bot Details</sys:String>
|
||||
<sys:String x:Key="ServerSettings_DiscordBotChannelLabel">Channel Id:</sys:String>
|
||||
<sys:String x:Key="ServerSettings_DiscordBotChannelTooltip">The id of the discord server channel this profile will listen to.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordBackupLabel">Allow Backup</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordBackupTooltip">If enabled, the profile will listen for backup commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordRestartLabel">Allow Restart</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordRestartTooltip">If enabled, the profile will listen for restart commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordShutdownLabel">Allow Shutdown</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordShutdownTooltip">If enabled, the profile will listen for shutdown commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordStartLabel">Allow Start</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordStartTooltip">If enabled, the profile will listen for start commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordStopLabel">Allow Stop</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordStopTooltip">If enabled, the profile will listen for stop commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordUpdateLabel">Allow Update</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordUpdateTooltip">If enabled, the profile will listen for update commands from discord.</sys:String>
|
||||
<!--#endregion-->
|
||||
|
||||
<!--#region Server Settings - Rules -->
|
||||
<sys:String x:Key="ServerSettings_RulesLabel">Rules</sys:String>
|
||||
<sys:String x:Key="ServerSettings_EnableHardcoreLabel">Enable Hardcore Mode</sys:String>
|
||||
|
|
@ -5523,4 +5561,32 @@
|
|||
<sys:String x:Key="ServerUpdate_WarningLabel">There was a problem while performing the server update. This may leave your server in a incomplete state.\r\n\r\nDo you want to continue with the server start, this could cause problems?</sys:String>
|
||||
<!--#endregion-->
|
||||
|
||||
<!--#region Discord Bot -->
|
||||
<sys:String x:Key="DiscordBot_ErrorTitle">Discord Bot Error</sys:String>
|
||||
<sys:String x:Key="DiscordBot_MissingTokenError">The discord bot requires a valid token so it can log into the discord server\r\nThis can be set in the global settings.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_InvalidPrefixError">The discord bot prefix contains invalid characters. Only letters and numbers are allowed.</sys:String>
|
||||
|
||||
<sys:String x:Key="DiscordBot_CommandNotEnabled">Command '{0}' has not been enabled.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_CommandUnknown">Unknown command '{0}'.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_CommandRunning">Another command is currently being processed.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_CommandRunningProfile">Another command '{0}' is currently running against profile '{1}'.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_CommandDisabledProfile">Command '{0}' has been disabled for profile '{1}'.</sys:String>
|
||||
|
||||
<sys:String x:Key="DiscordBot_ProfileMissing">The '{0}' command requires a profile id.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_ProfileNotFound">Profile '{0}' was not found or is not associated with the channel.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_ProfileBadStatus">Profile '{0}' is in a state '{1}' that cannot run this command.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_ProfileUpdating">Profile '{0}' is currently being updated.</sys:String>
|
||||
|
||||
<sys:String x:Key="DiscordBot_InfoFailed">Call to server '{0}' failed.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_BackupRequested">A backup request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_RestartRequested">A restart request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_ShutdownRequested">A shutdown request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_StartRequested">A start request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_StopRequested">A stop request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_UpdateRequested">An update request for server '{0}' has been sent.</sys:String>
|
||||
|
||||
<sys:String x:Key="DiscordBot_CountLabel">Count:</sys:String>
|
||||
<sys:String x:Key="DiscordBot_MapLabel">Map:</sys:String>
|
||||
<!--#endregion-->
|
||||
|
||||
</Globalization:GlobalizationResourceDictionary>
|
||||
|
|
@ -3,15 +3,37 @@ using System.Collections.Generic;
|
|||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ServerBranchSnapshot
|
||||
public class BranchSnapshot
|
||||
{
|
||||
private BranchSnapshot()
|
||||
{
|
||||
}
|
||||
|
||||
public string BranchName = string.Empty;
|
||||
public string BranchPassword = string.Empty;
|
||||
|
||||
public static BranchSnapshot Create(ServerProfile profile)
|
||||
{
|
||||
return new BranchSnapshot
|
||||
{
|
||||
BranchName = profile.BranchName,
|
||||
BranchPassword = profile.BranchPassword
|
||||
};
|
||||
}
|
||||
|
||||
public static BranchSnapshot Create(ServerProfileSnapshot profile)
|
||||
{
|
||||
return new BranchSnapshot
|
||||
{
|
||||
BranchName = profile.BranchName,
|
||||
BranchPassword = profile.BranchPassword
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerBranchSnapshotComparer : IEqualityComparer<ServerBranchSnapshot>
|
||||
public class BranchSnapshotComparer : IEqualityComparer<BranchSnapshot>
|
||||
{
|
||||
public bool Equals(ServerBranchSnapshot x, ServerBranchSnapshot y)
|
||||
public bool Equals(BranchSnapshot x, BranchSnapshot y)
|
||||
{
|
||||
//Check whether the compared objects reference the same data.
|
||||
if (Object.ReferenceEquals(x, y)) return true;
|
||||
|
|
@ -24,7 +46,7 @@ namespace ServerManagerTool.Lib
|
|||
return x.BranchName == y.BranchName;
|
||||
}
|
||||
|
||||
public int GetHashCode(ServerBranchSnapshot snapshot)
|
||||
public int GetHashCode(BranchSnapshot snapshot)
|
||||
{
|
||||
//Check whether the object is null
|
||||
if (snapshot is null) return 0;
|
||||
|
|
@ -94,7 +94,7 @@ namespace ServerManagerTool.Lib
|
|||
await this.Runtime.StopAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, ServerBranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
|
||||
public async Task<bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, BranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
|
||||
{
|
||||
await this.Runtime.AttachToProfile(this.Profile);
|
||||
var success = await this.Runtime.UpgradeAsync(cancellationToken, updateServer, branch, validate, updateMods, progressCallback);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Delegates;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using ServerManagerTool.Utils;
|
||||
|
|
@ -105,6 +106,7 @@ namespace ServerManagerTool.Lib
|
|||
public int ShutdownInterval = Config.Default.ServerShutdown_GracePeriod;
|
||||
public ProgressDelegate ProgressCallback = null;
|
||||
public ProcessWindowStyle SteamCMDProcessWindowStyle = ProcessWindowStyle.Minimized;
|
||||
public ServerStatusChangeDelegate ServerStatusChangeCallback = null;
|
||||
|
||||
public ServerApp(bool resetStartTime = false)
|
||||
{
|
||||
|
|
@ -112,7 +114,7 @@ namespace ServerManagerTool.Lib
|
|||
_startTime = DateTime.Now;
|
||||
}
|
||||
|
||||
private void BackupServer()
|
||||
private void BackupServer(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_profile == null || _profile.SotFEnabled)
|
||||
{
|
||||
|
|
@ -140,65 +142,65 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
if (_serverRunning)
|
||||
{
|
||||
// check if RCON is enabled
|
||||
if (_profile.RCONEnabled)
|
||||
try
|
||||
{
|
||||
try
|
||||
emailMessage.AppendLine();
|
||||
|
||||
var sent = false;
|
||||
|
||||
// perform a world save
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerBackup_WorldSaveMessage))
|
||||
{
|
||||
try
|
||||
ProcessAlert(AlertType.Backup, Config.Default.ServerBackup_WorldSaveMessage);
|
||||
sent = SendMessageAsync(Config.Default.ServerBackup_WorldSaveMessage, cancellationToken).Result;
|
||||
if (sent)
|
||||
{
|
||||
emailMessage.AppendLine();
|
||||
|
||||
var sent = false;
|
||||
|
||||
// perform a world save
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerBackup_WorldSaveMessage))
|
||||
{
|
||||
ProcessAlert(AlertType.Backup, Config.Default.ServerBackup_WorldSaveMessage);
|
||||
sent = SendMessageAsync(Config.Default.ServerBackup_WorldSaveMessage, CancellationToken.None).Result;
|
||||
if (sent)
|
||||
{
|
||||
emailMessage.AppendLine("sent server save message.");
|
||||
}
|
||||
}
|
||||
|
||||
sent = SendCommandAsync(Config.Default.ServerSaveCommand, false).Result;
|
||||
if (sent)
|
||||
{
|
||||
emailMessage.AppendLine("sent server save command.");
|
||||
Task.Delay(Config.Default.ServerShutdown_WorldSaveDelay * 1000).Wait();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"RCON> {Config.Default.ServerSaveCommand} command.\r\n{ex.Message}");
|
||||
emailMessage.AppendLine("sent server save message.");
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
sent = SendCommandAsync(Config.Default.ServerSaveCommand, false).Result;
|
||||
if (sent)
|
||||
{
|
||||
CloseRconConsole();
|
||||
emailMessage.AppendLine("sent server save command.");
|
||||
Task.Delay(Config.Default.ServerShutdown_WorldSaveDelay * 1000).Wait();
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogProfileMessage("RCON not enabled.");
|
||||
Debug.WriteLine($"RCON> {Config.Default.ServerSaveCommand} command.\r\n{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
return;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
// make a backup of the current profile and config files.
|
||||
CreateProfileBackupArchiveFile(_profile);
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
return;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
// make a backup of the current world file.
|
||||
CreateServerBackupArchiveFile(emailMessage, _profile);
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
return;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Config.Default.EmailNotify_AutoBackup)
|
||||
{
|
||||
|
|
@ -264,7 +266,15 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
if (updateServer)
|
||||
{
|
||||
UpgradeLocal(true, cancellationToken, true);
|
||||
try
|
||||
{
|
||||
ServerStatusChangeCallback?.Invoke(ServerStatus.Updating);
|
||||
UpgradeLocal(true, true, cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ServerStatusChangeCallback?.Invoke(ServerStatus.Stopped);
|
||||
}
|
||||
}
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
|
|
@ -300,17 +310,20 @@ namespace ServerManagerTool.Lib
|
|||
return;
|
||||
}
|
||||
|
||||
// check if the server was previously running before the update.
|
||||
if (!_serverRunning && !_profile.AutoRestartIfShutdown)
|
||||
// check if the server was previously running.
|
||||
if (!_serverRunning)
|
||||
{
|
||||
LogProfileMessage("Server was not running, server will not be started.");
|
||||
if (_profile.AutoRestartIfShutdown)
|
||||
{
|
||||
LogProfileMessage("Server was not running, server will be started as the setting to restart if shutdown is TRUE.");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogProfileMessage("Server was not running, server will not be started.");
|
||||
|
||||
ExitCode = EXITCODE_NORMALEXIT;
|
||||
return;
|
||||
}
|
||||
if (!_serverRunning && _profile.AutoRestartIfShutdown)
|
||||
{
|
||||
LogProfileMessage("Server was not running, server will be started as the setting to restart if shutdown is TRUE.");
|
||||
ExitCode = EXITCODE_NORMALEXIT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the server process.
|
||||
|
|
@ -394,7 +407,7 @@ namespace ServerManagerTool.Lib
|
|||
try
|
||||
{
|
||||
// create a connection to the server
|
||||
var endPoint = new IPEndPoint(IPAddress.Parse(_profile.ServerIP), _profile.QueryPort);
|
||||
var endPoint = new IPEndPoint(_profile.ServerIPAddress, _profile.QueryPort);
|
||||
gameServer = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endPoint);
|
||||
|
||||
// check if there is a shutdown reason
|
||||
|
|
@ -407,10 +420,6 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
|
||||
LogProfileMessage("Starting shutdown timer...");
|
||||
if (!CheckForOnlinePlayers)
|
||||
{
|
||||
LogProfileMessage("CheckForOnlinePlayers disabled, shutdown timer will not perform online player check.");
|
||||
}
|
||||
|
||||
var minutesLeft = ShutdownInterval;
|
||||
while (minutesLeft > 0)
|
||||
|
|
@ -422,7 +431,7 @@ namespace ServerManagerTool.Lib
|
|||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerShutdown_CancelMessage))
|
||||
{
|
||||
ProcessAlert(AlertType.Shutdown, Config.Default.ServerShutdown_CancelMessage);
|
||||
SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, CancellationToken.None).Wait();
|
||||
SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, cancellationToken).Wait();
|
||||
}
|
||||
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
|
|
@ -452,7 +461,8 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine($"CheckForOnlinePlayers disabled");
|
||||
Debug.WriteLine($"CheckForOnlinePlayers disabled, shutdown timer cancelled.");
|
||||
break;
|
||||
}
|
||||
|
||||
var message = string.Empty;
|
||||
|
|
@ -526,7 +536,7 @@ namespace ServerManagerTool.Lib
|
|||
{
|
||||
LogProfileMessage(Config.Default.ServerShutdown_WorldSaveMessage);
|
||||
ProcessAlert(AlertType.ShutdownMessage, Config.Default.ServerShutdown_WorldSaveMessage);
|
||||
SendMessageAsync(Config.Default.ServerShutdown_WorldSaveMessage, cancellationToken).Wait();
|
||||
SendMessageAsync(Config.Default.ServerShutdown_WorldSaveMessage, cancellationToken).Wait(cancellationToken);
|
||||
}
|
||||
|
||||
if (SendCommandAsync(Config.Default.ServerSaveCommand, false).Result)
|
||||
|
|
@ -551,7 +561,7 @@ namespace ServerManagerTool.Lib
|
|||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerShutdown_CancelMessage))
|
||||
{
|
||||
ProcessAlert(AlertType.Shutdown, Config.Default.ServerShutdown_CancelMessage);
|
||||
SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, CancellationToken.None).Wait();
|
||||
SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, cancellationToken).Wait();
|
||||
}
|
||||
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
|
|
@ -577,8 +587,6 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
finally
|
||||
{
|
||||
CloseRconConsole();
|
||||
|
||||
gameServer?.Dispose();
|
||||
gameServer = null;
|
||||
}
|
||||
|
|
@ -590,11 +598,9 @@ namespace ServerManagerTool.Lib
|
|||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerShutdown_CancelMessage))
|
||||
{
|
||||
ProcessAlert(AlertType.Shutdown, Config.Default.ServerShutdown_CancelMessage);
|
||||
SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, CancellationToken.None).Wait();
|
||||
SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, cancellationToken).Wait();
|
||||
}
|
||||
|
||||
CloseRconConsole();
|
||||
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
|
@ -643,8 +649,6 @@ namespace ServerManagerTool.Lib
|
|||
LogProfileMessage("Exiting server timed out, attempting to close the server.");
|
||||
}
|
||||
|
||||
CloseRconConsole();
|
||||
|
||||
// Method 2 - Close the process
|
||||
sent = process.CloseMainWindow();
|
||||
|
||||
|
|
@ -711,7 +715,7 @@ namespace ServerManagerTool.Lib
|
|||
ExitCode = EXITCODE_SHUTDOWN_TIMEOUT;
|
||||
}
|
||||
|
||||
private void UpgradeLocal(bool validate, CancellationToken cancellationToken, bool updateMods)
|
||||
private void UpgradeLocal(bool validate, bool updateMods, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_profile == null)
|
||||
{
|
||||
|
|
@ -1240,7 +1244,7 @@ namespace ServerManagerTool.Lib
|
|||
{
|
||||
// perform a steamcmd validate to confirm all the files
|
||||
LogProfileMessage("Validating server files (*new*).");
|
||||
UpgradeLocal(true, CancellationToken.None, false);
|
||||
UpgradeLocal(true, false, CancellationToken.None);
|
||||
LogProfileMessage("Validated server files (*new*).");
|
||||
}
|
||||
|
||||
|
|
@ -1766,17 +1770,6 @@ namespace ServerManagerTool.Lib
|
|||
ExitCode = EXITCODE_NORMALEXIT;
|
||||
}
|
||||
|
||||
private void CloseRconConsole()
|
||||
{
|
||||
if (_rconConsole != null)
|
||||
{
|
||||
_rconConsole.Dispose();
|
||||
_rconConsole = null;
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckServerWorldFileExists(ServerProfileSnapshot profile = null)
|
||||
{
|
||||
// do nothing if profile is null or SotF
|
||||
|
|
@ -2568,39 +2561,42 @@ namespace ServerManagerTool.Lib
|
|||
int rconRetries = 0;
|
||||
int maxRetries = retryIfFailed ? RCON_MAXRETRIES : 1;
|
||||
|
||||
while (retries < maxRetries && rconRetries < RCON_MAXRETRIES)
|
||||
try
|
||||
{
|
||||
SetupRconConsole();
|
||||
|
||||
if (_rconConsole == null)
|
||||
while (retries < maxRetries && rconRetries < RCON_MAXRETRIES)
|
||||
{
|
||||
LogProfileMessage($"RCON> {command} - attempt {rconRetries + 1} (a).", false);
|
||||
#if DEBUG
|
||||
LogProfileMessage("RCON connection not created.", false);
|
||||
#endif
|
||||
rconRetries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rconRetries = 0;
|
||||
try
|
||||
{
|
||||
_rconConsole.SendCommand(command);
|
||||
LogProfileMessage($"RCON> {command}");
|
||||
SetupRconConsole();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
if (_rconConsole == null)
|
||||
{
|
||||
LogProfileMessage($"RCON> {command} - attempt {retries + 1} (b).", false);
|
||||
#if DEBUG
|
||||
LogProfileMessage($"{ex.Message}", false);
|
||||
#endif
|
||||
LogProfileMessage($"RCON> {command} - attempt {rconRetries + 1} (a).", false);
|
||||
LogProfileMessage("RCON connection not created.", false);
|
||||
rconRetries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rconRetries = 0;
|
||||
try
|
||||
{
|
||||
_rconConsole.SendCommand(command);
|
||||
LogProfileMessage($"RCON> {command}");
|
||||
|
||||
retries++;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogProfileMessage($"RCON> {command} - attempt {retries + 1} (b).", false);
|
||||
LogProfileMessage($"{ex.Message}", false);
|
||||
}
|
||||
|
||||
retries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseRconConsole();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2662,6 +2658,17 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
}
|
||||
|
||||
private void CloseRconConsole()
|
||||
{
|
||||
if (_rconConsole != null)
|
||||
{
|
||||
_rconConsole.Dispose();
|
||||
_rconConsole = null;
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupRconConsole()
|
||||
{
|
||||
CloseRconConsole();
|
||||
|
|
@ -2671,7 +2678,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
try
|
||||
{
|
||||
var endPoint = new IPEndPoint(IPAddress.Parse(_profile.ServerIP), _profile.RCONPort);
|
||||
var endPoint = new IPEndPoint(_profile.ServerIPAddress, _profile.RCONPort);
|
||||
var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endPoint, sendTimeOut: 10000, receiveTimeOut: 10000);
|
||||
if (server == null)
|
||||
{
|
||||
|
|
@ -2708,7 +2715,7 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
}
|
||||
|
||||
public int PerformProfileBackup(ServerProfileSnapshot profile)
|
||||
public int PerformProfileBackup(ServerProfileSnapshot profile, CancellationToken cancellationToken)
|
||||
{
|
||||
_profile = profile;
|
||||
|
||||
|
|
@ -2733,7 +2740,7 @@ namespace ServerManagerTool.Lib
|
|||
// check if the mutex was established
|
||||
if (createdNew)
|
||||
{
|
||||
BackupServer();
|
||||
BackupServer(cancellationToken);
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
{
|
||||
|
|
@ -2869,7 +2876,7 @@ namespace ServerManagerTool.Lib
|
|||
return ExitCode;
|
||||
}
|
||||
|
||||
public int PerformProfileUpdate(ServerBranchSnapshot branch, ServerProfileSnapshot profile)
|
||||
public int PerformProfileUpdate(BranchSnapshot branch, ServerProfileSnapshot profile)
|
||||
{
|
||||
_profile = profile;
|
||||
|
||||
|
|
@ -2945,7 +2952,7 @@ namespace ServerManagerTool.Lib
|
|||
return ExitCode;
|
||||
}
|
||||
|
||||
public int PerformServerBranchUpdate(ServerBranchSnapshot branch)
|
||||
public int PerformServerBranchUpdate(BranchSnapshot branch)
|
||||
{
|
||||
if (branch == null)
|
||||
return EXITCODE_NORMALEXIT;
|
||||
|
|
@ -3089,7 +3096,7 @@ namespace ServerManagerTool.Lib
|
|||
SendEmails = true,
|
||||
ServerProcess = ServerProcessType.AutoBackup
|
||||
};
|
||||
exitCodes.TryAdd(profile, app.PerformProfileBackup(profile));
|
||||
exitCodes.TryAdd(profile, app.PerformProfileBackup(profile, CancellationToken.None));
|
||||
});
|
||||
|
||||
foreach (var profile in _profiles.Keys)
|
||||
|
|
@ -3233,8 +3240,8 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
if (exitCode == EXITCODE_NORMALEXIT)
|
||||
{
|
||||
var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => new ServerBranchSnapshot() { BranchName = p.BranchName, BranchPassword = p.BranchPassword}).Distinct(new ServerBranchSnapshotComparer()).ToArray();
|
||||
var exitCodes = new ConcurrentDictionary<ServerBranchSnapshot, int>();
|
||||
var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => BranchSnapshot.Create(p)).Distinct(new BranchSnapshotComparer()).ToArray();
|
||||
var exitCodes = new ConcurrentDictionary<BranchSnapshot, int>();
|
||||
|
||||
// update the server cache for each branch
|
||||
if (Config.Default.AutoUpdate_ParallelUpdate)
|
||||
|
|
|
|||
|
|
@ -957,6 +957,64 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
#endregion
|
||||
|
||||
#region Discord Bot
|
||||
public static readonly DependencyProperty DiscordChannelIdProperty = DependencyProperty.Register(nameof(DiscordChannelId), typeof(string), typeof(ServerProfile), new PropertyMetadata(String.Empty));
|
||||
[DataMember]
|
||||
public string DiscordChannelId
|
||||
{
|
||||
get { return (string)GetValue(DiscordChannelIdProperty); }
|
||||
set { SetValue(DiscordChannelIdProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordBackupProperty = DependencyProperty.Register(nameof(AllowDiscordBackup), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordBackup
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordBackupProperty); }
|
||||
set { SetValue(AllowDiscordBackupProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordRestartProperty = DependencyProperty.Register(nameof(AllowDiscordRestart), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordRestart
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordRestartProperty); }
|
||||
set { SetValue(AllowDiscordRestartProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordShutdownProperty = DependencyProperty.Register(nameof(AllowDiscordShutdown), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordShutdown
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordShutdownProperty); }
|
||||
set { SetValue(AllowDiscordShutdownProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordStartProperty = DependencyProperty.Register(nameof(AllowDiscordStart), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordStart
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordStartProperty); }
|
||||
set { SetValue(AllowDiscordStartProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordStopProperty = DependencyProperty.Register(nameof(AllowDiscordStop), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordStop
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordStopProperty); }
|
||||
set { SetValue(AllowDiscordStopProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordUpdateProperty = DependencyProperty.Register(nameof(AllowDiscordUpdate), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordUpdate
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordUpdateProperty); }
|
||||
set { SetValue(AllowDiscordUpdateProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Rules
|
||||
public static readonly DependencyProperty EnableHardcoreProperty = DependencyProperty.Register(nameof(EnableHardcore), typeof(bool), typeof(ServerProfile), new PropertyMetadata(false));
|
||||
[IniFileEntry(IniFiles.GameUserSettings, IniSections.GUS_ServerSettings, ServerProfileCategory.Rules, "ServerHardcore")]
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ namespace ServerManagerTool.Lib
|
|||
{
|
||||
public class ServerProfileSnapshot
|
||||
{
|
||||
private ServerProfileSnapshot()
|
||||
{
|
||||
}
|
||||
|
||||
public string ProfileId;
|
||||
public string ProfileName;
|
||||
public string InstallDirectory;
|
||||
|
|
@ -16,7 +20,7 @@ namespace ServerManagerTool.Lib
|
|||
public string AdminPassword;
|
||||
public string ServerName;
|
||||
public string ServerArgs;
|
||||
public string ServerIP;
|
||||
public IPAddress ServerIPAddress;
|
||||
public int ServerPort;
|
||||
public int ServerPeerPort;
|
||||
public int QueryPort;
|
||||
|
|
@ -67,7 +71,7 @@ namespace ServerManagerTool.Lib
|
|||
AdminPassword = profile.AdminPassword,
|
||||
ServerName = profile.ServerName,
|
||||
ServerArgs = profile.GetServerArgs(),
|
||||
ServerIP = string.IsNullOrWhiteSpace(profile.ServerIP) ? IPAddress.Loopback.ToString() : profile.ServerIP.Trim(),
|
||||
ServerIPAddress = string.IsNullOrWhiteSpace(profile.ServerIP) ? IPAddress.Loopback : IPAddress.TryParse(profile.ServerIP.Trim(), out IPAddress ipAddress) ? ipAddress : IPAddress.Loopback,
|
||||
ServerPort = profile.ServerPort,
|
||||
ServerPeerPort = profile.ServerPeerPort,
|
||||
QueryPort = profile.QueryPort,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace ServerManagerTool.Lib
|
|||
public event EventHandler StatusUpdate;
|
||||
|
||||
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private static readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private readonly List<PropertyChangeNotifier> profileNotifiers = new List<PropertyChangeNotifier>();
|
||||
private Process serverProcess;
|
||||
private IAsyncDisposable updateRegistration;
|
||||
|
|
@ -169,6 +169,9 @@ namespace ServerManagerTool.Lib
|
|||
ServerProfile.ServerIPProperty,
|
||||
ServerProfile.MaxPlayersProperty,
|
||||
|
||||
ServerProfile.ServerPasswordProperty,
|
||||
ServerProfile.AdminPasswordProperty,
|
||||
|
||||
ServerProfile.ServerMapProperty,
|
||||
ServerProfile.ServerModIdsProperty,
|
||||
ServerProfile.TotalConversionModIdProperty,
|
||||
|
|
@ -177,7 +180,7 @@ namespace ServerManagerTool.Lib
|
|||
},
|
||||
(s, p) =>
|
||||
{
|
||||
if (Status == ServerStatus.Stopped || Status == ServerStatus.Uninstalled || Status == ServerStatus.Unknown)
|
||||
if (Status == ServerStatus.Stopped || Status == ServerStatus.Uninstalled || Status == ServerStatus.Unknown || Status == ServerStatus.Updating)
|
||||
{
|
||||
AttachToProfileCore(profile);
|
||||
}
|
||||
|
|
@ -198,16 +201,7 @@ namespace ServerManagerTool.Lib
|
|||
return;
|
||||
}
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(this.ProfileSnapshot.ServerIP) && IPAddress.TryParse(this.ProfileSnapshot.ServerIP, out IPAddress localServerIpAddress))
|
||||
{
|
||||
// Use the explicit Server IP
|
||||
localServerQueryEndPoint = new IPEndPoint(localServerIpAddress, Convert.ToUInt16(this.ProfileSnapshot.QueryPort));
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Server IP specified, use Loopback
|
||||
localServerQueryEndPoint = new IPEndPoint(IPAddress.Loopback, Convert.ToUInt16(this.ProfileSnapshot.QueryPort));
|
||||
}
|
||||
localServerQueryEndPoint = new IPEndPoint(this.ProfileSnapshot.ServerIPAddress, Convert.ToUInt16(this.ProfileSnapshot.QueryPort));
|
||||
|
||||
//
|
||||
// Get the public endpoint for querying Steam
|
||||
|
|
@ -281,13 +275,13 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
case WatcherServerStatus.RunningLocalCheck:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
UpdateServerStatus(ServerStatus.Running, this.Availability != AvailabilityStatus.Available ? AvailabilityStatus.WaitingForPublication : this.Availability, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
UpdateServerStatus(ServerStatus.Running, this.Availability != AvailabilityStatus.Available ? AvailabilityStatus.Waiting : this.Availability, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.RunningExternalCheck:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.WaitingForPublication, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.Waiting, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
break;
|
||||
|
||||
|
|
@ -439,7 +433,7 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
|
||||
CheckServerWorldFileExists();
|
||||
UpdateServerStatus(ServerStatus.Initializing, this.Availability, false);
|
||||
UpdateServerStatus(ServerStatus.Initializing, false);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -498,12 +492,12 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, ServerBranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
|
||||
public async Task<bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, BranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
|
||||
{
|
||||
return await UpgradeAsync(cancellationToken, updateServer, branch, validate, updateMods, null, progressCallback);
|
||||
}
|
||||
|
||||
public async Task<bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, ServerBranchSnapshot branch, bool validate, bool updateMods, string[] updateModIds, ProgressDelegate progressCallback)
|
||||
public async Task<bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, BranchSnapshot branch, bool validate, bool updateMods, string[] updateModIds, ProgressDelegate progressCallback)
|
||||
{
|
||||
if (updateServer && !Environment.Is64BitOperatingSystem)
|
||||
{
|
||||
|
|
@ -520,7 +514,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
bool isNewInstallation = this.Status == ServerStatus.Uninstalled;
|
||||
|
||||
UpdateServerStatus(ServerStatus.Updating, Availability, false);
|
||||
UpdateServerStatus(ServerStatus.Updating, false);
|
||||
|
||||
// Run the SteamCMD to install the server
|
||||
var steamCmdFile = SteamCmdUpdater.GetSteamCmdFile(Config.Default.DataDir);
|
||||
|
|
@ -957,7 +951,7 @@ namespace ServerManagerTool.Lib
|
|||
finally
|
||||
{
|
||||
this.lastModStatusQuery = DateTime.MinValue;
|
||||
UpdateServerStatus(ServerStatus.Stopped, Availability, false);
|
||||
UpdateServerStatus(ServerStatus.Stopped, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -993,6 +987,11 @@ namespace ServerManagerTool.Lib
|
|||
this.lastModStatusQuery = DateTime.MinValue;
|
||||
}
|
||||
|
||||
public void UpdateServerStatus(ServerStatus serverStatus, bool sendAlert)
|
||||
{
|
||||
UpdateServerStatus(serverStatus, Availability, sendAlert);
|
||||
}
|
||||
|
||||
public void UpdateServerStatus(ServerStatus serverStatus, AvailabilityStatus availabilityStatus, bool sendAlert)
|
||||
{
|
||||
this.Status = serverStatus;
|
||||
|
|
@ -1006,32 +1005,29 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
public void UpdateServerStatusString()
|
||||
{
|
||||
switch (Status)
|
||||
StatusString = GetServerStatusString(Status);
|
||||
}
|
||||
|
||||
public static string GetServerStatusString(ServerStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusInitializingLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusInitializingLabel");
|
||||
case ServerStatus.Running:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusRunningLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusRunningLabel");
|
||||
case ServerStatus.Stopped:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppedLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppedLabel");
|
||||
case ServerStatus.Stopping:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppingLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppingLabel");
|
||||
case ServerStatus.Uninstalled:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUninstalledLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUninstalledLabel");
|
||||
case ServerStatus.Unknown:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
|
||||
case ServerStatus.Updating:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUpdatingLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUpdatingLabel");
|
||||
default:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1091,7 +1087,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
try
|
||||
{
|
||||
var endPoint = new IPEndPoint(IPAddress.Parse(this.ProfileSnapshot.ServerIP), this.ProfileSnapshot.RCONPort);
|
||||
var endPoint = new IPEndPoint(this.ProfileSnapshot.ServerIPAddress, this.ProfileSnapshot.RCONPort);
|
||||
var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endPoint, sendTimeOut: 10000, receiveTimeOut: 10000);
|
||||
|
||||
if (server == null)
|
||||
|
|
|
|||
|
|
@ -713,5 +713,15 @@
|
|||
<Label Content="{DynamicResource GlobalSettings_SetLocationButtonLabel}" VerticalAlignment="Center" Margin="0,-3,0,-3"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="DiscordBotApplyButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_DiscordBotApplyButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="DiscordBotHelpButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_DiscordBotHelpButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
|
||||
</Globalization:StyleResourceDictionary>
|
||||
735
src/ARKServerManager/Utils/DiscordBotHelper.cs
Normal file
735
src/ARKServerManager/Utils/DiscordBotHelper.cs
Normal file
|
|
@ -0,0 +1,735 @@
|
|||
using QueryMaster;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.DiscordBot.Enums;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool.Utils
|
||||
{
|
||||
internal static class DiscordBotHelper
|
||||
{
|
||||
private static readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private static bool _runningCommand = false;
|
||||
|
||||
private static readonly Dictionary<string, CommandType> _currentProfileCommands = new Dictionary<string, CommandType>();
|
||||
|
||||
public static bool HasRunningCommands => _currentProfileCommands.Count > 0;
|
||||
|
||||
public static IList<string> HandleDiscordCommand(CommandType commandType, string serverId, string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
// check if incoming values are valid
|
||||
if (string.IsNullOrWhiteSpace(serverId) || string.IsNullOrWhiteSpace(channelId))
|
||||
return null;
|
||||
|
||||
// check if the server ids match
|
||||
if (!serverId.Equals(Config.Default.DiscordBotServerId))
|
||||
return new List<string>();
|
||||
|
||||
if (_runningCommand)
|
||||
return new List<string> { _globalizer.GetResourceString("DiscordBot_CommandRunning") };
|
||||
_runningCommand = true;
|
||||
|
||||
try
|
||||
{
|
||||
switch (commandType)
|
||||
{
|
||||
case CommandType.Info:
|
||||
return GetServerInfo(channelId, profileId);
|
||||
case CommandType.List:
|
||||
return GetServerList(channelId);
|
||||
case CommandType.Status:
|
||||
return GetServerStatus(channelId, profileId);
|
||||
|
||||
case CommandType.Backup:
|
||||
if (Config.Default.AllowDiscordBackup)
|
||||
return BackupServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Restart:
|
||||
if (Config.Default.AllowDiscordRestart)
|
||||
return RestartServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Shutdown:
|
||||
if (Config.Default.AllowDiscordShutdown)
|
||||
return ShutdownServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Stop:
|
||||
if (Config.Default.AllowDiscordStop)
|
||||
return StopServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Start:
|
||||
if (Config.Default.AllowDiscordStart)
|
||||
return StartServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Update:
|
||||
if (Config.Default.AllowDiscordUpdate)
|
||||
return UpdateServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
|
||||
default:
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandUnknown"), commandType) };
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = ex.InnerException is null ? ex.Message : ex.InnerException.Message;
|
||||
return new string[] { message };
|
||||
}
|
||||
finally
|
||||
{
|
||||
_runningCommand = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string HandleTranslation(string translationKey)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(translationKey) ? string.Empty : _globalizer.GetResourceString(translationKey) ?? translationKey;
|
||||
}
|
||||
|
||||
private static IList<string> GetServerInfo(string channelId, string profileId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Info) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Info);
|
||||
|
||||
try
|
||||
{
|
||||
var serverName = string.Empty;
|
||||
var serverIp = IPAddress.Loopback;
|
||||
var queryPort = 0;
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Stopped:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
}
|
||||
|
||||
serverName = server.Profile.ServerName;
|
||||
if (!string.IsNullOrWhiteSpace(server.Profile.ServerIP))
|
||||
{
|
||||
IPAddress.TryParse(server.Profile.ServerIP, out serverIp);
|
||||
}
|
||||
queryPort = server.Profile.QueryPort;
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
using (var gameServer = ServerQuery.GetServerInstance(EngineType.Source, new IPEndPoint(serverIp, queryPort)))
|
||||
{
|
||||
var info = gameServer?.GetInfo();
|
||||
if (info is null)
|
||||
{
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_InfoFailed"), serverName));
|
||||
}
|
||||
else
|
||||
{
|
||||
var mapName = _globalizer.GetResourceString($"Map_{info.Map}") ?? info.Map;
|
||||
response.Add($"```{info.Name}\n{_globalizer.GetResourceString("DiscordBot_MapLabel")} {mapName}\n{_globalizer.GetResourceString("ServerSettings_PlayersLabel")} {info.Players} / {info.MaxPlayers}```");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_InfoFailed"), serverName));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> GetServerList(string channelId)
|
||||
{
|
||||
List<string> response = new List<string>();
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var serverList = ServerManager.Instance.Servers.Where(s => Equals(channelId, s.Profile.DiscordChannelId));
|
||||
|
||||
response.Add($"**{_globalizer.GetResourceString("DiscordBot_CountLabel")}** {serverList.Count()}");
|
||||
foreach (var server in serverList)
|
||||
{
|
||||
response.Add($"```{_globalizer.GetResourceString("ServerSettings_ProfileIdLabel")} {server.Profile.ProfileID}\n{_globalizer.GetResourceString("ServerSettings_ProfileLabel")} {server.Profile.ProfileName}\n{_globalizer.GetResourceString("ServerSettings_ServerNameLabel")} {server.Profile.ServerName}```");
|
||||
}
|
||||
}).Wait();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private static IList<string> GetServerStatus(string channelId, string profileId)
|
||||
{
|
||||
List<string> response = new List<string>();
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var serverList = ServerManager.Instance.Servers.Where(s => Equals(channelId, s.Profile.DiscordChannelId) && (string.IsNullOrWhiteSpace(profileId) || Equals(profileId, s.Profile.ProfileID)));
|
||||
|
||||
response.Add($"**{_globalizer.GetResourceString("DiscordBot_CountLabel")}** {serverList.Count()}");
|
||||
foreach (var server in serverList)
|
||||
{
|
||||
response.Add($"```{_globalizer.GetResourceString("ServerSettings_ProfileLabel")} {server.Profile.ProfileName}\n{_globalizer.GetResourceString("ServerSettings_ServerNameLabel")} {server.Profile.ServerName}\n{_globalizer.GetResourceString("ServerSettings_StatusLabel")} {server.Runtime.StatusString}\n{_globalizer.GetResourceString("ServerSettings_AvailabilityLabel")} {_globalizer.GetResourceString($"ServerSettings_Availability_{server.Runtime.Availability}")}```");
|
||||
}
|
||||
}).Wait();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private static IList<string> BackupServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Backup) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Backup);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordBackup)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Backup, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileBackup(profile, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_BackupRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> RestartServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Restart) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Restart);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordRestart)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Restart, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
profile.AutoRestartIfShutdown = true;
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, true, false, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_RestartRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> ShutdownServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Shutdown) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Shutdown);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordShutdown)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Shutdown, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Stopped:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, false, false, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_ShutdownRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> StopServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Stop) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Stop);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordStop)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Stop, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Stopped:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !Config.Default.AutoBackup_EnableBackup,
|
||||
OutputLogs = false,
|
||||
SendAlerts = true,
|
||||
SendEmails = false,
|
||||
ServerProcess = ServerProcessType.Shutdown,
|
||||
ShutdownInterval = 0,
|
||||
ServerStatusChangeCallback = (ServerStatus serverStatus) =>
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, false, false, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_StopRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> StartServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Start) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Start);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordStart)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Start, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Running:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
profile.AutoRestartIfShutdown = true;
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, true, false, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_StartRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> UpdateServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Update) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Update);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
bool performRestart = false;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordUpdate)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Update, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Running:
|
||||
performRestart = true;
|
||||
break;
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, performRestart, true, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_UpdateRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/ARKServerManager/Utils/DiscordPluginHelper.cs
Normal file
18
src/ARKServerManager/Utils/DiscordPluginHelper.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using ServerManagerTool.Lib;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ServerManagerTool.Utils
|
||||
{
|
||||
internal static class DiscordPluginHelper
|
||||
{
|
||||
public static IList<Plugin.Common.Lib.Profile> FetchProfiles()
|
||||
{
|
||||
return ServerManager.Instance.Servers.Select(s => new ServerManagerTool.Plugin.Common.Lib.Profile()
|
||||
{
|
||||
ProfileName = s?.Profile?.ProfileName ?? string.Empty,
|
||||
InstallationFolder = s?.Profile?.InstallDirectory ?? string.Empty
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -579,6 +579,55 @@
|
|||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="19" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<CheckBox IsChecked="{Binding CurrentConfig.DiscordBotEnabled}" Content="{DynamicResource GlobalSettings_DiscordBotLabel}" VerticalAlignment="Center"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid IsEnabled="{Binding CurrentConfig.DiscordBotEnabled}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="60"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="60"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="60"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="8" Margin="5" Text="{DynamicResource GlobalSettings_DiscordBotInformationLabel}" TextWrapping="Wrap" VerticalAlignment="Center" FontWeight="Bold" Foreground="{DynamicResource WarningMessage}"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource GlobalSettings_DiscordBotTokenLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="6" Margin="1" Name="HideDiscordBotTokenTextBox" Text="{DynamicResource ServerSettings_HidePasswordText}" ToolTip="{DynamicResource ServerSettings_HidePasswordTooltip}" GotFocus="HiddenField_GotFocus" Style="{StaticResource HiddenTextBoxStyle}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="6" Margin="1" Name="DiscordBotTokenTextBox" Text="{Binding CurrentConfig.DiscordBotToken}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_DiscordBotTokenTooltip}" LostFocus="HiddenField_LostFocus" Visibility="Collapsed"/>
|
||||
<StackPanel Grid.Row="1" Grid.Column="7" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Margin="1" Content="{DynamicResource DiscordBotApplyButtonContent}" Click="DiscordBotApply_Click"/>
|
||||
<Button Margin="1" Content="{DynamicResource DiscordBotHelpButtonContent}" Click="DiscordBotHelp_Click"/>
|
||||
</StackPanel>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource GlobalSettings_DiscordBotServerLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.DiscordBotServerId}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_DiscordBotServerTooltip}"/>
|
||||
<Label Grid.Row="2" Grid.Column="3" Content="{DynamicResource GlobalSettings_DiscordBotPrefixLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="4" Margin="1" Text="{Binding CurrentConfig.DiscordBotPrefix}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_DiscordBotPrefixTooltip}"/>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="1" Margin="0,5,0,0" IsChecked="{Binding CurrentConfig.AllowDiscordBackup}" Content="{DynamicResource ServerSettings_AllowDiscordBackupLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowBackupTooltip}"/>
|
||||
<CheckBox Grid.Row="3" Grid.Column="4" Margin="0,5,0,0" IsChecked="{Binding CurrentConfig.AllowDiscordUpdate}" Content="{DynamicResource ServerSettings_AllowDiscordUpdateLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowUpdateTooltip}"/>
|
||||
<CheckBox Grid.Row="3" Grid.Column="7" Margin="0,5,0,0" IsChecked="{Binding CurrentConfig.AllowDiscordStart}" Content="{DynamicResource ServerSettings_AllowDiscordStartLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowStartTooltip}"/>
|
||||
|
||||
<CheckBox Grid.Row="4" Grid.Column="1" Margin="0,5,0,5" IsChecked="{Binding CurrentConfig.AllowDiscordRestart}" Content="{DynamicResource ServerSettings_AllowDiscordRestartLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowRestartTooltip}"/>
|
||||
<CheckBox Grid.Row="4" Grid.Column="4" Margin="0,5,0,5" IsChecked="{Binding CurrentConfig.AllowDiscordShutdown}" Content="{DynamicResource ServerSettings_AllowDiscordShutdownLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowShutdownTooltip}"/>
|
||||
<CheckBox Grid.Row="4" Grid.Column="7" Margin="0,5,0,5" IsChecked="{Binding CurrentConfig.AllowDiscordStop}" Content="{DynamicResource ServerSettings_AllowDiscordStopLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowStopTooltip}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="20" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_EmailSettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
|
@ -621,7 +670,7 @@
|
|||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="20" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox Grid.Row="21" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_EmailNotifySettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
|
@ -645,7 +694,7 @@
|
|||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="21" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox Grid.Row="22" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_AdvancedSettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
|
|
|||
|
|
@ -289,6 +289,16 @@ namespace ServerManagerTool
|
|||
}
|
||||
}
|
||||
|
||||
private void DiscordBotApply_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start(Config.Default.DiscordBotApplyUrl);
|
||||
}
|
||||
|
||||
private void DiscordBotHelp_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start(Config.Default.DiscordBotHelpUrl);
|
||||
}
|
||||
|
||||
private void ComboBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
var comboBox = sender as ComboBox;
|
||||
|
|
@ -326,6 +336,8 @@ namespace ServerManagerTool
|
|||
textBox = SteamAPIKeyTextBox;
|
||||
if (Equals(hideTextBox, HideEmailPasswordTextBox))
|
||||
textBox = EmailPasswordTextBox;
|
||||
if (Equals(hideTextBox, HideDiscordBotTokenTextBox))
|
||||
textBox = DiscordBotTokenTextBox;
|
||||
|
||||
if (textBox != null)
|
||||
{
|
||||
|
|
@ -349,6 +361,8 @@ namespace ServerManagerTool
|
|||
hideTextBox = HideSteamAPIKeyTextBox;
|
||||
if (textBox == EmailPasswordTextBox)
|
||||
hideTextBox = HideEmailPasswordTextBox;
|
||||
if (textBox == DiscordBotTokenTextBox)
|
||||
hideTextBox = HideDiscordBotTokenTextBox;
|
||||
|
||||
if (hideTextBox != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
xmlns:enum="clr-namespace:ServerManagerTool.Enums"
|
||||
MinWidth="900" MinHeight="600" Width="1100" Height="900" Left="50" Top="50" WindowState="Normal"
|
||||
Loaded="Window_Loaded" SizeChanged="Window_SizeChanged" StateChanged="Window_StateChanged" LocationChanged="Window_LocationChanged"
|
||||
Loaded="MainWindow_Loaded" SizeChanged="MainWindow_SizeChanged" StateChanged="MainWindow_StateChanged" LocationChanged="MainWindow_LocationChanged"
|
||||
Name="Main" Icon="../Art/favicon.ico" Title="{DynamicResource MainWindow_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using ServerManagerTool.Common.Utils;
|
|||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using ServerManagerTool.Utils;
|
||||
using ServerManagerTool.Windows;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
|
@ -169,7 +170,7 @@ namespace ServerManagerTool
|
|||
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//
|
||||
// Kick off the initialization.
|
||||
|
|
@ -199,15 +200,7 @@ namespace ServerManagerTool
|
|||
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
|
||||
}
|
||||
|
||||
private void Window_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is Window window)
|
||||
window.Closed -= Window_Closed;
|
||||
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
private void Window_LocationChanged(object sender, EventArgs e)
|
||||
private void MainWindow_LocationChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (this.WindowState == WindowState.Normal)
|
||||
{
|
||||
|
|
@ -216,7 +209,7 @@ namespace ServerManagerTool
|
|||
}
|
||||
}
|
||||
|
||||
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (this.WindowState == WindowState.Normal)
|
||||
{
|
||||
|
|
@ -225,7 +218,7 @@ namespace ServerManagerTool
|
|||
}
|
||||
}
|
||||
|
||||
private void Window_StateChanged(object sender, EventArgs e)
|
||||
private void MainWindow_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Config.Default.MainWindow_MinimizeToTray && this.WindowState == WindowState.Minimized)
|
||||
{
|
||||
|
|
@ -233,8 +226,26 @@ namespace ServerManagerTool
|
|||
}
|
||||
}
|
||||
|
||||
private void Window_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is Window window)
|
||||
window.Closed -= Window_Closed;
|
||||
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
if (DiscordBotHelper.HasRunningCommands)
|
||||
{
|
||||
var result = MessageBox.Show(_globalizer.GetResourceString("MainWindow_DiscordBot_RunningCommandsLabel"), _globalizer.GetResourceString("MainWindow_DiscordBot_RunningCommandsTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.No)
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
base.OnClosing(e);
|
||||
RCONWindow.CloseAllWindows();
|
||||
PlayerListWindow.CloseAllWindows();
|
||||
|
|
|
|||
|
|
@ -664,7 +664,7 @@ namespace ServerManagerTool
|
|||
ProfileId = server.Runtime.ProfileSnapshot.ProfileId,
|
||||
ProfileName = server.Runtime.ProfileSnapshot.ProfileName,
|
||||
MaxPlayers = server.Runtime.MaxPlayers,
|
||||
RCONHost = server.Runtime.ProfileSnapshot.ServerIP,
|
||||
RCONHost = server.Runtime.ProfileSnapshot.ServerIPAddress.ToString(),
|
||||
RCONPort = server.Runtime.ProfileSnapshot.RCONPort,
|
||||
|
||||
PGM_Enabled = server.Profile.PGM_Enabled,
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ namespace ServerManagerTool.Windows
|
|||
|
||||
var profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
|
||||
var exitCode = await Task.Run(() => app.PerformProfileBackup(profile));
|
||||
var exitCode = await Task.Run(() => app.PerformProfileBackup(profile, CancellationToken.None));
|
||||
if (exitCode != ServerApp.EXITCODE_NORMALEXIT && exitCode != ServerApp.EXITCODE_CANCELLED)
|
||||
{
|
||||
throw new ApplicationException($"An error occured during the backup process - ExitCode: {exitCode}");
|
||||
|
|
@ -623,7 +623,7 @@ namespace ServerManagerTool.Windows
|
|||
|
||||
await Task.Delay(1000);
|
||||
|
||||
var branch = new ServerBranchSnapshot() { BranchName = serverProfile.BranchName, BranchPassword = serverProfile.BranchPassword };
|
||||
var branch = BranchSnapshot.Create(serverProfile);
|
||||
return await server.UpgradeAsync(_upgradeCancellationSource.Token, updateServer, branch, true, updateMods, (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { window?.AddMessage(m, n); }).DoNotWait(); });
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -420,13 +420,13 @@
|
|||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.Unknown}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Unknown}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.NeedPublicIP}">
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.SetPublicIP}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_SetPublicIP}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.Unavailable}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Unavailable}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.WaitingForPublication}">
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.Waiting}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Waiting}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.Available}">
|
||||
|
|
@ -1579,6 +1579,55 @@
|
|||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
<Expander Name="SectionDiscordBot" IsExpanded="{Binding CurrentConfig.SectionDiscordBotIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding CurrentConfig.DiscordBotEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<Expander.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{DynamicResource ServerSettings_DiscordBotLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Expander.Header>
|
||||
|
||||
<Expander.Style>
|
||||
<Style BasedOn="{StaticResource ExpanderStyle1}" TargetType="{x:Type Expander}">
|
||||
<Setter Property="Template" Value="{StaticResource ExpanderTemplateSE}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding ElementName=EnableSOTFCheckbox, Path=IsChecked}" Value="True">
|
||||
<Setter Property="Template" Value="{StaticResource ExpanderTemplateSotF}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ElementName=EnablePGMCheckbox, Path=IsChecked}" Value="True">
|
||||
<Setter Property="Template" Value="{StaticResource ExpanderTemplatePGM}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Expander.Style>
|
||||
|
||||
<Grid Margin="-8,0,2,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource ServerSettings_DiscordBotChannelLabel}" ToolTip="{DynamicResource ServerSettings_DiscordBotChannelTooltip}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Text="{Binding DiscordChannelId, Mode=TwoWay}" ToolTip="{DynamicResource ServerSettings_DiscordBotChannelTooltip}" VerticalContentAlignment="Center" />
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5,0" IsChecked="{Binding AllowDiscordBackup, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordBackupLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordBackupTooltip}"/>
|
||||
<CheckBox Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Margin="5,5,5,0" IsChecked="{Binding AllowDiscordUpdate, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordUpdateLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordUpdateTooltip}"/>
|
||||
<CheckBox Grid.Row="1" Grid.Column="4" Grid.ColumnSpan="2" Margin="5,5,5,0" IsChecked="{Binding AllowDiscordStart, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordStartLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordStartTooltip}"/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" IsChecked="{Binding AllowDiscordRestart, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordRestartLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordRestartTooltip}"/>
|
||||
<CheckBox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" Margin="5" IsChecked="{Binding AllowDiscordShutdown, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordShutdownLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordShutdownTooltip}"/>
|
||||
<CheckBox Grid.Row="2" Grid.Column="4" Grid.ColumnSpan="2" Margin="5" IsChecked="{Binding AllowDiscordStop, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordStopLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordStopTooltip}"/>
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<Expander Name="SectionRules" IsExpanded="{Binding CurrentConfig.SectionRulesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
|
||||
<Expander.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
|
|
|||
|
|
@ -1099,7 +1099,7 @@ namespace ServerManagerTool
|
|||
|
||||
var profile = ServerProfileSnapshot.Create(Server.Profile);
|
||||
|
||||
var exitCode = await Task.Run(() => app.PerformProfileBackup(profile));
|
||||
var exitCode = await Task.Run(() => app.PerformProfileBackup(profile, CancellationToken.None));
|
||||
if (exitCode != ServerApp.EXITCODE_NORMALEXIT && exitCode != ServerApp.EXITCODE_CANCELLED)
|
||||
throw new ApplicationException($"An error occured during the backup process - ExitCode: {exitCode}");
|
||||
|
||||
|
|
@ -4266,7 +4266,7 @@ namespace ServerManagerTool
|
|||
|
||||
await Task.Delay(1000);
|
||||
|
||||
var branch = new ServerBranchSnapshot() { BranchName = this.Server.Profile.BranchName, BranchPassword = this.Server.Profile.BranchPassword };
|
||||
var branch = BranchSnapshot.Create(this.Server.Profile);
|
||||
return await this.Server.UpgradeAsync(_upgradeCancellationSource.Token, updateServer, branch, true, updateMods, (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { window?.AddMessage(m, n); }).DoNotWait(); });
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -257,6 +257,12 @@
|
|||
<setting name="DefaultDataDirectoryName" serializeAs="String">
|
||||
<value>csmdata</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotApplyUrl" serializeAs="String">
|
||||
<value>https://discord.com/developers/applications</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotHelpUrl" serializeAs="String">
|
||||
<value>https://servermanagers.freeforums.net/thread/99/get-own-discord-bot</value>
|
||||
</setting>
|
||||
</ServerManagerTool.Config>
|
||||
<ServerManagerTool.Common.CommonConfig>
|
||||
<setting name="DefaultSteamAPIKey" serializeAs="String">
|
||||
|
|
@ -570,6 +576,39 @@
|
|||
<setting name="ServerFilesGridHeight" serializeAs="String">
|
||||
<value>250</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotEnabled" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotPrefix" serializeAs="String">
|
||||
<value>csm</value>
|
||||
</setting>
|
||||
<setting name="DiscordBotToken" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="DiscordBotServerId" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="SectionDiscordBotIsExpanded" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordBackup" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordUpdate" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordStart" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordRestart" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordShutdown" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AllowDiscordStop" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
</ServerManagerTool.Config>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using NLog;
|
||||
using NLog;
|
||||
using NLog.Config;
|
||||
using NLog.Targets;
|
||||
using ServerManagerTool.Common;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.DiscordBot;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using ServerManagerTool.Utils;
|
||||
using ServerManagerTool.Windows;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
|
@ -37,6 +37,7 @@ namespace ServerManagerTool
|
|||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private CancellationTokenSource _tokenSource;
|
||||
private GlobalizedApplication _globalizer;
|
||||
private bool _applicationStarted;
|
||||
private string _args;
|
||||
|
|
@ -175,11 +176,6 @@ namespace ServerManagerTool
|
|||
}
|
||||
}
|
||||
|
||||
private IList<Plugin.Common.Lib.Profile> FetchProfiles()
|
||||
{
|
||||
return ServerManager.Instance.Servers.Select(s => new ServerManagerTool.Plugin.Common.Lib.Profile() { ProfileName = s?.Profile?.ProfileName ?? string.Empty, InstallationFolder = s?.Profile?.InstallDirectory ?? string.Empty }).ToList();
|
||||
}
|
||||
|
||||
public static string GetLogFolder() => IOUtils.NormalizePath(Path.Combine(Config.Default.DataPath, Config.Default.LogsRelativePath));
|
||||
|
||||
public static string GetProfileLogFolder(string profileId) => IOUtils.NormalizePath(Path.Combine(Config.Default.DataPath, Config.Default.LogsRelativePath, profileId.ToLower()));
|
||||
|
|
@ -304,7 +300,7 @@ namespace ServerManagerTool
|
|||
var installPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
PluginHelper.Instance.BetaEnabled = this.BetaVersion;
|
||||
PluginHelper.Instance.LoadPlugins(installPath, true);
|
||||
PluginHelper.Instance.SetFetchProfileCallback(FetchProfiles);
|
||||
PluginHelper.Instance.SetFetchProfileCallback(DiscordPluginHelper.FetchProfiles);
|
||||
OnResourceDictionaryChanged(Thread.CurrentThread.CurrentCulture.Name);
|
||||
|
||||
// check if we are starting server manager for server shutdown
|
||||
|
|
@ -395,6 +391,7 @@ namespace ServerManagerTool
|
|||
|
||||
this.ApplicationStarted = true;
|
||||
|
||||
var restartRequired = false;
|
||||
if (string.IsNullOrWhiteSpace(Config.Default.DataPath))
|
||||
{
|
||||
var dataDirectoryWindow = new DataDirectoryWindow();
|
||||
|
|
@ -405,6 +402,8 @@ namespace ServerManagerTool
|
|||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
restartRequired = true;
|
||||
}
|
||||
|
||||
Config.Default.ConfigPath = Path.Combine(Config.Default.DataPath, Config.Default.ProfilesRelativePath);
|
||||
|
|
@ -412,6 +411,11 @@ namespace ServerManagerTool
|
|||
Config.Default.Save();
|
||||
CommonConfig.Default.Save();
|
||||
|
||||
if (restartRequired)
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
if (e.Args.Any(a => a.StartsWith(Constants.ARG_SERVERMONITOR, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
ServerRuntime.EnableUpdateModStatus = false;
|
||||
|
|
@ -426,6 +430,25 @@ namespace ServerManagerTool
|
|||
|
||||
StartupUri = new Uri("Windows/AutoUpdateWindow.xaml", UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
|
||||
if (Config.Default.DiscordBotEnabled)
|
||||
{
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
|
||||
Task discordTask = Task.Run(async () =>
|
||||
{
|
||||
await ServerManagerBotFactory.GetServerManagerBot()?.StartAsync(Config.Default.DiscordBotToken,Config.Default.DiscordBotPrefix, Config.Default.DataPath, DiscordBotHelper.HandleDiscordCommand, DiscordBotHelper.HandleTranslation, _tokenSource.Token);
|
||||
}, _tokenSource.Token)
|
||||
.ContinueWith(t => {
|
||||
var message = t.Exception.InnerException is null ? t.Exception.Message : t.Exception.InnerException.Message;
|
||||
if (message.StartsWith("#"))
|
||||
{
|
||||
message = _globalizer.GetResourceString(message.Substring(1)) ?? message.Substring(1);
|
||||
}
|
||||
|
||||
MessageBox.Show(message, _globalizer.GetResourceString("DiscordBot_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
|
|
@ -466,6 +489,12 @@ namespace ServerManagerTool
|
|||
|
||||
private void ShutDownApplication()
|
||||
{
|
||||
if (!(_tokenSource is null))
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
_tokenSource.Dispose();
|
||||
}
|
||||
|
||||
if (this.ApplicationStarted)
|
||||
{
|
||||
foreach (var server in ServerManager.Instance.Servers)
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Delegates\ServerStatusChangeDelegate.cs" />
|
||||
<Compile Include="Lib\Model\PlayerListParameters.cs" />
|
||||
<Compile Include="Lib\Model\RconParameters.cs" />
|
||||
<Compile Include="Lib\Serialization\IniFileEntryAttribute.cs" />
|
||||
|
|
@ -171,6 +172,8 @@
|
|||
<Compile Include="Lib\ViewConverters\EnumDescriptionTypeConverter.cs" />
|
||||
<Compile Include="Lib\ViewConverters\MapNameValueConverter.cs" />
|
||||
<Compile Include="Lib\ViewModel\PlayerInfo.cs" />
|
||||
<Compile Include="Utils\DiscordBotHelper.cs" />
|
||||
<Compile Include="Utils\DiscordPluginHelper.cs" />
|
||||
<Compile Include="Windows\AddUserWindow.xaml.cs">
|
||||
<DependentUpon>AddUserWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
|
|
|||
150
src/ConanServerManager/Config.Designer.cs
generated
150
src/ConanServerManager/Config.Designer.cs
generated
|
|
@ -1965,5 +1965,155 @@ namespace ServerManagerTool {
|
|||
return ((string)(this["DefaultDataDirectoryName"]));
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool DiscordBotEnabled {
|
||||
get {
|
||||
return ((bool)(this["DiscordBotEnabled"]));
|
||||
}
|
||||
set {
|
||||
this["DiscordBotEnabled"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("csm")]
|
||||
public string DiscordBotPrefix {
|
||||
get {
|
||||
return ((string)(this["DiscordBotPrefix"]));
|
||||
}
|
||||
set {
|
||||
this["DiscordBotPrefix"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string DiscordBotToken {
|
||||
get {
|
||||
return ((string)(this["DiscordBotToken"]));
|
||||
}
|
||||
set {
|
||||
this["DiscordBotToken"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string DiscordBotServerId {
|
||||
get {
|
||||
return ((string)(this["DiscordBotServerId"]));
|
||||
}
|
||||
set {
|
||||
this["DiscordBotServerId"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("https://discord.com/developers/applications")]
|
||||
public string DiscordBotApplyUrl {
|
||||
get {
|
||||
return ((string)(this["DiscordBotApplyUrl"]));
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("https://servermanagers.freeforums.net/thread/99/get-own-discord-bot")]
|
||||
public string DiscordBotHelpUrl {
|
||||
get {
|
||||
return ((string)(this["DiscordBotHelpUrl"]));
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool SectionDiscordBotIsExpanded {
|
||||
get {
|
||||
return ((bool)(this["SectionDiscordBotIsExpanded"]));
|
||||
}
|
||||
set {
|
||||
this["SectionDiscordBotIsExpanded"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordBackup {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordBackup"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordBackup"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordUpdate {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordUpdate"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordUpdate"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordStart {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordStart"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordStart"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordRestart {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordRestart"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordRestart"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordShutdown {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordShutdown"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordShutdown"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool AllowDiscordStop {
|
||||
get {
|
||||
return ((bool)(this["AllowDiscordStop"]));
|
||||
}
|
||||
set {
|
||||
this["AllowDiscordStop"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -545,5 +545,44 @@
|
|||
<Setting Name="DefaultDataDirectoryName" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">csmdata</Value>
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotEnabled" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotPrefix" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">csm</Value>
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotToken" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotServerId" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotApplyUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://discord.com/developers/applications</Value>
|
||||
</Setting>
|
||||
<Setting Name="DiscordBotHelpUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://servermanagers.freeforums.net/thread/99/get-own-discord-bot</Value>
|
||||
</Setting>
|
||||
<Setting Name="SectionDiscordBotIsExpanded" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordBackup" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordUpdate" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordStart" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordRestart" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordShutdown" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AllowDiscordStop" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
using ServerManagerTool.Enums;
|
||||
|
||||
namespace ServerManagerTool.Delegates
|
||||
{
|
||||
public delegate void ServerStatusChangeDelegate(ServerStatus serverStatus);
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@
|
|||
public enum AvailabilityStatus
|
||||
{
|
||||
Unknown,
|
||||
NeedPublicIP,
|
||||
SetPublicIP,
|
||||
Unavailable,
|
||||
WaitingForPublication,
|
||||
Waiting,
|
||||
Available
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@
|
|||
Backup,
|
||||
Shutdown,
|
||||
Restart,
|
||||
Update,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -628,6 +628,9 @@
|
|||
<sys:String x:Key="MainWindow_SteamCmd_FailedTitle">Reinstall SteamCMD Error</sys:String>
|
||||
<sys:String x:Key="MainWindow_SteamCmd_FailedLabel">An error occured while trying to reinstall SteamCMD. This has left SteamCmd in an unstable state, try reinstalling again or please report this.\r\nException: {0}</sys:String>
|
||||
|
||||
<sys:String x:Key="MainWindow_DiscordBot_RunningCommandsTitle">Discord Bot Running Commands</sys:String>
|
||||
<sys:String x:Key="MainWindow_DiscordBot_RunningCommandsLabel">The discord bot has one or more running commands, do you want to continue shutting down the server manager?</sys:String>
|
||||
|
||||
<sys:String x:Key="MainWindow_ServerStatus_StartServerActionTitle">Start Server Confirmation</sys:String>
|
||||
<sys:String x:Key="MainWindow_ServerStatus_StartServerActionLabel">You are about to start the server, do you want to continue?</sys:String>
|
||||
<sys:String x:Key="MainWindow_ServerStatus_ShutdownServerActionTitle">Shutdown Server Confirmation</sys:String>
|
||||
|
|
@ -768,6 +771,23 @@
|
|||
<sys:String x:Key="GlobalSettings_ShutdownAllMessagesShowReasonLabel">Show shutdown reason with ALL shutdown messages</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_ShutdownAllMessagesShowReasonTooltip">If enabled, the shutdown reason will be shown with all shutdown message; otherwise it will only be shown at the start of the server shutdown.</sys:String>
|
||||
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotLabel">Enable Discord Bot</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotInformationLabel">You will need to restart the server manager if you change any settings for the Discord Bot.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotTokenLabel">Token:</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotTokenTooltip">The token associated with the discord bot.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotServerLabel">Server Id:</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotServerTooltip">The id of the discord server the bot will listen to.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotPrefixLabel">Prefix:</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotPrefixTooltip">The prefix that must be used when sending a command via discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotApplyButtonLabel">Get Token...</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotHelpButtonLabel">Help...</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowBackupTooltip">If enabled, the backup command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowRestartTooltip">If enabled, the restart command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowShutdownTooltip">If enabled, the shutdown command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowStartTooltip">If enabled, the start command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowStopTooltip">If enabled, the stop command can be sent from discord.</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_DiscordBotAllowUpdateTooltip">If enabled, the update command can be sent from discord.</sys:String>
|
||||
|
||||
<sys:String x:Key="GlobalSettings_EmailSettingsLabel">SMTP Email Settings</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_EmailHostLabel">Host:</sys:String>
|
||||
<sys:String x:Key="GlobalSettings_EmailHostTooltip">The name or IP address of the host used for SMTP transmissions.</sys:String>
|
||||
|
|
@ -1121,6 +1141,24 @@
|
|||
<sys:String x:Key="ServerSettings_RestartIfShutdownTooltip">If enabled, the server will be restarted even if shutdown for Auto-Restarts and Auto-Updates.</sys:String>
|
||||
<!--#endregion-->
|
||||
|
||||
<!--#region Server Settings - Discord Bot Details -->
|
||||
<sys:String x:Key="ServerSettings_DiscordBotLabel">Discord Bot Details</sys:String>
|
||||
<sys:String x:Key="ServerSettings_DiscordBotChannelLabel">Channel Id:</sys:String>
|
||||
<sys:String x:Key="ServerSettings_DiscordBotChannelTooltip">The id of the discord server channel this profile will listen to.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordBackupLabel">Allow Backup</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordBackupTooltip">If enabled, the profile will listen for backup commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordRestartLabel">Allow Restart</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordRestartTooltip">If enabled, the profile will listen for restart commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordShutdownLabel">Allow Shutdown</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordShutdownTooltip">If enabled, the profile will listen for shutdown commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordStartLabel">Allow Start</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordStartTooltip">If enabled, the profile will listen for start commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordStopLabel">Allow Stop</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordStopTooltip">If enabled, the profile will listen for stop commands from discord.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordUpdateLabel">Allow Update</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AllowDiscordUpdateTooltip">If enabled, the profile will listen for update commands from discord.</sys:String>
|
||||
<!--#endregion-->
|
||||
|
||||
<!--#region Server Settings - Server File Details -->
|
||||
<sys:String x:Key="ServerSettings_ServerFilesLabel">Server File Details</sys:String>
|
||||
<sys:String x:Key="ServerSettings_ServerFilesWarningLabel">NOTE: Any changes will require a server restart to take effect.</sys:String>
|
||||
|
|
@ -1193,4 +1231,32 @@
|
|||
<sys:String x:Key="ServerUpdate_WarningLabel">There was a problem while performing the server update. This may leave your server in a incomplete state.\r\n\r\nDo you want to continue with the server start, this could cause problems?</sys:String>
|
||||
<!--#endregion-->
|
||||
|
||||
<!--#region Discord Bot -->
|
||||
<sys:String x:Key="DiscordBot_ErrorTitle">Discord Bot Error</sys:String>
|
||||
<sys:String x:Key="DiscordBot_MissingTokenError">The discord bot requires a valid token so it can log into the discord server\r\nThis can be set in the global settings.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_InvalidPrefixError">The discord bot prefix contains invalid characters. Only letters and numbers are allowed.</sys:String>
|
||||
|
||||
<sys:String x:Key="DiscordBot_CommandNotEnabled">Command '{0}' has not been enabled.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_CommandUnknown">Unknown command '{0}'.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_CommandRunning">Another command is currently being processed.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_CommandRunningProfile">Another command '{0}' is currently running against profile '{1}'.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_CommandDisabledProfile">Command '{0}' has been disabled for profile '{1}'.</sys:String>
|
||||
|
||||
<sys:String x:Key="DiscordBot_ProfileMissing">The '{0}' command requires a profile id.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_ProfileNotFound">Profile '{0}' was not found or is not associated with the channel.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_ProfileBadStatus">Profile '{0}' is in a state '{1}' that cannot run this command.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_ProfileUpdating">Profile '{0}' is currently being updated.</sys:String>
|
||||
|
||||
<sys:String x:Key="DiscordBot_InfoFailed">Call to server '{0}' failed.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_BackupRequested">A backup request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_RestartRequested">A restart request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_ShutdownRequested">A shutdown request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_StartRequested">A start request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_StopRequested">A stop request for server '{0}' has been sent.</sys:String>
|
||||
<sys:String x:Key="DiscordBot_UpdateRequested">An update request for server '{0}' has been sent.</sys:String>
|
||||
|
||||
<sys:String x:Key="DiscordBot_CountLabel">Count:</sys:String>
|
||||
<sys:String x:Key="DiscordBot_MapLabel">Map:</sys:String>
|
||||
<!--#endregion-->
|
||||
|
||||
</Globalization:GlobalizationResourceDictionary>
|
||||
|
|
@ -5,8 +5,30 @@ namespace ServerManagerTool.Lib
|
|||
{
|
||||
public class BranchSnapshot
|
||||
{
|
||||
private BranchSnapshot()
|
||||
{
|
||||
}
|
||||
|
||||
public string BranchName = string.Empty;
|
||||
public string BranchPassword = string.Empty;
|
||||
|
||||
public static BranchSnapshot Create(ServerProfile profile)
|
||||
{
|
||||
return new BranchSnapshot
|
||||
{
|
||||
BranchName = profile.BranchName,
|
||||
BranchPassword = profile.BranchPassword
|
||||
};
|
||||
}
|
||||
|
||||
public static BranchSnapshot Create(ServerProfileSnapshot profile)
|
||||
{
|
||||
return new BranchSnapshot
|
||||
{
|
||||
BranchName = profile.BranchName,
|
||||
BranchPassword = profile.BranchPassword
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class BranchSnapshotComparer : IEqualityComparer<BranchSnapshot>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using ServerManagerTool.Common;
|
|||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Delegates;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using ServerManagerTool.Utils;
|
||||
|
|
@ -108,6 +109,7 @@ namespace ServerManagerTool.Lib
|
|||
public int ShutdownInterval = Config.Default.ServerShutdown_GracePeriod;
|
||||
public ProgressDelegate ProgressCallback = null;
|
||||
public ProcessWindowStyle SteamCMDProcessWindowStyle = ProcessWindowStyle.Minimized;
|
||||
public ServerStatusChangeDelegate ServerStatusChangeCallback = null;
|
||||
|
||||
public ServerApp(bool resetStartTime = false)
|
||||
{
|
||||
|
|
@ -115,7 +117,7 @@ namespace ServerManagerTool.Lib
|
|||
_startTime = DateTime.Now;
|
||||
}
|
||||
|
||||
private void BackupServer()
|
||||
private void BackupServer(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_profile == null)
|
||||
{
|
||||
|
|
@ -144,58 +146,67 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
if (_serverRunning)
|
||||
{
|
||||
// check if RCON is enabled
|
||||
//if (_profile.RconEnabled)
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// emailMessage.AppendLine();
|
||||
try
|
||||
{
|
||||
emailMessage.AppendLine();
|
||||
|
||||
// // perform a world save
|
||||
// if (!string.IsNullOrWhiteSpace(Config.Default.ServerBackup_WorldSaveMessage))
|
||||
// {
|
||||
// ProcessAlert(AlertType.Backup, Config.Default.ServerBackup_WorldSaveMessage);
|
||||
// sent = SendMessage(Config.Default.ServerBackup_WorldSaveMessage, CancellationToken.None);
|
||||
// if (sent)
|
||||
// {
|
||||
// emailMessage.AppendLine("sent server save message.");
|
||||
// }
|
||||
// }
|
||||
var sent = false;
|
||||
|
||||
// sent = SendCommand(Config.Default.ServerSaveCommand, false);
|
||||
// if (sent)
|
||||
// {
|
||||
// emailMessage.AppendLine("sent server save command.");
|
||||
// Task.Delay(Config.Default.ServerShutdown_WorldSaveDelay * 1000).Wait();
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// CloseRconConsole();
|
||||
// perform a world save
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerBackup_WorldSaveMessage))
|
||||
{
|
||||
ProcessAlert(AlertType.Backup, Config.Default.ServerBackup_WorldSaveMessage);
|
||||
sent = SendMessageAsync(Config.Default.ServerBackup_WorldSaveMessage, CancellationToken.None).Result;
|
||||
if (sent)
|
||||
{
|
||||
emailMessage.AppendLine("sent server save message.");
|
||||
}
|
||||
}
|
||||
|
||||
// Debug.WriteLine($"RCON> {Config.Default.ServerSaveCommand} command.\r\n{ex.Message}");
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// LogProfileMessage("RCON not enabled.");
|
||||
//}
|
||||
sent = SendCommandAsync(Config.Default.ServerSaveCommand, false).Result;
|
||||
if (sent)
|
||||
{
|
||||
emailMessage.AppendLine("sent server save command.");
|
||||
Task.Delay(Config.Default.ServerShutdown_WorldSaveDelay * 1000).Wait();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CloseRconConsole();
|
||||
|
||||
Debug.WriteLine($"RCON> {Config.Default.ServerSaveCommand} command.\r\n{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
return;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
// make a backup of the current profile and config files.
|
||||
CreateProfileBackupArchiveFile();
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
return;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
// make a backup of the current world file.
|
||||
CreateServerBackupArchiveFile(emailMessage);
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
return;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Config.Default.EmailNotify_AutoBackup)
|
||||
{
|
||||
|
|
@ -261,7 +272,15 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
if (updateServer)
|
||||
{
|
||||
UpgradeLocal(true, steamCmdRemoveQuit, cancellationToken, true);
|
||||
try
|
||||
{
|
||||
ServerStatusChangeCallback?.Invoke(ServerStatus.Updating);
|
||||
UpgradeLocal(true, true, steamCmdRemoveQuit, cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ServerStatusChangeCallback?.Invoke(ServerStatus.Stopped);
|
||||
}
|
||||
}
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
|
|
@ -297,17 +316,20 @@ namespace ServerManagerTool.Lib
|
|||
return;
|
||||
}
|
||||
|
||||
// check if the server was previously running before the update.
|
||||
if (!_serverRunning && !_profile.AutoRestartIfShutdown)
|
||||
// check if the server was previously running.
|
||||
if (!_serverRunning)
|
||||
{
|
||||
LogProfileMessage("Server was not running, server will not be started.");
|
||||
if (_profile.AutoRestartIfShutdown)
|
||||
{
|
||||
LogProfileMessage("Server was not running, server will be started as the setting to restart if shutdown is TRUE.");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogProfileMessage("Server was not running, server will not be started.");
|
||||
|
||||
ExitCode = EXITCODE_NORMALEXIT;
|
||||
return;
|
||||
}
|
||||
if (!_serverRunning && _profile.AutoRestartIfShutdown)
|
||||
{
|
||||
LogProfileMessage("Server was not running, server will be started as the setting to restart if shutdown is TRUE.");
|
||||
ExitCode = EXITCODE_NORMALEXIT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the server process.
|
||||
|
|
@ -380,10 +402,15 @@ namespace ServerManagerTool.Lib
|
|||
_serverRunning = true;
|
||||
LogProfileMessage($"Server process found PID {process.Id}.");
|
||||
|
||||
QueryMaster.Server gameServer = null;
|
||||
bool sent = false;
|
||||
|
||||
try
|
||||
{
|
||||
// create a connection to the server
|
||||
var endPoint = new IPEndPoint(_profile.ServerIPAddress, _profile.QueryPort);
|
||||
gameServer = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endPoint);
|
||||
|
||||
// check if there is a shutdown reason
|
||||
if (!string.IsNullOrWhiteSpace(ShutdownReason) && !Config.Default.ServerShutdown_AllMessagesShowReason)
|
||||
{
|
||||
|
|
@ -394,10 +421,6 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
|
||||
LogProfileMessage("Starting shutdown timer...");
|
||||
if (!CheckForOnlinePlayers)
|
||||
{
|
||||
LogProfileMessage("CheckForOnlinePlayers disabled, shutdown timer will not perform online player check.");
|
||||
}
|
||||
|
||||
var minutesLeft = ShutdownInterval;
|
||||
while (minutesLeft > 0)
|
||||
|
|
@ -420,8 +443,11 @@ namespace ServerManagerTool.Lib
|
|||
{
|
||||
try
|
||||
{
|
||||
var gameFile = GetServerWorldFile();
|
||||
var playerCount = DataContainer.GetOnlinePlayerCount(gameFile);
|
||||
// BH - commented out until Funcom fix the Online player status column in the world save database
|
||||
//var gameFile = GetServerWorldFile();
|
||||
//var playerCount = DataContainer.GetOnlinePlayerCount(gameFile);
|
||||
var playerInfo = gameServer?.GetPlayers()?.Where(p => !string.IsNullOrWhiteSpace(p.Name?.Trim())).ToList();
|
||||
var playerCount = playerInfo?.Count ?? -1;
|
||||
|
||||
// check if anyone is logged into the server
|
||||
if (playerCount <= 0)
|
||||
|
|
@ -439,7 +465,8 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine($"CheckForOnlinePlayers disabled");
|
||||
Debug.WriteLine($"CheckForOnlinePlayers disabled, shutdown timer cancelled.");
|
||||
break;
|
||||
}
|
||||
|
||||
var message = string.Empty;
|
||||
|
|
@ -506,7 +533,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
// BH - commented out until funcom provide a way to send a save command
|
||||
// check if we need to perform a world save
|
||||
//if (_profile.RconEnabled && Config.Default.ServerShutdown_EnableWorldSave)
|
||||
//if (Config.Default.ServerShutdown_EnableWorldSave)
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
|
|
@ -515,10 +542,10 @@ namespace ServerManagerTool.Lib
|
|||
// {
|
||||
// LogProfileMessage(Config.Default.ServerShutdown_WorldSaveMessage);
|
||||
// ProcessAlert(AlertType.ShutdownMessage, Config.Default.ServerShutdown_WorldSaveMessage);
|
||||
// SendMessage(Config.Default.ServerShutdown_WorldSaveMessage, cancellationToken);
|
||||
// SendMessageAsync(Config.Default.ServerShutdown_WorldSaveMessage, cancellationToken).Wait(cancellationToken);
|
||||
// }
|
||||
|
||||
// if (SendCommand(Config.Default.ServerSaveCommand, false))
|
||||
// if (SendCommandAsync(Config.Default.ServerSaveCommand, false).Result)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
|
|
@ -566,7 +593,8 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
finally
|
||||
{
|
||||
CloseRconConsole();
|
||||
gameServer?.Dispose();
|
||||
gameServer = null;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
|
|
@ -579,8 +607,6 @@ namespace ServerManagerTool.Lib
|
|||
SendMessageAsync(Config.Default.ServerShutdown_CancelMessage, CancellationToken.None).Wait();
|
||||
}
|
||||
|
||||
CloseRconConsole();
|
||||
|
||||
ExitCode = EXITCODE_CANCELLED;
|
||||
return;
|
||||
}
|
||||
|
|
@ -654,7 +680,7 @@ namespace ServerManagerTool.Lib
|
|||
ExitCode = EXITCODE_SHUTDOWN_TIMEOUT;
|
||||
}
|
||||
|
||||
private void UpgradeLocal(bool validate, bool steamCmdRemoveQuit, CancellationToken cancellationToken, bool updateMods)
|
||||
private void UpgradeLocal(bool validate, bool updateMods, bool steamCmdRemoveQuit, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_profile == null)
|
||||
{
|
||||
|
|
@ -1172,7 +1198,7 @@ namespace ServerManagerTool.Lib
|
|||
{
|
||||
// perform a steamcmd validate to confirm all the files
|
||||
LogProfileMessage("Validating server files (*new*).");
|
||||
UpgradeLocal(true, false, CancellationToken.None, false);
|
||||
UpgradeLocal(true, false, false, CancellationToken.None);
|
||||
LogProfileMessage("Validated server files (*new*).");
|
||||
}
|
||||
|
||||
|
|
@ -1693,17 +1719,6 @@ namespace ServerManagerTool.Lib
|
|||
ExitCode = EXITCODE_NORMALEXIT;
|
||||
}
|
||||
|
||||
private void CloseRconConsole()
|
||||
{
|
||||
if (_rconConsole != null)
|
||||
{
|
||||
_rconConsole.Dispose();
|
||||
_rconConsole = null;
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateProfileBackupArchiveFile(ServerProfileSnapshot profile = null)
|
||||
{
|
||||
var oldProfile = _profile;
|
||||
|
|
@ -2403,36 +2418,43 @@ namespace ServerManagerTool.Lib
|
|||
int rconRetries = 0;
|
||||
int maxRetries = retryIfFailed ? RCON_MAXRETRIES : 1;
|
||||
|
||||
while (retries < maxRetries && rconRetries < RCON_MAXRETRIES)
|
||||
try
|
||||
{
|
||||
SetupRconConsole();
|
||||
|
||||
if (_rconConsole == null)
|
||||
while (retries < maxRetries && rconRetries < RCON_MAXRETRIES)
|
||||
{
|
||||
LogProfileMessage($"RCON> {command} - attempt {rconRetries + 1} (a).", false);
|
||||
LogProfileMessage("RCON connection could not be created.", false);
|
||||
rconRetries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rconRetries = 0;
|
||||
try
|
||||
{
|
||||
_rconConsole.SendCommand(command);
|
||||
LogProfileMessage($"RCON> {command}");
|
||||
SetupRconConsole();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
if (_rconConsole == null)
|
||||
{
|
||||
LogProfileMessage($"RCON> {command} - attempt {retries + 1} (b).", false);
|
||||
LogProfileMessage($"{ex.Message}", false);
|
||||
LogProfileMessage($"{ex.StackTrace}", false);
|
||||
LogProfileMessage($"RCON> {command} - attempt {rconRetries + 1} (a).", false);
|
||||
LogProfileMessage("RCON connection could not be created.", false);
|
||||
rconRetries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rconRetries = 0;
|
||||
try
|
||||
{
|
||||
_rconConsole.SendCommand(command);
|
||||
LogProfileMessage($"RCON> {command}");
|
||||
|
||||
retries++;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogProfileMessage($"RCON> {command} - attempt {retries + 1} (b).", false);
|
||||
LogProfileMessage($"{ex.Message}", false);
|
||||
LogProfileMessage($"{ex.StackTrace}", false);
|
||||
}
|
||||
|
||||
retries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseRconConsole();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2494,6 +2516,17 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
}
|
||||
|
||||
private void CloseRconConsole()
|
||||
{
|
||||
if (_rconConsole != null)
|
||||
{
|
||||
_rconConsole.Dispose();
|
||||
_rconConsole = null;
|
||||
|
||||
Task.Delay(1000).Wait();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupRconConsole()
|
||||
{
|
||||
CloseRconConsole();
|
||||
|
|
@ -2503,7 +2536,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
try
|
||||
{
|
||||
var endPoint = new IPEndPoint(IPAddress.Parse(_profile.ServerIP), _profile.RconPort);
|
||||
var endPoint = new IPEndPoint(_profile.ServerIPAddress, _profile.RconPort);
|
||||
var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endPoint, sendTimeOut: 10000, receiveTimeOut: 10000);
|
||||
if (server == null)
|
||||
{
|
||||
|
|
@ -2541,7 +2574,7 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
}
|
||||
|
||||
public int PerformProfileBackup(ServerProfileSnapshot profile)
|
||||
public int PerformProfileBackup(ServerProfileSnapshot profile, CancellationToken cancellationToken)
|
||||
{
|
||||
_profile = profile;
|
||||
|
||||
|
|
@ -2563,7 +2596,7 @@ namespace ServerManagerTool.Lib
|
|||
// check if the mutex was established
|
||||
if (createdNew)
|
||||
{
|
||||
BackupServer();
|
||||
BackupServer(cancellationToken);
|
||||
|
||||
if (ExitCode != EXITCODE_NORMALEXIT)
|
||||
{
|
||||
|
|
@ -2916,7 +2949,7 @@ namespace ServerManagerTool.Lib
|
|||
SendEmails = true,
|
||||
ServerProcess = ServerProcessType.AutoBackup
|
||||
};
|
||||
exitCodes.TryAdd(profile, app.PerformProfileBackup(profile));
|
||||
exitCodes.TryAdd(profile, app.PerformProfileBackup(profile, CancellationToken.None));
|
||||
});
|
||||
|
||||
foreach (var profile in _profiles.Keys)
|
||||
|
|
@ -3060,7 +3093,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
if (exitCode == EXITCODE_NORMALEXIT)
|
||||
{
|
||||
var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => new BranchSnapshot() { BranchName = p.BranchName, BranchPassword = p.BranchPassword }).Distinct(new BranchSnapshotComparer()).ToArray();
|
||||
var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => BranchSnapshot.Create(p)).Distinct(new BranchSnapshotComparer()).ToArray();
|
||||
var exitCodes = new ConcurrentDictionary<BranchSnapshot, int>();
|
||||
|
||||
// update the server cache for each branch
|
||||
|
|
|
|||
|
|
@ -567,6 +567,64 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
#endregion
|
||||
|
||||
#region Discord Bot
|
||||
public static readonly DependencyProperty DiscordChannelIdProperty = DependencyProperty.Register(nameof(DiscordChannelId), typeof(string), typeof(ServerProfile), new PropertyMetadata(String.Empty));
|
||||
[DataMember]
|
||||
public string DiscordChannelId
|
||||
{
|
||||
get { return (string)GetValue(DiscordChannelIdProperty); }
|
||||
set { SetValue(DiscordChannelIdProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordBackupProperty = DependencyProperty.Register(nameof(AllowDiscordBackup), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordBackup
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordBackupProperty); }
|
||||
set { SetValue(AllowDiscordBackupProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordRestartProperty = DependencyProperty.Register(nameof(AllowDiscordRestart), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordRestart
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordRestartProperty); }
|
||||
set { SetValue(AllowDiscordRestartProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordShutdownProperty = DependencyProperty.Register(nameof(AllowDiscordShutdown), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordShutdown
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordShutdownProperty); }
|
||||
set { SetValue(AllowDiscordShutdownProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordStartProperty = DependencyProperty.Register(nameof(AllowDiscordStart), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordStart
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordStartProperty); }
|
||||
set { SetValue(AllowDiscordStartProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordStopProperty = DependencyProperty.Register(nameof(AllowDiscordStop), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordStop
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordStopProperty); }
|
||||
set { SetValue(AllowDiscordStopProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllowDiscordUpdateProperty = DependencyProperty.Register(nameof(AllowDiscordUpdate), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
|
||||
[DataMember]
|
||||
public bool AllowDiscordUpdate
|
||||
{
|
||||
get { return (bool)GetValue(AllowDiscordUpdateProperty); }
|
||||
set { SetValue(AllowDiscordUpdateProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Server Files
|
||||
public static readonly DependencyProperty ServerFilesBlacklistedProperty = DependencyProperty.Register(nameof(ServerFilesBlacklisted), typeof(PlayerUserList), typeof(ServerProfile), new PropertyMetadata(null));
|
||||
[DataMember]
|
||||
|
|
|
|||
|
|
@ -7,13 +7,17 @@ namespace ServerManagerTool.Lib
|
|||
{
|
||||
public class ServerProfileSnapshot
|
||||
{
|
||||
private ServerProfileSnapshot()
|
||||
{
|
||||
}
|
||||
|
||||
public string ProfileId;
|
||||
public string ProfileName;
|
||||
public string ServerName;
|
||||
public string InstallDirectory;
|
||||
public string GameFile;
|
||||
public string AdminPassword;
|
||||
public string ServerIP;
|
||||
public IPAddress ServerIPAddress;
|
||||
public int ServerPort;
|
||||
public int ServerPeerPort;
|
||||
public int QueryPort;
|
||||
|
|
@ -56,7 +60,7 @@ namespace ServerManagerTool.Lib
|
|||
InstallDirectory = profile.InstallDirectory,
|
||||
GameFile = profile.GetServerWorldFile(),
|
||||
AdminPassword = profile.AdminPassword,
|
||||
ServerIP = string.IsNullOrWhiteSpace(profile.ServerIP) ? IPAddress.Loopback.ToString() : profile.ServerIP.Trim(),
|
||||
ServerIPAddress = string.IsNullOrWhiteSpace(profile.ServerIP) || !IPAddress.TryParse(profile.ServerIP.Trim(), out IPAddress ipAddress) ? IPAddress.Loopback : ipAddress,
|
||||
ServerPort = profile.ServerPort,
|
||||
ServerPeerPort = profile.ServerPeerPort,
|
||||
QueryPort = profile.QueryPort,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace ServerManagerTool.Lib
|
|||
public event EventHandler StatusUpdate;
|
||||
|
||||
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private static readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private readonly List<PropertyChangeNotifier> profileNotifiers = new List<PropertyChangeNotifier>();
|
||||
private Process serverProcess;
|
||||
private IAsyncDisposable updateRegistration;
|
||||
|
|
@ -167,13 +167,19 @@ namespace ServerManagerTool.Lib
|
|||
ServerProfile.QueryPortProperty,
|
||||
ServerProfile.ServerIPProperty,
|
||||
ServerProfile.MaxPlayersProperty,
|
||||
|
||||
ServerProfile.ServerPasswordProperty,
|
||||
ServerProfile.AdminPasswordProperty,
|
||||
|
||||
ServerProfile.ServerMapProperty,
|
||||
ServerProfile.ServerMapSaveFileNameProperty,
|
||||
ServerProfile.ServerModIdsProperty,
|
||||
|
||||
ServerProfile.MOTDIntervalProperty,
|
||||
},
|
||||
(s, p) =>
|
||||
{
|
||||
if (Status == ServerStatus.Stopped || Status == ServerStatus.Uninstalled || Status == ServerStatus.Unknown)
|
||||
if (Status == ServerStatus.Stopped || Status == ServerStatus.Uninstalled || Status == ServerStatus.Unknown || Status == ServerStatus.Updating)
|
||||
{
|
||||
AttachToProfileCore(profile);
|
||||
}
|
||||
|
|
@ -194,16 +200,7 @@ namespace ServerManagerTool.Lib
|
|||
return;
|
||||
}
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(this.ProfileSnapshot.ServerIP) && IPAddress.TryParse(this.ProfileSnapshot.ServerIP, out IPAddress localServerIpAddress))
|
||||
{
|
||||
// Use the explicit Server IP
|
||||
localServerQueryEndPoint = new IPEndPoint(localServerIpAddress, Convert.ToUInt16(this.ProfileSnapshot.QueryPort));
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Server IP specified, use Loopback
|
||||
localServerQueryEndPoint = new IPEndPoint(IPAddress.Loopback, Convert.ToUInt16(this.ProfileSnapshot.QueryPort));
|
||||
}
|
||||
localServerQueryEndPoint = new IPEndPoint(this.ProfileSnapshot.ServerIPAddress, Convert.ToUInt16(this.ProfileSnapshot.QueryPort));
|
||||
|
||||
//
|
||||
// Get the public endpoint for querying Steam
|
||||
|
|
@ -277,13 +274,13 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
case WatcherServerStatus.RunningLocalCheck:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
UpdateServerStatus(ServerStatus.Running, this.Availability != AvailabilityStatus.Available ? AvailabilityStatus.WaitingForPublication : this.Availability, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
UpdateServerStatus(ServerStatus.Running, this.Availability != AvailabilityStatus.Available ? AvailabilityStatus.Waiting : this.Availability, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.RunningExternalCheck:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.WaitingForPublication, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.Waiting, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
break;
|
||||
|
||||
|
|
@ -442,7 +439,7 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
}
|
||||
|
||||
UpdateServerStatus(ServerStatus.Initializing, this.Availability, false);
|
||||
UpdateServerStatus(ServerStatus.Initializing, false);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -516,7 +513,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
bool isNewInstallation = this.Status == ServerStatus.Uninstalled;
|
||||
|
||||
UpdateServerStatus(ServerStatus.Updating, Availability, false);
|
||||
UpdateServerStatus(ServerStatus.Updating, false);
|
||||
|
||||
// Run the SteamCMD to install the server
|
||||
var steamCmdFile = SteamCmdUpdater.GetSteamCmdFile(Config.Default.DataPath);
|
||||
|
|
@ -938,7 +935,7 @@ namespace ServerManagerTool.Lib
|
|||
finally
|
||||
{
|
||||
this.lastModStatusQuery = DateTime.MinValue;
|
||||
UpdateServerStatus(ServerStatus.Stopped, Availability, false);
|
||||
UpdateServerStatus(ServerStatus.Stopped, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -961,6 +958,11 @@ namespace ServerManagerTool.Lib
|
|||
this.lastModStatusQuery = DateTime.MinValue;
|
||||
}
|
||||
|
||||
public void UpdateServerStatus(ServerStatus serverStatus, bool sendAlert)
|
||||
{
|
||||
UpdateServerStatus(serverStatus, Availability, sendAlert);
|
||||
}
|
||||
|
||||
public void UpdateServerStatus(ServerStatus serverStatus, AvailabilityStatus availabilityStatus, bool sendAlert)
|
||||
{
|
||||
this.Status = serverStatus;
|
||||
|
|
@ -974,32 +976,29 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
public void UpdateServerStatusString()
|
||||
{
|
||||
switch (Status)
|
||||
StatusString = GetServerStatusString(Status);
|
||||
}
|
||||
|
||||
public static string GetServerStatusString(ServerStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusInitializingLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusInitializingLabel");
|
||||
case ServerStatus.Running:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusRunningLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusRunningLabel");
|
||||
case ServerStatus.Stopped:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppedLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppedLabel");
|
||||
case ServerStatus.Stopping:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppingLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppingLabel");
|
||||
case ServerStatus.Uninstalled:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUninstalledLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUninstalledLabel");
|
||||
case ServerStatus.Unknown:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
|
||||
case ServerStatus.Updating:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUpdatingLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUpdatingLabel");
|
||||
default:
|
||||
StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
|
||||
break;
|
||||
return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1059,7 +1058,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
try
|
||||
{
|
||||
var endPoint = new IPEndPoint(IPAddress.Parse(this.ProfileSnapshot.ServerIP), this.ProfileSnapshot.RconPort);
|
||||
var endPoint = new IPEndPoint(this.ProfileSnapshot.ServerIPAddress, this.ProfileSnapshot.RconPort);
|
||||
var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endPoint, sendTimeOut: 10000, receiveTimeOut: 10000);
|
||||
|
||||
if (server == null)
|
||||
|
|
|
|||
|
|
@ -671,5 +671,15 @@
|
|||
<Label Content="{DynamicResource GlobalSettings_CacheDirectoryButtonLabel}" VerticalAlignment="Center" Margin="0,-3,0,-3"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="DiscordBotApplyButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_DiscordBotApplyButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
<ContentControl x:Key="DiscordBotHelpButtonContent">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Label Content="{DynamicResource GlobalSettings_DiscordBotHelpButtonLabel}" VerticalAlignment="Center" Margin="0,-2,0,-2"/>
|
||||
</StackPanel>
|
||||
</ContentControl>
|
||||
|
||||
</Globalization:StyleResourceDictionary>
|
||||
735
src/ConanServerManager/Utils/DiscordBotHelper.cs
Normal file
735
src/ConanServerManager/Utils/DiscordBotHelper.cs
Normal file
|
|
@ -0,0 +1,735 @@
|
|||
using QueryMaster;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.DiscordBot.Enums;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool.Utils
|
||||
{
|
||||
internal static class DiscordBotHelper
|
||||
{
|
||||
private static readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
private static bool _runningCommand = false;
|
||||
|
||||
private static readonly Dictionary<string, CommandType> _currentProfileCommands = new Dictionary<string, CommandType>();
|
||||
|
||||
public static bool HasRunningCommands => _currentProfileCommands.Count > 0;
|
||||
|
||||
public static IList<string> HandleDiscordCommand(CommandType commandType, string serverId, string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
// check if incoming values are valid
|
||||
if (string.IsNullOrWhiteSpace(serverId) || string.IsNullOrWhiteSpace(channelId))
|
||||
return null;
|
||||
|
||||
// check if the server ids match
|
||||
if (!serverId.Equals(Config.Default.DiscordBotServerId))
|
||||
return new List<string>();
|
||||
|
||||
if (_runningCommand)
|
||||
return new List<string> { _globalizer.GetResourceString("DiscordBot_CommandRunning") };
|
||||
_runningCommand = true;
|
||||
|
||||
try
|
||||
{
|
||||
switch (commandType)
|
||||
{
|
||||
case CommandType.Info:
|
||||
return GetServerInfo(channelId, profileId);
|
||||
case CommandType.List:
|
||||
return GetServerList(channelId);
|
||||
case CommandType.Status:
|
||||
return GetServerStatus(channelId, profileId);
|
||||
|
||||
case CommandType.Backup:
|
||||
if (Config.Default.AllowDiscordBackup)
|
||||
return BackupServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Restart:
|
||||
if (Config.Default.AllowDiscordRestart)
|
||||
return RestartServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Shutdown:
|
||||
if (Config.Default.AllowDiscordShutdown)
|
||||
return ShutdownServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Stop:
|
||||
if (Config.Default.AllowDiscordStop)
|
||||
return StopServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Start:
|
||||
if (Config.Default.AllowDiscordStart)
|
||||
return StartServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
case CommandType.Update:
|
||||
if (Config.Default.AllowDiscordUpdate)
|
||||
return UpdateServer(channelId, profileId, token);
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
|
||||
|
||||
default:
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandUnknown"), commandType) };
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = ex.InnerException is null ? ex.Message : ex.InnerException.Message;
|
||||
return new string[] { message };
|
||||
}
|
||||
finally
|
||||
{
|
||||
_runningCommand = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string HandleTranslation(string translationKey)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(translationKey) ? string.Empty : _globalizer.GetResourceString(translationKey) ?? translationKey;
|
||||
}
|
||||
|
||||
private static IList<string> GetServerInfo(string channelId, string profileId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Info) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Info);
|
||||
|
||||
try
|
||||
{
|
||||
var serverName = string.Empty;
|
||||
var serverIp = IPAddress.Loopback;
|
||||
var queryPort = 0;
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Stopped:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
}
|
||||
|
||||
serverName = server.Profile.ServerName;
|
||||
if (!string.IsNullOrWhiteSpace(server.Profile.ServerIP))
|
||||
{
|
||||
IPAddress.TryParse(server.Profile.ServerIP, out serverIp);
|
||||
}
|
||||
queryPort = server.Profile.QueryPort;
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
using (var gameServer = ServerQuery.GetServerInstance(EngineType.Source, new IPEndPoint(serverIp, queryPort)))
|
||||
{
|
||||
var info = gameServer?.GetInfo();
|
||||
if (info is null)
|
||||
{
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_InfoFailed"), serverName));
|
||||
}
|
||||
else
|
||||
{
|
||||
var mapName = _globalizer.GetResourceString($"Map_{info.Map}") ?? info.Map;
|
||||
response.Add($"```{info.Name}\n{_globalizer.GetResourceString("DiscordBot_MapLabel")} {mapName}\n{_globalizer.GetResourceString("ServerSettings_PlayersLabel")} {info.Players} / {info.MaxPlayers}```");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_InfoFailed"), serverName));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> GetServerList(string channelId)
|
||||
{
|
||||
List<string> response = new List<string>();
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var serverList = ServerManager.Instance.Servers.Where(s => Equals(channelId, s.Profile.DiscordChannelId));
|
||||
|
||||
response.Add($"**{_globalizer.GetResourceString("DiscordBot_CountLabel")}** {serverList.Count()}");
|
||||
foreach (var server in serverList)
|
||||
{
|
||||
response.Add($"```{_globalizer.GetResourceString("ServerSettings_ProfileIdLabel")} {server.Profile.ProfileID}\n{_globalizer.GetResourceString("ServerSettings_ProfileLabel")} {server.Profile.ProfileName}\n{_globalizer.GetResourceString("ServerSettings_ServerNameLabel")} {server.Profile.ServerName}```");
|
||||
}
|
||||
}).Wait();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private static IList<string> GetServerStatus(string channelId, string profileId)
|
||||
{
|
||||
List<string> response = new List<string>();
|
||||
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var serverList = ServerManager.Instance.Servers.Where(s => Equals(channelId, s.Profile.DiscordChannelId) && (string.IsNullOrWhiteSpace(profileId) || Equals(profileId, s.Profile.ProfileID)));
|
||||
|
||||
response.Add($"**{_globalizer.GetResourceString("DiscordBot_CountLabel")}** {serverList.Count()}");
|
||||
foreach (var server in serverList)
|
||||
{
|
||||
response.Add($"```{_globalizer.GetResourceString("ServerSettings_ProfileLabel")} {server.Profile.ProfileName}\n{_globalizer.GetResourceString("ServerSettings_ServerNameLabel")} {server.Profile.ServerName}\n{_globalizer.GetResourceString("ServerSettings_StatusLabel")} {server.Runtime.StatusString}\n{_globalizer.GetResourceString("ServerSettings_AvailabilityLabel")} {_globalizer.GetResourceString($"ServerSettings_Availability_{server.Runtime.Availability}")}```");
|
||||
}
|
||||
}).Wait();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private static IList<string> BackupServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Backup) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Backup);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordBackup)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Backup, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileBackup(profile, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_BackupRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> RestartServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Restart) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Restart);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordRestart)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Restart, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
profile.AutoRestartIfShutdown = true;
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, true, false, false, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_RestartRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> ShutdownServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Shutdown) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Shutdown);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordShutdown)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Shutdown, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Stopped:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, false, false, false, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_ShutdownRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> StopServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Stop) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Stop);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordStop)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Stop, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Stopped:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !Config.Default.AutoBackup_EnableBackup,
|
||||
OutputLogs = false,
|
||||
SendAlerts = true,
|
||||
SendEmails = false,
|
||||
ServerProcess = ServerProcessType.Shutdown,
|
||||
ShutdownInterval = 0,
|
||||
ServerStatusChangeCallback = (ServerStatus serverStatus) =>
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, false, false, false, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_StopRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> StartServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Start) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Start);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordStart)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Start, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Running:
|
||||
case ServerStatus.Uninstalled:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
profile.AutoRestartIfShutdown = true;
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, true, false, false, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_StartRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IList<string> UpdateServer(string channelId, string profileId, CancellationToken token)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Update) };
|
||||
}
|
||||
|
||||
// check if another command is being run against the profile
|
||||
if (_currentProfileCommands.ContainsKey(profileId))
|
||||
{
|
||||
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
|
||||
}
|
||||
_currentProfileCommands.Add(profileId, CommandType.Update);
|
||||
|
||||
ServerProfileSnapshot profile = null;
|
||||
bool performRestart = false;
|
||||
Task task = null;
|
||||
|
||||
try
|
||||
{
|
||||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
|
||||
}
|
||||
|
||||
if (!server.Profile.AllowDiscordUpdate)
|
||||
{
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Update, profileId));
|
||||
}
|
||||
|
||||
switch (server.Runtime.Status)
|
||||
{
|
||||
case ServerStatus.Initializing:
|
||||
case ServerStatus.Stopping:
|
||||
case ServerStatus.Unknown:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
|
||||
|
||||
case ServerStatus.Running:
|
||||
performRestart = true;
|
||||
break;
|
||||
|
||||
case ServerStatus.Updating:
|
||||
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
|
||||
}
|
||||
|
||||
profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
}).Wait();
|
||||
|
||||
List<string> response = new List<string>();
|
||||
|
||||
var app = new ServerApp(true)
|
||||
{
|
||||
DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
|
||||
server.Runtime.UpdateServerStatus(serverStatus, true);
|
||||
}).Wait();
|
||||
}
|
||||
};
|
||||
|
||||
task = Task.Run(() =>
|
||||
{
|
||||
app.PerformProfileShutdown(profile, performRestart, true, false, false, token);
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
});
|
||||
|
||||
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_UpdateRequested"), profile.ServerName));
|
||||
|
||||
return response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (task is null)
|
||||
{
|
||||
_currentProfileCommands.Remove(profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/ConanServerManager/Utils/DiscordPluginHelper.cs
Normal file
18
src/ConanServerManager/Utils/DiscordPluginHelper.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using ServerManagerTool.Lib;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ServerManagerTool.Utils
|
||||
{
|
||||
internal static class DiscordPluginHelper
|
||||
{
|
||||
public static IList<Plugin.Common.Lib.Profile> FetchProfiles()
|
||||
{
|
||||
return ServerManager.Instance.Servers.Select(s => new ServerManagerTool.Plugin.Common.Lib.Profile()
|
||||
{
|
||||
ProfileName = s?.Profile?.ProfileName ?? string.Empty,
|
||||
InstallationFolder = s?.Profile?.InstallDirectory ?? string.Empty
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -527,6 +527,55 @@
|
|||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="19" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<CheckBox IsChecked="{Binding Config.DiscordBotEnabled}" Content="{DynamicResource GlobalSettings_DiscordBotLabel}" VerticalAlignment="Center"/>
|
||||
</GroupBox.Header>
|
||||
|
||||
<Grid IsEnabled="{Binding Config.DiscordBotEnabled}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="60"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="60"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="60"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="8" Margin="5" Text="{DynamicResource GlobalSettings_DiscordBotInformationLabel}" TextWrapping="Wrap" VerticalAlignment="Center" FontWeight="Bold" Foreground="{DynamicResource WarningMessage}"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource GlobalSettings_DiscordBotTokenLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="6" Margin="1" Name="HideDiscordBotTokenTextBox" Text="{DynamicResource ServerSettings_HidePasswordText}" ToolTip="{DynamicResource ServerSettings_HidePasswordTooltip}" GotFocus="HiddenField_GotFocus" Style="{StaticResource HiddenTextBoxStyle}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="6" Margin="1" Name="DiscordBotTokenTextBox" Text="{Binding Config.DiscordBotToken}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_DiscordBotTokenTooltip}" LostFocus="HiddenField_LostFocus" Visibility="Collapsed"/>
|
||||
<StackPanel Grid.Row="1" Grid.Column="7" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Margin="1" Content="{DynamicResource DiscordBotApplyButtonContent}" Click="DiscordBotApply_Click"/>
|
||||
<Button Margin="1" Content="{DynamicResource DiscordBotHelpButtonContent}" Click="DiscordBotHelp_Click"/>
|
||||
</StackPanel>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource GlobalSettings_DiscordBotServerLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Text="{Binding Config.DiscordBotServerId}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_DiscordBotServerTooltip}"/>
|
||||
<Label Grid.Row="2" Grid.Column="3" Content="{DynamicResource GlobalSettings_DiscordBotPrefixLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="4" Margin="1" Text="{Binding Config.DiscordBotPrefix}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_DiscordBotPrefixTooltip}"/>
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="1" Margin="0,5,0,0" IsChecked="{Binding Config.AllowDiscordBackup}" Content="{DynamicResource ServerSettings_AllowDiscordBackupLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowBackupTooltip}"/>
|
||||
<CheckBox Grid.Row="3" Grid.Column="4" Margin="0,5,0,0" IsChecked="{Binding Config.AllowDiscordUpdate}" Content="{DynamicResource ServerSettings_AllowDiscordUpdateLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowUpdateTooltip}"/>
|
||||
<CheckBox Grid.Row="3" Grid.Column="7" Margin="0,5,0,0" IsChecked="{Binding Config.AllowDiscordStart}" Content="{DynamicResource ServerSettings_AllowDiscordStartLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowStartTooltip}"/>
|
||||
|
||||
<CheckBox Grid.Row="4" Grid.Column="1" Margin="0,5,0,5" IsChecked="{Binding Config.AllowDiscordRestart}" Content="{DynamicResource ServerSettings_AllowDiscordRestartLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowRestartTooltip}"/>
|
||||
<CheckBox Grid.Row="4" Grid.Column="4" Margin="0,5,0,5" IsChecked="{Binding Config.AllowDiscordShutdown}" Content="{DynamicResource ServerSettings_AllowDiscordShutdownLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowShutdownTooltip}"/>
|
||||
<CheckBox Grid.Row="4" Grid.Column="7" Margin="0,5,0,5" IsChecked="{Binding Config.AllowDiscordStop}" Content="{DynamicResource ServerSettings_AllowDiscordStopLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource GlobalSettings_DiscordBotAllowStopTooltip}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="20" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_EmailSettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
|
@ -538,13 +587,13 @@
|
|||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="60"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="60"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="60"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
|
@ -569,7 +618,7 @@
|
|||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="20" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox Grid.Row="21" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_EmailNotifySettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
|
@ -593,7 +642,7 @@
|
|||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="21" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox Grid.Row="22" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}">
|
||||
<GroupBox.Header>
|
||||
<Label Content="{DynamicResource GlobalSettings_AdvancedSettingsLabel}"/>
|
||||
</GroupBox.Header>
|
||||
|
|
|
|||
|
|
@ -257,6 +257,16 @@ namespace ServerManagerTool
|
|||
Process.Start(Config.Default.SteamWebAPIKeyHelpUrl);
|
||||
}
|
||||
|
||||
private void DiscordBotApply_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start(Config.Default.DiscordBotApplyUrl);
|
||||
}
|
||||
|
||||
private void DiscordBotHelp_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start(Config.Default.DiscordBotHelpUrl);
|
||||
}
|
||||
|
||||
private async void SteamCMDAuthenticate_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cursor = this.Cursor;
|
||||
|
|
@ -335,6 +345,8 @@ namespace ServerManagerTool
|
|||
textBox = SteamAPIKeyTextBox;
|
||||
if (Equals(hideTextBox, HideEmailPasswordTextBox))
|
||||
textBox = EmailPasswordTextBox;
|
||||
if (Equals(hideTextBox, HideDiscordBotTokenTextBox))
|
||||
textBox = DiscordBotTokenTextBox;
|
||||
|
||||
if (textBox != null)
|
||||
{
|
||||
|
|
@ -358,6 +370,8 @@ namespace ServerManagerTool
|
|||
hideTextBox = HideSteamAPIKeyTextBox;
|
||||
if (textBox == EmailPasswordTextBox)
|
||||
hideTextBox = HideEmailPasswordTextBox;
|
||||
if (textBox == DiscordBotTokenTextBox)
|
||||
hideTextBox = HideDiscordBotTokenTextBox;
|
||||
|
||||
if (hideTextBox != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
|
||||
xmlns:enum="clr-namespace:ServerManagerTool.Enums"
|
||||
MinWidth="900" MinHeight="600" Width="1100" Height="900" Left="50" Top="50" WindowState="Normal"
|
||||
Loaded="Window_Loaded" SizeChanged="Window_SizeChanged" StateChanged="Window_StateChanged" LocationChanged="Window_LocationChanged"
|
||||
Loaded="MainWindow_Loaded" SizeChanged="MainWindow_SizeChanged" StateChanged="MainWindow_StateChanged" LocationChanged="MainWindow_LocationChanged"
|
||||
Name="Main" Icon="../Art/favicon.ico" Title="{DynamicResource MainWindow_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using ServerManagerTool.Common.Utils;
|
|||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using ServerManagerTool.Utils;
|
||||
using ServerManagerTool.Windows;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
|
@ -162,7 +163,7 @@ namespace ServerManagerTool
|
|||
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//
|
||||
// Kick off the initialization.
|
||||
|
|
@ -192,15 +193,7 @@ namespace ServerManagerTool
|
|||
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
|
||||
}
|
||||
|
||||
private void Window_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is Window window)
|
||||
window.Closed -= Window_Closed;
|
||||
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
private void Window_LocationChanged(object sender, EventArgs e)
|
||||
private void MainWindow_LocationChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (this.WindowState == WindowState.Normal)
|
||||
{
|
||||
|
|
@ -209,7 +202,7 @@ namespace ServerManagerTool
|
|||
}
|
||||
}
|
||||
|
||||
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (this.WindowState == WindowState.Normal)
|
||||
{
|
||||
|
|
@ -218,7 +211,7 @@ namespace ServerManagerTool
|
|||
}
|
||||
}
|
||||
|
||||
private void Window_StateChanged(object sender, EventArgs e)
|
||||
private void MainWindow_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Config.Default.MainWindow_MinimizeToTray && this.WindowState == WindowState.Minimized)
|
||||
{
|
||||
|
|
@ -226,8 +219,26 @@ namespace ServerManagerTool
|
|||
}
|
||||
}
|
||||
|
||||
private void Window_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is Window window)
|
||||
window.Closed -= Window_Closed;
|
||||
|
||||
this.Activate();
|
||||
}
|
||||
|
||||
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
if (DiscordBotHelper.HasRunningCommands)
|
||||
{
|
||||
var result = MessageBox.Show(_globalizer.GetResourceString("MainWindow_DiscordBot_RunningCommandsLabel"), _globalizer.GetResourceString("MainWindow_DiscordBot_RunningCommandsTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.No)
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
base.OnClosing(e);
|
||||
RconWindow.CloseAllWindows();
|
||||
PlayerListWindow.CloseAllWindows();
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@ namespace ServerManagerTool
|
|||
ProfileId = server.Runtime.ProfileSnapshot.ProfileId,
|
||||
ProfileName = server.Runtime.ProfileSnapshot.ProfileName,
|
||||
MaxPlayers = server.Runtime.MaxPlayers,
|
||||
RconHost = server.Runtime.ProfileSnapshot.ServerIP,
|
||||
RconHost = server.Runtime.ProfileSnapshot.ServerIPAddress.ToString(),
|
||||
RconPort = server.Runtime.ProfileSnapshot.RconPort,
|
||||
RconPassword = server.Runtime.ProfileSnapshot.RconPassword,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ namespace ServerManagerTool.Windows
|
|||
|
||||
var profile = ServerProfileSnapshot.Create(server.Profile);
|
||||
|
||||
var exitCode = await Task.Run(() => app.PerformProfileBackup(profile));
|
||||
var exitCode = await Task.Run(() => app.PerformProfileBackup(profile, CancellationToken.None));
|
||||
if (exitCode != ServerApp.EXITCODE_NORMALEXIT && exitCode != ServerApp.EXITCODE_CANCELLED)
|
||||
{
|
||||
throw new ApplicationException($"An error occured during the backup process - ExitCode: {exitCode}");
|
||||
|
|
@ -620,7 +620,7 @@ namespace ServerManagerTool.Windows
|
|||
|
||||
await Task.Delay(1000);
|
||||
|
||||
var branch = new BranchSnapshot() { BranchName = serverProfile.BranchName, BranchPassword = serverProfile.BranchPassword };
|
||||
var branch = BranchSnapshot.Create(serverProfile);
|
||||
return await server.UpgradeAsync(_upgradeCancellationSource.Token, updateServer, branch, true, updateMods, (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { window?.AddMessage(m, n); }).DoNotWait(); });
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -282,13 +282,13 @@
|
|||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.Unknown}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Unknown}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.NeedPublicIP}">
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.SetPublicIP}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_SetPublicIP}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.Unavailable}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Unavailable}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.WaitingForPublication}">
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.Waiting}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Waiting}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static enum:AvailabilityStatus.Available}">
|
||||
|
|
@ -1062,6 +1062,47 @@
|
|||
</StackPanel>
|
||||
</Expander>
|
||||
|
||||
<Expander Name="SectionDiscordBot" IsExpanded="{Binding Config.SectionDiscordBotIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding Config.DiscordBotEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<Expander.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{DynamicResource ServerSettings_DiscordBotLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Expander.Header>
|
||||
|
||||
<Expander.Style>
|
||||
<Style BasedOn="{StaticResource ExpanderStyle1}" TargetType="{x:Type Expander}">
|
||||
<Setter Property="Template" Value="{StaticResource ExpanderTemplateSE}"/>
|
||||
</Style>
|
||||
</Expander.Style>
|
||||
|
||||
<Grid Margin="-8,0,2,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto" MinWidth="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource ServerSettings_DiscordBotChannelLabel}" ToolTip="{DynamicResource ServerSettings_DiscordBotChannelTooltip}" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Text="{Binding DiscordChannelId, Mode=TwoWay}" ToolTip="{DynamicResource ServerSettings_DiscordBotChannelTooltip}" VerticalContentAlignment="Center" />
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5,0" IsChecked="{Binding AllowDiscordBackup, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordBackupLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordBackupTooltip}"/>
|
||||
<CheckBox Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Margin="5,5,5,0" IsChecked="{Binding AllowDiscordUpdate, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordUpdateLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordUpdateTooltip}"/>
|
||||
<CheckBox Grid.Row="1" Grid.Column="4" Grid.ColumnSpan="2" Margin="5,5,5,0" IsChecked="{Binding AllowDiscordStart, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordStartLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordStartTooltip}"/>
|
||||
|
||||
<CheckBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" IsChecked="{Binding AllowDiscordRestart, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordRestartLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordRestartTooltip}"/>
|
||||
<CheckBox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" Margin="5" IsChecked="{Binding AllowDiscordShutdown, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordShutdownLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordShutdownTooltip}"/>
|
||||
<CheckBox Grid.Row="2" Grid.Column="4" Grid.ColumnSpan="2" Margin="5" IsChecked="{Binding AllowDiscordStop, Mode=TwoWay}" Content="{DynamicResource ServerSettings_AllowDiscordStopLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_AllowDiscordStopTooltip}"/>
|
||||
</Grid>
|
||||
</Expander>
|
||||
|
||||
<Expander Name="SectionServerFiles" IsExpanded="{Binding Config.SectionServerFilesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
|
||||
<Expander.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
|
|
|||
|
|
@ -834,7 +834,7 @@ namespace ServerManagerTool
|
|||
|
||||
var profile = ServerProfileSnapshot.Create(Server.Profile);
|
||||
|
||||
var exitCode = await Task.Run(() => app.PerformProfileBackup(profile));
|
||||
var exitCode = await Task.Run(() => app.PerformProfileBackup(profile, CancellationToken.None));
|
||||
if (exitCode != ServerApp.EXITCODE_NORMALEXIT && exitCode != ServerApp.EXITCODE_CANCELLED)
|
||||
throw new ApplicationException($"An error occured during the backup process - ExitCode: {exitCode}");
|
||||
|
||||
|
|
@ -1449,7 +1449,7 @@ namespace ServerManagerTool
|
|||
|
||||
await Task.Delay(1000);
|
||||
|
||||
var branch = new BranchSnapshot() { BranchName = this.Server.Profile.BranchName, BranchPassword = this.Server.Profile.BranchPassword };
|
||||
var branch = BranchSnapshot.Create(this.Server.Profile);
|
||||
return await this.Server.UpgradeAsync(_upgradeCancellationSource.Token, updateServer, branch, true, updateMods, (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { window?.AddMessage(m, n); }).DoNotWait(); });
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
using ServerManagerTool.DiscordBot.Enums;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot.Delegates
|
||||
{
|
||||
public delegate IList<string> HandleCommandDelegate(CommandType commandType, string serverId, string channelId, string profileId, CancellationToken token);
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
namespace ServerManagerTool.DiscordBot.Delegates
|
||||
{
|
||||
public delegate string HandleTranslationDelegate(string translationKey);
|
||||
}
|
||||
9
src/ServerManager.Discord/DiscordBot.cs
Normal file
9
src/ServerManager.Discord/DiscordBot.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using ServerManagerTool.DiscordBot.Delegates;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot
|
||||
{
|
||||
public static class DiscordBot
|
||||
{
|
||||
public const string PREFIX_DELIMITER = "!";
|
||||
}
|
||||
}
|
||||
16
src/ServerManager.Discord/Enums/CommandType.cs
Normal file
16
src/ServerManager.Discord/Enums/CommandType.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
namespace ServerManagerTool.DiscordBot.Enums
|
||||
{
|
||||
public enum CommandType
|
||||
{
|
||||
Info,
|
||||
List,
|
||||
Status,
|
||||
|
||||
Backup,
|
||||
Restart,
|
||||
Shutdown,
|
||||
Start,
|
||||
Stop,
|
||||
Update,
|
||||
}
|
||||
}
|
||||
13
src/ServerManager.Discord/Interfaces/IServerManagerBot.cs
Normal file
13
src/ServerManager.Discord/Interfaces/IServerManagerBot.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using ServerManagerTool.DiscordBot.Delegates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot.Interfaces
|
||||
{
|
||||
public interface IServerManagerBot
|
||||
{
|
||||
CancellationToken Token { get; }
|
||||
|
||||
Task StartAsync(string discordToken, string commandPrefix, string dataDirectory, HandleCommandDelegate handleCommandCallback, HandleTranslationDelegate handleTranslationCallback, CancellationToken token);
|
||||
}
|
||||
}
|
||||
153
src/ServerManager.Discord/Modules/HelpModule.cs
Normal file
153
src/ServerManager.Discord/Modules/HelpModule.cs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot.Modules
|
||||
{
|
||||
[Name("Help")]
|
||||
public sealed class HelpModule : ModuleBase<SocketCommandContext>
|
||||
{
|
||||
private const int MAX_VALUE_LENGTH = 1024;
|
||||
|
||||
private readonly CommandService _service;
|
||||
private readonly IConfigurationRoot _config;
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public HelpModule(CommandService service, IConfigurationRoot config, IServiceProvider services)
|
||||
{
|
||||
_service = service;
|
||||
_config = config;
|
||||
_services = services;
|
||||
}
|
||||
|
||||
[Command("help")]
|
||||
[Summary("Provides a list of available commands")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task HelpAsync()
|
||||
{
|
||||
var prefix = _config["DiscordSettings:Prefix"];
|
||||
|
||||
var builder = new EmbedBuilder()
|
||||
{
|
||||
Color = new Color(114, 137, 218),
|
||||
Description = "These are the commands you can use"
|
||||
};
|
||||
|
||||
foreach (var module in _service.Modules)
|
||||
{
|
||||
var moduleName = module.Name;
|
||||
|
||||
// create the list of accessible commands
|
||||
var commands = new List<string>(module.Commands.Count);
|
||||
|
||||
foreach (var cmd in module.Commands)
|
||||
{
|
||||
var result = await cmd.CheckPreconditionsAsync(Context, _services);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
commands.Add($"{prefix}{cmd.Aliases.First()}");
|
||||
}
|
||||
|
||||
// remove all duplicate commands
|
||||
commands = commands.Distinct().ToList();
|
||||
|
||||
var commandString = string.Empty;
|
||||
|
||||
foreach (var command in commands)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(command))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var commandToAdd = $"{command}\n";
|
||||
|
||||
if (commandString.Length + commandToAdd.Length > MAX_VALUE_LENGTH)
|
||||
{
|
||||
// force the output, string would be too long
|
||||
builder.AddField(x =>
|
||||
{
|
||||
x.Name = moduleName;
|
||||
x.Value = $"{commandString}\n";
|
||||
x.IsInline = false;
|
||||
});
|
||||
|
||||
// reset the module name and command string
|
||||
moduleName = $"{module.Name} cont.";
|
||||
commandString = string.Empty;
|
||||
}
|
||||
|
||||
commandString += commandToAdd;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(commandString))
|
||||
{
|
||||
builder.AddField(x =>
|
||||
{
|
||||
x.Name = moduleName;
|
||||
x.Value = $"{commandString}\n";
|
||||
x.IsInline = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await ReplyAsync(string.Empty, false, builder.Build());
|
||||
}
|
||||
|
||||
[Command("help")]
|
||||
[Summary("Searches a list of available commands")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task HelpAsync(string command)
|
||||
{
|
||||
var searchResults = _service.Search(Context, command);
|
||||
|
||||
if (!searchResults.IsSuccess)
|
||||
{
|
||||
await ReplyAsync($"Sorry, couldn't find a command like **{command}**.");
|
||||
return;
|
||||
}
|
||||
|
||||
var prefix = _config["DiscordSettings:Prefix"];
|
||||
|
||||
var builder = new EmbedBuilder()
|
||||
{
|
||||
Color = new Color(114, 137, 218),
|
||||
Description = $"Here are some commands like **{command}**"
|
||||
};
|
||||
|
||||
foreach (var match in searchResults.Commands)
|
||||
{
|
||||
var cmd = match.Command;
|
||||
|
||||
var result = await cmd.CheckPreconditionsAsync(Context, _services);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var usage = $"{prefix}{cmd.Aliases.First()}";
|
||||
if (cmd.Parameters.Count > 0)
|
||||
{
|
||||
usage += $" {string.Join(" ", cmd.Parameters.Select(p => p.Name))}";
|
||||
}
|
||||
usage += $"\n";
|
||||
|
||||
builder.AddField(x =>
|
||||
{
|
||||
x.Name = string.Join(", ", cmd.Aliases);
|
||||
x.Value = $"Summary: {cmd.Summary}\nUsage: {usage}";
|
||||
x.IsInline = false;
|
||||
});
|
||||
}
|
||||
|
||||
await ReplyAsync(string.Empty, false, builder.Build());
|
||||
}
|
||||
}
|
||||
}
|
||||
216
src/ServerManager.Discord/Modules/ServerCommandModule.cs
Normal file
216
src/ServerManager.Discord/Modules/ServerCommandModule.cs
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
using Discord;
|
||||
using Discord.Addons.Interactive;
|
||||
using Discord.Commands;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using ServerManagerTool.DiscordBot.Delegates;
|
||||
using ServerManagerTool.DiscordBot.Enums;
|
||||
using ServerManagerTool.DiscordBot.Interfaces;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot.Modules
|
||||
{
|
||||
[Name("Server Commands")]
|
||||
public sealed class ServerCommandModule : InteractiveBase
|
||||
{
|
||||
private readonly IServerManagerBot _serverManagerBot;
|
||||
private readonly CommandService _service;
|
||||
private readonly HandleCommandDelegate _handleCommandCallback;
|
||||
private readonly IConfigurationRoot _config;
|
||||
|
||||
public ServerCommandModule(IServerManagerBot serverManagerBot, CommandService service, HandleCommandDelegate handleCommandCallback, IConfigurationRoot config)
|
||||
{
|
||||
_serverManagerBot = serverManagerBot;
|
||||
_service = service;
|
||||
_handleCommandCallback = handleCommandCallback;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
[Command("backup", RunMode = RunMode.Async)]
|
||||
[Summary("Backup the server")]
|
||||
[Remarks("backup profileId")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task BackupServerAsync(string profileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverId = Context?.Guild?.Id.ToString() ?? string.Empty;
|
||||
var channelId = Context?.Channel?.Id.ToString() ?? string.Empty;
|
||||
|
||||
var response = _handleCommandCallback?.Invoke(CommandType.Backup, serverId, channelId, profileId, _serverManagerBot.Token);
|
||||
if (response is null)
|
||||
{
|
||||
await ReplyAsync("No servers associated with this channel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in response)
|
||||
{
|
||||
await ReplyAsync(output.Replace("&", "_"));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyAsync($"'{Context.Message}' command sent and failed with exception ({ex.Message})");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("restart", RunMode = RunMode.Async)]
|
||||
[Summary("Restart the server")]
|
||||
[Remarks("restart profileId")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task RestartServerAsync(string profileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverId = Context?.Guild?.Id.ToString() ?? string.Empty;
|
||||
var channelId = Context?.Channel?.Id.ToString() ?? string.Empty;
|
||||
|
||||
var response = _handleCommandCallback?.Invoke(CommandType.Restart, serverId, channelId, profileId, _serverManagerBot.Token);
|
||||
if (response is null)
|
||||
{
|
||||
await ReplyAsync("No servers associated with this channel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in response)
|
||||
{
|
||||
await ReplyAsync(output.Replace("&", "_"));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyAsync($"'{Context.Message}' command sent and failed with exception ({ex.Message})");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("shutdown", RunMode = RunMode.Async)]
|
||||
[Summary("Shuts down the server properly")]
|
||||
[Remarks("shutdown profileId")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task ShutdownServerAsync(string profileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverId = Context?.Guild?.Id.ToString() ?? string.Empty;
|
||||
var channelId = Context?.Channel?.Id.ToString() ?? string.Empty;
|
||||
|
||||
var response = _handleCommandCallback?.Invoke(CommandType.Shutdown, serverId, channelId, profileId, _serverManagerBot.Token);
|
||||
if (response is null)
|
||||
{
|
||||
await ReplyAsync("No servers associated with this channel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in response)
|
||||
{
|
||||
await ReplyAsync(output.Replace("&", "_"));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyAsync($"'{Context.Message}' command sent and failed with exception ({ex.Message})");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("start", RunMode = RunMode.Async)]
|
||||
[Summary("Starts the server")]
|
||||
[Remarks("start profileId")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task StartServerAsync(string profileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverId = Context?.Guild?.Id.ToString() ?? string.Empty;
|
||||
var channelId = Context?.Channel?.Id.ToString() ?? string.Empty;
|
||||
|
||||
var response = _handleCommandCallback?.Invoke(CommandType.Start, serverId, channelId, profileId, _serverManagerBot.Token);
|
||||
if (response is null)
|
||||
{
|
||||
await ReplyAsync("No servers associated with this channel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in response)
|
||||
{
|
||||
await ReplyAsync(output.Replace("&", "_"));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyAsync($"'{Context.Message}' command sent and failed with exception ({ex.Message})");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("stop", RunMode = RunMode.Async)]
|
||||
[Summary("Forcibly stops the server")]
|
||||
[Remarks("stop profileId")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task StopServerAsync(string profileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverId = Context?.Guild?.Id.ToString() ?? string.Empty;
|
||||
var channelId = Context?.Channel?.Id.ToString() ?? string.Empty;
|
||||
|
||||
var response = _handleCommandCallback?.Invoke(CommandType.Stop, serverId, channelId, profileId, _serverManagerBot.Token);
|
||||
if (response is null)
|
||||
{
|
||||
await ReplyAsync("No servers associated with this channel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in response)
|
||||
{
|
||||
await ReplyAsync(output.Replace("&", "_"));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyAsync($"'{Context.Message}' command sent and failed with exception ({ex.Message})");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("update", RunMode = RunMode.Async)]
|
||||
[Summary("Updates the server")]
|
||||
[Remarks("update profileId")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task UpdateServerAsync(string profileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverId = Context?.Guild?.Id.ToString() ?? string.Empty;
|
||||
var channelId = Context?.Channel?.Id.ToString() ?? string.Empty;
|
||||
|
||||
var response = _handleCommandCallback?.Invoke(CommandType.Update, serverId, channelId, profileId, _serverManagerBot.Token);
|
||||
if (response is null)
|
||||
{
|
||||
await ReplyAsync("No servers associated with this channel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in response)
|
||||
{
|
||||
await ReplyAsync(output.Replace("&", "_"));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyAsync($"'{Context.Message}' command sent and failed with exception ({ex.Message})");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
141
src/ServerManager.Discord/Modules/ServerQueryModule.cs
Normal file
141
src/ServerManager.Discord/Modules/ServerQueryModule.cs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
using Discord;
|
||||
using Discord.Addons.Interactive;
|
||||
using Discord.Commands;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using ServerManagerTool.DiscordBot.Delegates;
|
||||
using ServerManagerTool.DiscordBot.Enums;
|
||||
using ServerManagerTool.DiscordBot.Interfaces;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot.Modules
|
||||
{
|
||||
[Name("Server Query")]
|
||||
public sealed class ServerQueryModule : InteractiveBase
|
||||
{
|
||||
private readonly IServerManagerBot _serverManagerBot;
|
||||
private readonly CommandService _service;
|
||||
private readonly HandleCommandDelegate _handleCommandCallback;
|
||||
private readonly IConfigurationRoot _config;
|
||||
|
||||
public ServerQueryModule(IServerManagerBot serverManagerBot, CommandService service, HandleCommandDelegate handleCommandCallback, IConfigurationRoot config)
|
||||
{
|
||||
_serverManagerBot = serverManagerBot;
|
||||
_service = service;
|
||||
_handleCommandCallback = handleCommandCallback;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
[Command("info", RunMode = RunMode.Async)]
|
||||
[Summary("Poll server for information")]
|
||||
[Remarks("info")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task ServerInfoAsync()
|
||||
{
|
||||
await ServerInfoAsync(null);
|
||||
}
|
||||
|
||||
[Command("info", RunMode = RunMode.Async)]
|
||||
[Summary("Poll server for information")]
|
||||
[Remarks("info profileId")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task ServerInfoAsync(string profileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverId = Context?.Guild?.Id.ToString() ?? string.Empty;
|
||||
var channelId = Context?.Channel?.Id.ToString() ?? string.Empty;
|
||||
|
||||
var response = _handleCommandCallback?.Invoke(CommandType.Info, serverId, channelId, profileId, _serverManagerBot.Token);
|
||||
if (response is null)
|
||||
{
|
||||
await ReplyAsync("No servers associated with this channel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in response)
|
||||
{
|
||||
await ReplyAsync(output.Replace("&", "_"));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyAsync($"'{Context.Message}' command sent and failed with exception ({ex.Message})");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("list", RunMode = RunMode.Async)]
|
||||
[Summary("List of all servers associated with this channel")]
|
||||
[Remarks("list")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task ServerListAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverId = Context?.Guild?.Id.ToString() ?? string.Empty;
|
||||
var channelId = Context?.Channel?.Id.ToString() ?? string.Empty;
|
||||
|
||||
var response = _handleCommandCallback?.Invoke(CommandType.List, serverId, channelId, null, _serverManagerBot.Token);
|
||||
if (response is null)
|
||||
{
|
||||
await ReplyAsync("No servers associated with this channel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in response)
|
||||
{
|
||||
await ReplyAsync(output.Replace("&", "_"));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyAsync($"'{Context.Message}' command sent and failed with exception ({ex.Message})");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("status", RunMode = RunMode.Async)]
|
||||
[Summary("Poll server for status")]
|
||||
[Remarks("status")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task ServerStatusAsync()
|
||||
{
|
||||
await ServerStatusAsync(null);
|
||||
}
|
||||
|
||||
[Command("status", RunMode = RunMode.Async)]
|
||||
[Summary("Poll server for status")]
|
||||
[Remarks("status profileId")]
|
||||
[RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
|
||||
public async Task ServerStatusAsync(string profileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverId = Context?.Guild?.Id.ToString() ?? string.Empty;
|
||||
var channelId = Context?.Channel?.Id.ToString() ?? string.Empty;
|
||||
|
||||
var response = _handleCommandCallback?.Invoke(CommandType.Status, serverId, channelId, profileId, _serverManagerBot.Token);
|
||||
if (response is null)
|
||||
{
|
||||
await ReplyAsync("No servers associated with this channel.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var output in response)
|
||||
{
|
||||
await ReplyAsync(output.Replace("&", "_"));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ReplyAsync($"'{Context.Message}' command sent and failed with exception ({ex.Message})");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,28 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup Label="Globals">
|
||||
<Configurations>Debug;Release;Debug - Beta</Configurations>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net462</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RootNamespace>ServerManagerTool.Discord</RootNamespace>
|
||||
<RootNamespace>ServerManagerTool.DiscordBot</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - Beta|AnyCPU'">
|
||||
<DefineConstants>$(DefineConstants);DEBUG</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Discord.Addons.Interactive" Version="2.0.0" />
|
||||
<PackageReference Include="Discord.Net" Version="2.4.0" />
|
||||
<PackageReference Include="Discord.Net.Providers.WS4Net" Version="2.4.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
138
src/ServerManager.Discord/ServerManagerBot.cs
Normal file
138
src/ServerManager.Discord/ServerManagerBot.cs
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
using Discord;
|
||||
using Discord.Addons.Interactive;
|
||||
using Discord.Commands;
|
||||
using Discord.Net.Providers.WS4Net;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ServerManagerTool.DiscordBot.Delegates;
|
||||
using ServerManagerTool.DiscordBot.Interfaces;
|
||||
using ServerManagerTool.DiscordBot.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot
|
||||
{
|
||||
public sealed class ServerManagerBot : IServerManagerBot
|
||||
{
|
||||
internal ServerManagerBot()
|
||||
{
|
||||
Started = false;
|
||||
}
|
||||
|
||||
public CancellationToken Token { get; private set; }
|
||||
public bool Started { get; private set; }
|
||||
|
||||
public async Task StartAsync(string discordToken, string commandPrefix, string dataDirectory, HandleCommandDelegate handleCommandCallback, HandleTranslationDelegate handleTranslationCallback, CancellationToken token)
|
||||
{
|
||||
if (Started)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Started = true;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(commandPrefix) || string.IsNullOrWhiteSpace(discordToken) || handleTranslationCallback is null || handleCommandCallback is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Token = token;
|
||||
|
||||
if (commandPrefix.Any(c => !char.IsLetterOrDigit(c)))
|
||||
{
|
||||
throw new Exception("#DiscordBot_InvalidPrefixError");
|
||||
}
|
||||
|
||||
if (!commandPrefix.EndsWith(DiscordBot.PREFIX_DELIMITER))
|
||||
{
|
||||
commandPrefix += DiscordBot.PREFIX_DELIMITER;
|
||||
}
|
||||
|
||||
var settings = new Dictionary<string, string>
|
||||
{
|
||||
{ "DiscordSettings:Token", discordToken },
|
||||
{ "DiscordSettings:Prefix", commandPrefix },
|
||||
{ "ServerManager:DataDirectory", dataDirectory },
|
||||
};
|
||||
|
||||
// Begin building the configuration file
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(settings)
|
||||
.Build();
|
||||
|
||||
var socketConfig = new DiscordSocketConfig
|
||||
{
|
||||
#if DEBUG
|
||||
LogLevel = LogSeverity.Verbose,
|
||||
#else
|
||||
LogLevel = LogSeverity.Info,
|
||||
#endif
|
||||
// Tell Discord.Net to cache 1000 messages per channel
|
||||
MessageCacheSize = 1000,
|
||||
};
|
||||
if (Environment.OSVersion.Version < new Version(6, 2))
|
||||
{
|
||||
// windows 7 or early
|
||||
socketConfig.WebSocketProvider = WS4NetProvider.Instance;
|
||||
}
|
||||
|
||||
var commandConfig = new CommandServiceConfig
|
||||
{
|
||||
// Force all commands to run async
|
||||
DefaultRunMode = RunMode.Async,
|
||||
#if DEBUG
|
||||
LogLevel = LogSeverity.Verbose,
|
||||
#else
|
||||
LogLevel = LogSeverity.Info,
|
||||
#endif
|
||||
};
|
||||
|
||||
// Build the service provider
|
||||
var services = new ServiceCollection()
|
||||
// Add the discord client to the service provider
|
||||
.AddSingleton(new DiscordSocketClient(socketConfig))
|
||||
// Add the command service to the service provider
|
||||
.AddSingleton(new CommandService(commandConfig))
|
||||
// Add remaining services to the provider
|
||||
.AddSingleton<CommandHandlerService>()
|
||||
.AddSingleton<InteractiveService>()
|
||||
.AddSingleton<LoggingService>()
|
||||
.AddSingleton<StartupService>()
|
||||
.AddSingleton<ShutdownService>()
|
||||
.AddSingleton<Random>()
|
||||
.AddSingleton(config)
|
||||
.AddSingleton(handleCommandCallback)
|
||||
.AddSingleton(handleTranslationCallback)
|
||||
.AddSingleton<IServerManagerBot>(this);
|
||||
|
||||
// Create the service provider
|
||||
using (var provider = services.BuildServiceProvider())
|
||||
{
|
||||
// Initialize the logging service, startup service, and command handler
|
||||
provider?.GetRequiredService<LoggingService>();
|
||||
await provider?.GetRequiredService<StartupService>().StartAsync();
|
||||
provider?.GetRequiredService<CommandHandlerService>();
|
||||
|
||||
try
|
||||
{
|
||||
// Prevent the application from closing
|
||||
await Task.Delay(Timeout.Infinite, token);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
Debug.WriteLine("Task Canceled");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Debug.WriteLine("Operation Canceled");
|
||||
}
|
||||
|
||||
await provider?.GetRequiredService<ShutdownService>().StopAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/ServerManager.Discord/ServerManagerBotFactory.cs
Normal file
19
src/ServerManager.Discord/ServerManagerBotFactory.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using ServerManagerTool.DiscordBot.Interfaces;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot
|
||||
{
|
||||
public static class ServerManagerBotFactory
|
||||
{
|
||||
private static IServerManagerBot _serverManagerBot;
|
||||
|
||||
public static IServerManagerBot GetServerManagerBot()
|
||||
{
|
||||
if (_serverManagerBot is null)
|
||||
{
|
||||
_serverManagerBot = new ServerManagerBot();
|
||||
}
|
||||
|
||||
return _serverManagerBot;
|
||||
}
|
||||
}
|
||||
}
|
||||
65
src/ServerManager.Discord/Services/CommandHandlerService.cs
Normal file
65
src/ServerManager.Discord/Services/CommandHandlerService.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot.Services
|
||||
{
|
||||
public class CommandHandlerService
|
||||
{
|
||||
private readonly DiscordSocketClient _discord;
|
||||
private readonly CommandService _commands;
|
||||
private readonly IConfigurationRoot _config;
|
||||
private readonly IServiceProvider _provider;
|
||||
|
||||
public CommandHandlerService(DiscordSocketClient discord, CommandService commands, IConfigurationRoot config, IServiceProvider provider)
|
||||
{
|
||||
_discord = discord;
|
||||
_commands = commands;
|
||||
_config = config;
|
||||
_provider = provider;
|
||||
|
||||
_discord.MessageReceived += OnMessageReceivedAsync;
|
||||
}
|
||||
|
||||
private async Task OnMessageReceivedAsync(SocketMessage s)
|
||||
{
|
||||
// Ensure the message is from a user/bot
|
||||
var msg = s as SocketUserMessage;
|
||||
if (msg is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore self when checking commands
|
||||
if (msg.Author == _discord.CurrentUser)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Tell bot to ignore itself.
|
||||
if (msg.Author.IsBot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the command context
|
||||
var context = new SocketCommandContext(_discord, msg);
|
||||
|
||||
// Check if the message has a valid command prefix
|
||||
var argPos = 0;
|
||||
if (msg.HasStringPrefix(_config["DiscordSettings:Prefix"], ref argPos) || msg.HasMentionPrefix(_discord.CurrentUser, ref argPos))
|
||||
{
|
||||
// Execute the command
|
||||
var result = await _commands.ExecuteAsync(context, argPos, _provider);
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
// If not successful, reply with the error.
|
||||
await context.Channel.SendMessageAsync(result.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/ServerManager.Discord/Services/LoggingService.cs
Normal file
57
src/ServerManager.Discord/Services/LoggingService.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot.Services
|
||||
{
|
||||
public class LoggingService
|
||||
{
|
||||
private readonly DiscordSocketClient _discord;
|
||||
private readonly CommandService _commands;
|
||||
private readonly IConfigurationRoot _config;
|
||||
|
||||
private string LogDirectory { get; }
|
||||
private string LogFile => Path.Combine(LogDirectory, $"ServerManager_DiscordBot.{DateTime.Now:yyyyMMdd}.log");
|
||||
|
||||
public LoggingService(DiscordSocketClient discord, CommandService commands, IConfigurationRoot config)
|
||||
{
|
||||
_discord = discord;
|
||||
_commands = commands;
|
||||
_config = config;
|
||||
|
||||
// Get the data directory from the config file
|
||||
var rootDirectory = _config["ServerManager:DataDirectory"] ?? AppContext.BaseDirectory;
|
||||
LogDirectory = Path.Combine(rootDirectory, "logs");
|
||||
|
||||
_discord.Log += OnLogAsync;
|
||||
_commands.Log += OnLogAsync;
|
||||
}
|
||||
|
||||
private async Task OnLogAsync(LogMessage message)
|
||||
{
|
||||
// Create the log directory if it doesn't exist
|
||||
if (!Directory.Exists(LogDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(LogDirectory);
|
||||
}
|
||||
|
||||
// Create today's log file if it doesn't exist
|
||||
if (!File.Exists(LogFile))
|
||||
{
|
||||
File.Create(LogFile).Dispose();
|
||||
}
|
||||
|
||||
var logText = $"{DateTime.Now:HH:mm:ss:ffff} [{message.Severity}] {message.Source}: {message.Exception?.ToString() ?? message.Message}";
|
||||
|
||||
// Write the log text to a file
|
||||
File.AppendAllText(LogFile, logText + "\n");
|
||||
|
||||
// Write the log text to the console
|
||||
await Console.Out.WriteLineAsync(logText);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/ServerManager.Discord/Services/ShutdownService.cs
Normal file
21
src/ServerManager.Discord/Services/ShutdownService.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
using Discord.WebSocket;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot.Services
|
||||
{
|
||||
public class ShutdownService
|
||||
{
|
||||
private readonly DiscordSocketClient _discord;
|
||||
|
||||
public ShutdownService(DiscordSocketClient discord)
|
||||
{
|
||||
_discord = discord;
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
{
|
||||
await _discord.StopAsync();
|
||||
await _discord.LogoutAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/ServerManager.Discord/Services/StartupService.cs
Normal file
45
src/ServerManager.Discord/Services/StartupService.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.DiscordBot.Services
|
||||
{
|
||||
public class StartupService
|
||||
{
|
||||
private readonly DiscordSocketClient _discord;
|
||||
private readonly CommandService _commands;
|
||||
private readonly IConfigurationRoot _config;
|
||||
private readonly IServiceProvider _provider;
|
||||
|
||||
public StartupService(DiscordSocketClient discord, CommandService commands, IConfigurationRoot config, IServiceProvider provider)
|
||||
{
|
||||
_discord = discord;
|
||||
_commands = commands;
|
||||
_config = config;
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
public async Task StartAsync()
|
||||
{
|
||||
// Get the discord token from the config file
|
||||
var discordToken = _config["DiscordSettings:Token"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(discordToken))
|
||||
{
|
||||
throw new Exception("#DiscordBot_MissingTokenError");
|
||||
}
|
||||
|
||||
// Login to discord
|
||||
await _discord.LoginAsync(TokenType.Bot, discordToken);
|
||||
// Connect to the websocket
|
||||
await _discord.StartAsync();
|
||||
|
||||
// Load commands and modules into the command service
|
||||
await _commands.AddModulesAsync(Assembly.GetExecutingAssembly(), _provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue