Merge branch 'master' into master

This commit is contained in:
Brett Hewitson 2021-12-17 15:45:39 +10:00 committed by GitHub
commit defc6355cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
160 changed files with 4646 additions and 1836 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -5,7 +5,84 @@
<title>Ark Server Manager Version Feed</title>
<subtitle>This is the Ark Server Manager release version feed.</subtitle>
<link href="http://arkservermanager.freeforums.net/" />
<updated>2021-12-05T00:00:00Z</updated>
<updated>2021-12-15T00:00:00Z</updated>
<entry>
<id>urn:uuid:18276A38-2C71-4BB8-9A83-96D5EBFE9C87</id>
<title>1.1.412 (1.1.412.4)</title>
<summary>1.1.412.4</summary>
<link href="" />
<updated>2021-12-15T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed a bug with the Server Shutdown when the CheckForOnlinePlayers option not selected.</li>
<li>Fixed a bug when the backup path was a root directory that caused a 'Invalid URI: A Dos path must be rooted' crash.</li>
<li>Added additional validation when setting directories in the global setting, to ensure they are rooted correctly.</li>
<li>Fixed a bug when starting the server manager and it tries to download steamcmd, but fails as steamcmd is unavailable for download.</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>fr-FR Translation file updated.</li>
<li>zh-CN Translation file updated.</li>
<li>Added LostIsland to official mods in the SurvivalEvolved gamedata file.</li>
<li>Added coloring to the setting grids for the Lost Island DLC engrams, creatures and resources.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:DBAFCE91-2235-4B6C-AE9B-5E4EF9FEC8F5</id>
<title>1.1.411 (1.1.411.10)</title>
<summary>1.1.411.10</summary>
<link href="" />
<updated>2021-12-14T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>
A new Discord Bot has been added to the server manager.<br/>
This new discord bot will allow you to send <font color="#0094FF">Start, Stop, Shutdown, Restart, Backup and Update</font> commands to the server manager from within your discord client.<br/>
To setup the new discord bot, open the global settings and scroll down to the Discord section.<br/><br/>
<font color="#e62919">
NOTE: This is long process to get the discord bot working, and I have created a forum post with detailed instructions how to do it.
</font>
</li>
<li>Server Settings - Dino Section - Added MutagenLevelBoost and MutagenLevelBoostBred settings.</li>
<li>Added gamedata file for the Lost Island DLC - only contains the map name for the Map droplist - do not use until the DLC is officially released!</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Global Settings - Added reset button to the Data Directory Location.</li>
<li>Server Monitor window now stores it's location.</li>
<li>Removed MOTD and Alternate Save Directory from the Administration section of the Sync.</li>
<li>fr-FR Translation file updated.</li>
<li>pt-BR Translation file updated.</li>
<li>ru-RU Translation file updated.</li>
<li>zh-CN Translation file updated.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:BE37B3FD-B498-4B1C-9D4D-754EA0F4A357</id>

View file

@ -5,22 +5,22 @@
<title>Ark Server Manager Version Feed</title>
<subtitle>This is the Ark Server Manager beta version feed.</subtitle>
<link href="http://arkservermanager.freeforums.net/" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-16T00:00:00Z</updated>
<entry>
<id>urn:uuid:C02D44F9-E3AA-4CA0-BF2F-110F8C83CC21</id>
<title>1.1.411 (1.1.411.7)</title>
<summary>1.1.411.7</summary>
<id>urn:uuid:8EE5659C-18E6-47D3-941D-C32B129D2E06</id>
<title>1.1.413 (1.1.413.7)</title>
<summary>1.1.413.7</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-17T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Added gamedata file for the Lost Island DLC - only contains the map name for the Map droplist - do not use until the DLC is officially released!</li>
<li>Added Lost Island to the language files for translation.</li>
<li>Main Window - Added Discord Bot Status and a button to Stop/Start the discord bot.</li>
<li>Global Settings - Discord Bot section - Added a checkbox to allow all bots.</li>
</ul>
</p>
</div>
@ -32,42 +32,18 @@
</entry>
<entry>
<id>urn:uuid:F75C6AFF-2A27-49BE-917A-7EAAACCCBF17</id>
<title>1.1.411 (1.1.411.6)</title>
<summary>1.1.411.6</summary>
<id>urn:uuid:65A7E6B1-98D1-422D-B42F-B0EBB1D20E41</id>
<title>1.1.413 (1.1.413.6)</title>
<summary>1.1.413.6</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-17T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>fr-FR Translation file updated.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:0BCB8BBA-330F-4063-8B7E-5B144589999A</id>
<title>1.1.411 (1.1.411.5)</title>
<summary>1.1.411.5</summary>
<link href="" />
<updated>2021-12-10T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Server Monitor window now stores it's location.</li>
<li>Reference library updates.</li>
<li>Added additional message logging when log level set to debug.</li>
<li>pt-BR Translation file updated.</li>
<li>ru-RU Translation file updated.</li>
</ul>
@ -81,29 +57,69 @@
</entry>
<entry>
<id>urn:uuid:7697EBD7-DEF6-422B-B9A6-D4B77F31D572</id>
<title>1.1.411 (1.1.411.4)</title>
<summary>1.1.411.4</summary>
<id>urn:uuid:65A7E6B1-98D1-422D-B42F-B0EBB1D20E41</id>
<title>1.1.413 (1.1.413.5)</title>
<summary>1.1.413.5</summary>
<link href="" />
<updated>2021-12-09T00:00:00Z</updated>
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Global Settings - Discord Bot section - Added a log level droplist.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:98FFBFA1-4E99-4801-BF2B-CA68BE300C27</id>
<title>1.1.413 (1.1.413.4)</title>
<summary>1.1.413.4</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed a minor issue when clicking the data directory reset button - fringe case that I found during testing.</li>
<li>Fixed a bug that would prevent a bot on the whitelist processing the message.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:8958A494-DE13-4F6F-ACA2-10026D5FB8A9</id>
<title>1.1.413 (1.1.413.3)</title>
<summary>1.1.413.3</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Server Settings - Dino Section - Added MutagenLevelBoost and MutagenLevelBoostBred settings.</li>
<li>Server Settings - Discord Bot section - Added an alias that can be used with the discord command instead of the profile id.</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>pt-BR Translation file updated.</li>
<li>ru-RU Translation file updated.</li>
<li>Removed the mandatory requirement to enter the '!' after the discord prefix. The '!' has been added to the existing prefix so no change to existing functionality, but you can now change it.</li>
<li>zh-CN Translation file updated.</li>
</ul>
</p>
@ -116,73 +132,41 @@
</entry>
<entry>
<id>urn:uuid:8290F43D-98F4-4F4D-8DD8-0A3EF5A45656</id>
<title>1.1.411 (1.1.411.3)</title>
<summary>1.1.411.3</summary>
<id>urn:uuid:8958A494-DE13-4F6F-ACA2-10026D5FB8A9</id>
<title>1.1.413 (1.1.413.2)</title>
<summary>1.1.413.2</summary>
<link href="" />
<updated>2021-12-08T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed language translation of Data Directory window.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:ADBF3FE0-017C-4E23-8FE8-EFE75E7C8BA1</id>
<title>1.1.411 (1.1.411.2)</title>
<summary>1.1.411.2</summary>
<link href="" />
<updated>2021-12-08T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Global Settings - Added reset button to the Data Directory Location.</li>
<li>pt-BR Translation file updated.</li>
<li>zh-CN Translation file updated.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:DBAFCE91-2235-4B6C-AE9B-5E4EF9FEC8F5</id>
<title>1.1.411 (1.1.411.1)</title>
<summary>1.1.411.1</summary>
<link href="" />
<updated>2021-12-06T00:00:00Z</updated>
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>
A new Discord Bot has been added to the server manager.<br/>
This new discord bot will allow you to send <font color="#0094FF">Start, Stop, Shutdown, Restart, Backup and Update</font> commands to the server manager from within your discord client.<br/>
To setup the new discord bot, open the global settings and scroll down to the Discord section.<br/><br/>
<font color="#e62919">
NOTE: This is long process to get the discord bot working, and I have created a forum post with detailed instructions how to do it.
</font>
</li>
<li>Global Settings - Discord Bot section - Added a whitelist to allow bots to send commands to the server manager.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:3E33DCB2-ECFE-4489-B1A4-56F5D386F9DC</id>
<title>1.1.413 (1.1.413.1)</title>
<summary>1.1.413.1</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Made changes to the code to help improve performance.</li>
</ul>
</p>
</div>

View file

@ -83,12 +83,21 @@
<sys:String x:Key="ProcessorAffinity_All">All</sys:String>
<!--#endregion-->
<!--#region Processor Window States -->
<!--#region Window States -->
<sys:String x:Key="WindowState_Normal">Normal</sys:String>
<sys:String x:Key="WindowState_Minimized">Minimized</sys:String>
<sys:String x:Key="WindowState_Maximized">Maximized</sys:String>
<!--#endregion-->
<!--#region Discord Bot Log Levels -->
<sys:String x:Key="DiscordBotLogLevel_Critical">Critical</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Error">Error</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Warning">Warning</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Info">Info</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Verbose">Verbose</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Debug">Debug</sys:String>
<!--#endregion-->
<!--#region Application -->
<sys:String x:Key="Application_RunAsAdministratorTitle">Run as Administrator</sys:String>
<sys:String x:Key="Application_RunAsAdministratorLabel">This application requires administration priviledges to access ALL functionality. Would you like to Run as Administrator?</sys:String>
@ -127,6 +136,7 @@
<sys:String x:Key="AutoUpdater_Status_DownloadNewServerComplete">Server download complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Complete">Complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Cancelled">Cancelled</sys:String>
<sys:String x:Key="AutoUpdater_Status_Failed">Failed</sys:String>
<sys:String x:Key="AutoUpdater_CancelButtonLabel">Cancel</sys:String>
<!--#endregion-->
@ -621,8 +631,17 @@
<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_DiscordBotLogLevelLabel">Log Level:</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="ServerSettings_DiscordBotAllowAllBotsLabel">Allow All Bots</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotAllowAllBotsTooltip">If enabled, the server manager bot will respond to all other bots, otherwise they will be ignored unless they are in the whitelist.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistLabel">Bot Whitelist</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdLabel">Bot ID</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdTooltip">The id of the bot to whitelist.</sys:String>
<sys:String x:Key="ServerSettings_AddDiscordBotWhitelistTooltip">Add Whitelist</sys:String>
<sys:String x:Key="ServerSettings_ClearDiscordBotWhitelistTooltip">Clear Whitelists</sys:String>
<sys:String x:Key="ServerSettings_RemoveDiscordBotWhitelistTooltip">Delete Whitelist</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>
@ -773,12 +792,18 @@
<sys:String x:Key="MainWindow_AutoUpdateTaskEnableLabel">Enable</sys:String>
<sys:String x:Key="MainWindow_AutoUpdateTaskEnableTooltip">Enable the auto-update scheduled task</sys:String>
<sys:String x:Key="MainWindow_TaskRunTimeLabel">Next Run Time:</sys:String>
<sys:String x:Key="MainWindow_DiscordBotStatusLabel">Discord Bot:</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStartLabel">Start</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStartTooltip">Start the discord bot</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStopLabel">Stop</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStopTooltip">Stop the discord bot</sys:String>
<sys:String x:Key="MainWindow_TaskStateUnknownLabel">Unknown</sys:String>
<sys:String x:Key="MainWindow_TaskStateDisabledLabel">Disabled</sys:String>
<sys:String x:Key="MainWindow_TaskStateQueuedLabel">Queued</sys:String>
<sys:String x:Key="MainWindow_TaskStateReadyLabel">Ready</sys:String>
<sys:String x:Key="MainWindow_TaskStateRunningLabel">Running</sys:String>
<sys:String x:Key="MainWindow_TaskStateStoppedLabel">Stopped</sys:String>
<sys:String x:Key="MainWindow_ProfileLoad_FailedTitle">Profile failed to load</sys:String>
<sys:String x:Key="MainWindow_ProfileLoad_FailedLabel">The profile at {0} failed to load. The error was: {1}\r\n{2}</sys:String>
@ -1207,6 +1232,8 @@
<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_DiscordAliasLabel">Alias:</sys:String>
<sys:String x:Key="ServerSettings_DiscordAliasTooltip">A unique name to identify your server when using the discord commands, can be used instead of the profile id.</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>
@ -5495,6 +5522,23 @@
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Easy_C">Boss Inventory - Crystal Wyvern Queen (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Medium_C">Boss Inventory - Crystal Wyvern Queen (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Hard_C">Boss Inventory - Crystal Wyvern Queen (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Ragnarok_C">Boss Inventory - Dragon (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Ragnarok_C">Boss Inventory - Dragon (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Hard_Ragnarok_C">Boss Inventory - Dragon (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Easy_Ragnarok_C">Boss Inventory - Manticore (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Medium_Ragnarok_C">Boss Inventory - Manticore (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Hard_Ragnarok_C">Boss Inventory - Manticore (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Valguero_C">Boss Inventory - Dragon (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Valguero_C">Boss Inventory - Dragon (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Hard_Valguero_C">Boss Inventory - Dragon (Hard)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Easy_Valguero_C">Boss Inventory - Manticore (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Medium_Valguero_C">Boss Inventory - Manticore (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Hard_Valguero_C">Boss Inventory - Manticore (Hard)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Easy_Valguero_C">Boss Inventory - Megapithecus (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Medium_Valguero_C">Boss Inventory - Megapithecus (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Hard_Valguero_C">Boss Inventory - Megapithecus (Hard)</sys:String>
<!--#endregion-->
<!--#endregion-->
@ -5580,8 +5624,9 @@
<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_ProfileMissing">The '{0}' command requires a profile id or alias.</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_ProfileMultiples">Multiple profiles with '{0}' were found in the channel, command aborted.</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>

View file

@ -1 +1 @@
1.1.411.7
1.1.413.7

Binary file not shown.

View file

@ -24,6 +24,7 @@
<sys:String x:Key="Map_Genesis">Genesis: Part 1</sys:String>
<sys:String x:Key="Map_CrystalIsles">Crystal Isles</sys:String>
<sys:String x:Key="Map_Gen2">Genesis: Part 2</sys:String>
<sys:String x:Key="Map_LostIsland">Lost Island</sys:String>
<!--#endregion-->
<!--#region Total Conversion Names -->
@ -56,6 +57,7 @@
<sys:String x:Key="Mod_Genesis">Genesis: Part 1</sys:String>
<sys:String x:Key="Mod_CrystalIsles">Crystal Isles</sys:String>
<sys:String x:Key="Mod_Genesis2">Genesis: Part 2</sys:String>
<sys:String x:Key="Mod_LostIsland">Lost Island</sys:String>
<sys:String x:Key="Mod_PGM">PGM</sys:String>
<!--#endregion-->
@ -125,6 +127,7 @@
<sys:String x:Key="AutoUpdater_Status_DownloadNewServerComplete">Server download complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Complete">Complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Cancelled">Cancelled</sys:String>
<sys:String x:Key="AutoUpdater_Status_Failed">Failed</sys:String>
<sys:String x:Key="AutoUpdater_CancelButtonLabel">Cancel</sys:String>
<!--#endregion-->
@ -610,7 +613,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>
@ -662,6 +682,8 @@
<sys:String x:Key="GlobalSettings_DataDirectoryChange_ConfirmLabel">Changing the data directory will move any existing profiles to the new location, but it will not move any server installations. Do you still want to change this directory?</sys:String>
<sys:String x:Key="GlobalSettings_DataDirectoryChange_FailedTitle">Failed to change data directory</sys:String>
<sys:String x:Key="GlobalSettings_DataDirectoryChange_FailedLabel">There was an error changing the data directory: {0}\r\nPlease correct the error and try again, or contact technical support for assistance.</sys:String>
<sys:String x:Key="GlobalSettings_ResetDataDirectory_ConfirmTitle">Confirm Data Directory Reset</sys:String>
<sys:String x:Key="GlobalSettings_ResetDataDirectory_ConfirmLabel">Click 'Yes' to confirm you want to reset the location of the data directory. Once reset, the server manager will shutdown and you will need to restart.</sys:String>
<sys:String x:Key="GlobalSettings_DataDirectoryTitle">Select Backup Directory</sys:String>
<sys:String x:Key="GlobalSettings_CacheDirectoryTitle">Select Cache Directory</sys:String>
@ -775,6 +797,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 +1204,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>
@ -1598,14 +1641,18 @@
<sys:String x:Key="ServerSettings_TamedDinoPerLevelStatAddMultipliersLabel">Per-Level Stat Multipliers (Tamed) - Add</sys:String>
<sys:String x:Key="ServerSettings_TamedDinoPerLevelStatAffinityMultipliersLabel">Per-Level Stat Multipliers (Tamed) - Affinity</sys:String>
<sys:String x:Key="ServerSettings_WildDinoPerLevelStatMultipliersLabel">Per-Level Stat Multipliers (Wild)</sys:String>
<sys:String x:Key="ServerSettings_DinoWildMutagenLevelBoostLabel">Mutagen Level Boost (Wild)</sys:String>
<sys:String x:Key="ServerSettings_DinoBredMutagenLevelBoostLabel">Mutagen Level Boost (Bred)</sys:String>
<sys:String x:Key="ServerSettings_DinoBreedingMultipliersLabel">Dino Breeding Multipliers</sys:String>
<sys:String x:Key="ServerSettings_BaseStatMultipliersTooltip">If enabled, allows scale factors to be applied to each base stat.</sys:String>
<sys:String x:Key="ServerSettings_PerLevelStatMultipliersTooltip">If enabled, allows scale factors to be applied to each stat.</sys:String>
<sys:String x:Key="ServerSettings_PerLevelStatTamedAddMultipliersTooltip">If enabled, allows scale factors to be applied to the Taming Addition for each stat.</sys:String>
<sys:String x:Key="ServerSettings_PerLevelStatTamedAffinityMultipliersTooltip">If enabled, allows scale factors to be applied to the Taming Multiplier for each stat.</sys:String>
<sys:String x:Key="ServerSettings_PerLevelStatTamedMultipliersTooltip">If enabled, allows scale factors to be applied to the Tamed Stat Increase for each stat.</sys:String>
<sys:String x:Key="ServerSettings_ResetPerLevelStatMultipliersTooltip">Reset all multipliers back to defaults.</sys:String>
<sys:String x:Key="ServerSettings_ResetBaseStatMultipliersTooltip">Reset all multipliers back to defaults.</sys:String>
<sys:String x:Key="ServerSettings_DinoWildMutagenLevelBoostTooltip">If enabled, allows scale factors to be applied to the Number of levels Mutagen adds to tames with wild ancestry.</sys:String>
<sys:String x:Key="ServerSettings_DinoBredMutagenLevelBoostTooltip">If enabled, allows scale factors to be applied to the Number of levels Mutagen adds to tames with bred ancestry.</sys:String>
<sys:String x:Key="ServerSettings_ResetPerLevelStatMultipliersTooltip">Reset all values back to defaults.</sys:String>
<sys:String x:Key="ServerSettings_ResetBaseStatMultipliersTooltip">Reset all values back to defaults.</sys:String>
<sys:String x:Key="ServerSettings_MatingIntervalLabel">Mating Interval:</sys:String>
<sys:String x:Key="ServerSettings_MatingIntervalTooltip">Specifies the multiplier for time between tamed dino mating. Lower values decrease the time between mating.</sys:String>
@ -5449,6 +5496,23 @@
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Easy_C">Boss Inventory - Crystal Wyvern Queen (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Medium_C">Boss Inventory - Crystal Wyvern Queen (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Hard_C">Boss Inventory - Crystal Wyvern Queen (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Ragnarok_C">Boss Inventory - Dragon (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Ragnarok_C">Boss Inventory - Dragon (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Hard_Ragnarok_C">Boss Inventory - Dragon (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Easy_Ragnarok_C">Boss Inventory - Manticore (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Medium_Ragnarok_C">Boss Inventory - Manticore (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Hard_Ragnarok_C">Boss Inventory - Manticore (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Valguero_C">Boss Inventory - Dragon (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Valguero_C">Boss Inventory - Dragon (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Hard_Valguero_C">Boss Inventory - Dragon (Hard)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Easy_Valguero_C">Boss Inventory - Manticore (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Medium_Valguero_C">Boss Inventory - Manticore (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Hard_Valguero_C">Boss Inventory - Manticore (Hard)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Easy_Valguero_C">Boss Inventory - Megapithecus (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Medium_Valguero_C">Boss Inventory - Megapithecus (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Hard_Valguero_C">Boss Inventory - Megapithecus (Hard)</sys:String>
<!--#endregion-->
<!--#endregion-->
@ -5523,4 +5587,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>

Binary file not shown.

View file

@ -1 +1 @@
1.1.410
1.1.412

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -5,7 +5,69 @@
<title>Conan Server Manager Version Feed</title>
<subtitle>This is the Conan Server Manager release version feed.</subtitle>
<link href="http://servermanagers.freeforums.net/" />
<updated>2021-12-02T00:00:00Z</updated>
<updated>2021-12-15T00:00:00Z</updated>
<entry>
<id>urn:uuid:6383E79A-C31F-462B-9730-B26B28DC5EFF</id>
<title>1.1.57 (1.1.57.3)</title>
<summary>1.1.57.3</summary>
<link href="" />
<updated>2021-12-15T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed a bug with the Server Shutdown when the CheckForOnlinePlayers option not selected.</li>
<li>Fixed a bug when the backup path was a root directory that caused a 'Invalid URI: A Dos path must be rooted' crash.</li>
<li>Added additional validation when setting directories in the global setting, to ensure they are rooted correctly.</li>
<li>Fixed a bug when starting the server manager and it tries to download steamcmd, but fails as steamcmd is unavailable for download.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:F8A08616-749B-48E7-87D5-D97E86AB3926</id>
<title>1.1.56 (1.1.56.6)</title>
<summary>1.1.56.6</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>
A new Discord Bot has been added to the server manager.<br/>
This new discord bot will allow you to send <font color="#0094FF">Start, Stop, Shutdown, Restart, Backup and Update</font> commands to the server manager from within your discord client.<br/>
To setup the new discord bot, open the global settings and scroll down to the Discord section.<br/><br/>
<font color="#e62919">
NOTE: This is long process to get the discord bot working, and I have created a forum post with detailed instructions how to do it.
</font>
</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Global Settings - Added reset button to the Data Directory Location.</li>
<li>Server Monitor window now stores it's location.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:A3A790A9-D511-4CE8-AC15-A36B3DAB4385</id>

View file

@ -5,144 +5,165 @@
<title>Conan Server Manager Version Feed</title>
<subtitle>This is the Conan Server Manager beta version feed.</subtitle>
<link href="http://servermanagers.freeforums.net/" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-17T00:00:00Z</updated>
<entry>
<id>urn:uuid:4C15C7A9-317C-4A9B-B426-6E885B918D3B</id>
<title>1.1.56 (1.1.56.6)</title>
<summary>1.1.56.6</summary>
<id>urn:uuid:9A427D82-9904-44F5-8C1E-7C943049869A</id>
<title>1.1.58 (1.1.58.7)</title>
<summary>1.1.58.7</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Reference library updates.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:126E8E9F-7FF2-4239-88D6-5FFC89925463</id>
<title>1.1.56 (1.1.56.5)</title>
<summary>1.1.56.5</summary>
<link href="" />
<updated>2021-12-10T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Server Monitor window now stores it's location.</li>
<li>Reference library updates.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:BECA74AB-1107-40B0-932A-A851E978EABF</id>
<title>1.1.56 (1.1.56.4)</title>
<summary>1.1.56.4</summary>
<link href="" />
<updated>2021-12-09T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed a minor issue when clicking the data directory reset button - fringe case that I found during testing.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:8C834060-F20F-4ACE-8F49-0B459531BA3C</id>
<title>1.1.56 (1.1.56.3)</title>
<summary>1.1.56.3</summary>
<link href="" />
<updated>2021-12-08T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed language translation of Data Directory window.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:339F72FC-920A-4425-AF86-AF9B34611A21</id>
<title>1.1.56 (1.1.56.2)</title>
<summary>1.1.56.2</summary>
<link href="" />
<updated>2021-12-08T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Global Settings - Added reset button to the Data Directory Location.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:F8A08616-749B-48E7-87D5-D97E86AB3926</id>
<title>1.1.56 (1.1.56.1)</title>
<summary>1.1.56.1</summary>
<link href="" />
<updated>2021-12-06T00:00:00Z</updated>
<updated>2021-12-17T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>
A new Discord Bot has been added to the server manager.<br/>
This new discord bot will allow you to send <font color="#0094FF">Start, Stop, Shutdown, Restart, Backup and Update</font> commands to the server manager from within your discord client.<br/>
To setup the new discord bot, open the global settings and scroll down to the Discord section.<br/><br/>
<font color="#e62919">
NOTE: This is long process to get the discord bot working, and I have created a forum post with detailed instructions how to do it.
</font>
</li>
<li>Main Window - Added Discord Bot Status and a button to Stop/Start the discord bot.</li>
<li>Global Settings - Discord Bot section - Added a checkbox to allow all bots.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:A189668E-DA03-471A-9C5A-7FF2A7264F9C</id>
<title>1.1.58 (1.1.58.6)</title>
<summary>1.1.58.6</summary>
<link href="" />
<updated>2021-12-17T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Added additional message logging when log level set to debug.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:A189668E-DA03-471A-9C5A-7FF2A7264F9C</id>
<title>1.1.58 (1.1.58.5)</title>
<summary>1.1.58.5</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Global Settings - Discord Bot section - Added a log level droplist.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:F3C22842-A089-46F7-AB1A-5D3DED105412</id>
<title>1.1.58 (1.1.58.4)</title>
<summary>1.1.58.4</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed a bug that would prevent a bot on the whitelist processing the message.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:F3C22842-A089-46F7-AB1A-5D3DED105412</id>
<title>1.1.58 (1.1.58.3)</title>
<summary>1.1.58.3</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Server Settings - Discord Bot section - Added an alias that can be used with the discord command instead of the profile id.</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Removed the mandatory requirement to enter the '!' after the discord prefix. The '!' has been added to the existing prefix so no change to existing functionality, but you can now change it.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:C566D9D2-3566-46DF-8AD4-39F5FC0FFEF2</id>
<title>1.1.58 (1.1.58.2)</title>
<summary>1.1.58.2</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Global Settings - Discord Bot section - Added a whitelist to allow bots to send commands to the server manager.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:19B09A66-43F2-4D5F-AF33-5C77D7EA9A6B</id>
<title>1.1.58 (1.1.58.1)</title>
<summary>1.1.58.1</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Made changes to the code to help improve performance.</li>
</ul>
</p>
</div>

View file

@ -57,12 +57,21 @@
<sys:String x:Key="ProcessorAffinity_All">All</sys:String>
<!--#endregion-->
<!--#region Processor Window States -->
<!--#region Window States -->
<sys:String x:Key="WindowState_Normal">Normal</sys:String>
<sys:String x:Key="WindowState_Minimized">Minimized</sys:String>
<sys:String x:Key="WindowState_Maximized">Maximized</sys:String>
<!--#endregion-->
<!--#region Discord Bot Log Levels -->
<sys:String x:Key="DiscordBotLogLevel_Critical">Critical</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Error">Error</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Warning">Warning</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Info">Info</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Verbose">Verbose</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Debug">Debug</sys:String>
<!--#endregion-->
<!--#region Unit strings -->
<sys:String x:Key="SliderUnits_Multiplier">x</sys:String>
<sys:String x:Key="SliderUnits_Percentage">%</sys:String>
@ -120,6 +129,7 @@
<sys:String x:Key="AutoUpdater_Status_DownloadNewServerComplete">Server download complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Complete">Complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Cancelled">Cancelled</sys:String>
<sys:String x:Key="AutoUpdater_Status_Failed">Failed</sys:String>
<sys:String x:Key="AutoUpdater_CancelButtonLabel">Cancel</sys:String>
<!--#endregion-->
@ -605,12 +615,18 @@
<sys:String x:Key="MainWindow_AutoUpdateTaskEnableLabel">Enable</sys:String>
<sys:String x:Key="MainWindow_AutoUpdateTaskEnableTooltip">Enable the auto-update scheduled task</sys:String>
<sys:String x:Key="MainWindow_TaskRunTimeLabel">Next Run Time:</sys:String>
<sys:String x:Key="MainWindow_DiscordBotStatusLabel">Discord Bot:</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStartLabel">Start</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStartTooltip">Start the discord bot</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStopLabel">Stop</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStopTooltip">Stop the discord bot</sys:String>
<sys:String x:Key="MainWindow_TaskStateUnknownLabel">Unknown</sys:String>
<sys:String x:Key="MainWindow_TaskStateDisabledLabel">Disabled</sys:String>
<sys:String x:Key="MainWindow_TaskStateQueuedLabel">Queued</sys:String>
<sys:String x:Key="MainWindow_TaskStateReadyLabel">Ready</sys:String>
<sys:String x:Key="MainWindow_TaskStateRunningLabel">Running</sys:String>
<sys:String x:Key="MainWindow_TaskStateStoppedLabel">Stopped</sys:String>
<sys:String x:Key="MainWindow_ProfileLoad_FailedTitle">Profile failed to load</sys:String>
<sys:String x:Key="MainWindow_ProfileLoad_FailedLabel">The profile at {0} failed to load. The error was: {1}\r\n{2}</sys:String>
@ -779,8 +795,17 @@
<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_DiscordBotLogLevelLabel">Log Level:</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="ServerSettings_DiscordBotAllowAllBotsLabel">Allow All Bots</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotAllowAllBotsTooltip">If enabled, the server manager bot will respond to all other bots, otherwise they will be ignored unless they are in the whitelist.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistLabel">Bot Whitelist</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdLabel">Bot ID</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdTooltip">The id of the bot to whitelist.</sys:String>
<sys:String x:Key="ServerSettings_AddDiscordBotWhitelistTooltip">Add Whitelist</sys:String>
<sys:String x:Key="ServerSettings_ClearDiscordBotWhitelistTooltip">Clear Whitelists</sys:String>
<sys:String x:Key="ServerSettings_RemoveDiscordBotWhitelistTooltip">Delete Whitelist</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>
@ -1147,6 +1172,8 @@
<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_DiscordAliasLabel">Alias:</sys:String>
<sys:String x:Key="ServerSettings_DiscordAliasTooltip">A unique name to identify your server when using the discord commands, can be used instead of the profile id.</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>
@ -1244,8 +1271,9 @@
<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_ProfileMissing">The '{0}' command requires a profile id or alias.</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_ProfileMultiples">Multiple profiles with '{0}' were found in the channel, command aborted.</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>

View file

@ -1 +1 @@
1.1.56.6
1.1.58.7

Binary file not shown.

View file

@ -120,6 +120,7 @@
<sys:String x:Key="AutoUpdater_Status_DownloadNewServerComplete">Server download complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Complete">Complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Cancelled">Cancelled</sys:String>
<sys:String x:Key="AutoUpdater_Status_Failed">Failed</sys:String>
<sys:String x:Key="AutoUpdater_CancelButtonLabel">Cancel</sys:String>
<!--#endregion-->
@ -628,6 +629,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 +772,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>
@ -815,6 +836,8 @@
<sys:String x:Key="GlobalSettings_DataDirectoryChange_ConfirmLabel">Changing the data directory will move any existing profiles to the new location, but it will not move any server installations. Do you still want to change this directory?</sys:String>
<sys:String x:Key="GlobalSettings_DataDirectoryChange_FailedTitle">Failed to change data directory</sys:String>
<sys:String x:Key="GlobalSettings_DataDirectoryChange_FailedLabel">There was an error changing the data directory: {0}\r\nPlease correct the error and try again, or contact technical support for assistance.</sys:String>
<sys:String x:Key="GlobalSettings_ResetDataDirectory_ConfirmTitle">Confirm Data Directory Reset</sys:String>
<sys:String x:Key="GlobalSettings_ResetDataDirectory_ConfirmLabel">Click 'Yes' to confirm you want to reset the location of the data directory. Once reset, the server manager will shutdown and you will need to restart.</sys:String>
<sys:String x:Key="GlobalSettings_DataDirectoryTitle">Select Backup Directory</sys:String>
<sys:String x:Key="GlobalSettings_CacheDirectoryTitle">Select Cache Directory</sys:String>
@ -1121,6 +1144,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 +1234,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>

Binary file not shown.

View file

@ -1 +1 @@
1.1.55
1.1.57

Binary file not shown.

View file

@ -2,7 +2,7 @@
"Application": "ark",
"Version": "1.0.0",
"Created": "2020-03-04T00:00:00.0000000Z",
"Mod": "ArkPrime|TheCenter|PrimitivePlus|ScorchedEarth|Ragnarok|Aberration|Extinction|Genesis|CrystalIsles|Genesis2|LostIsland|<modid>",
"Mod": "ArkPrime|TheCenter|PrimitivePlus|ScorchedEarth|Ragnarok|Aberration|Extinction|Genesis|Valguero|CrystalIsles|Genesis2|LostIsland|<modid>",
"Creatures": [
{
"NameTag": "Achatina",

View file

@ -5,7 +5,39 @@
<title>Discord Plugin Version Feed</title>
<subtitle>This is the Discord Plugin release version feed.</subtitle>
<link href="" />
<updated>2021-12-03T00:00:00Z</updated>
<updated>2021-12-12T00:00:00Z</updated>
<entry>
<id>urn:uuid:A9EC2F32-E026-485F-BD7B-C657DBA95B54</id>
<title>1.0.19 (1.0.19.5)</title>
<summary>1.0.19.5</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed alert test message to support globalization.</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Changed the plugin initialization so it throws an exception if unable to load config file, rather than creating a new config file.</li>
<li>de-DE Translation file updated.</li>
<li>fr-FR Translation file added.</li>
<li>pt-BR Translation file updated.</li>
<li>ru-RU Translation file added.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:C01A4AA0-D839-4732-9814-301DAC6EB094</id>

View file

@ -7,6 +7,52 @@
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<entry>
<id>urn:uuid:A0D7BFD2-F2F0-481A-A22D-3C193BFB4C99</id>
<title>1.0.19 (1.0.19.5)</title>
<summary>1.0.19.5</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>ru-RU Translation file updated.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:38A61493-CA4E-479E-A3FD-266565E83D90</id>
<title>1.0.19 (1.0.19.4)</title>
<summary>1.0.19.4</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>ru-RU Translation file added.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:DDB25735-1D20-4580-B5FE-1AD4BD107376</id>
<title>1.0.19 (1.0.19.3)</title>

View file

@ -1 +1 @@
1.0.19.3
1.0.19.5

Binary file not shown.

View file

@ -118,6 +118,8 @@
<sys:String x:Key="ConfigProfileWindow_TestErrorTitle">Test Action Error</sys:String>
<sys:String x:Key="ConfigProfileWindow_TestErrorLabel">An error occurred while trying to test the config profile.</sys:String>
<sys:String x:Key="ConfigProfileWindow_TestEnabledErrorLabel">The profile is not enabled and cannot be tested.</sys:String>
<sys:String x:Key="ConfigProfileWindow_TestAlertMessage">Test '{0}' alert type message for profile name '{1}'</sys:String>
<!--#endregion-->
<!--#region Version Feed Window -->

View file

@ -1 +1 @@
1.0.18
1.0.19

Binary file not shown.

View file

@ -145,7 +145,6 @@
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Management" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Numerics" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />

View file

@ -353,6 +353,9 @@
<setting name="DiscordBotHelpUrl" serializeAs="String">
<value>https://arkservermanager.freeforums.net/thread/8764/get-own-discord-bot</value>
</setting>
<setting name="DiscordBotStatusCheckTime" serializeAs="String">
<value>10</value>
</setting>
</ServerManagerTool.Config>
<ServerManagerTool.Common.CommonConfig>
<setting name="DefaultSteamAPIKey" serializeAs="String">
@ -814,7 +817,7 @@
<value>False</value>
</setting>
<setting name="DiscordBotPrefix" serializeAs="String">
<value>asm</value>
<value>asm!</value>
</setting>
<setting name="DiscordBotToken" serializeAs="String">
<value />
@ -849,6 +852,20 @@
<setting name="ServerMonitorWindow_Top" serializeAs="String">
<value>50</value>
</setting>
<setting name="DiscordBotWhitelist" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</value>
</setting>
<setting name="DiscordBotPrefixFixed" serializeAs="String">
<value>False</value>
</setting>
<setting name="DiscordBotLogLevel" serializeAs="String">
<value>Info</value>
</setting>
<setting name="DiscordBotAllowAllBots" serializeAs="String">
<value>False</value>
</setting>
</ServerManagerTool.Config>
</userSettings>
</configuration>

View file

@ -11,6 +11,7 @@ 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;
@ -38,7 +39,7 @@ namespace ServerManagerTool
public event PropertyChangedEventHandler PropertyChanged;
private CancellationTokenSource _tokenSource;
private CancellationTokenSource _tokenSourceDiscordBot;
private GlobalizedApplication _globalizer;
private bool _applicationStarted;
private string _args;
@ -49,7 +50,45 @@ namespace ServerManagerTool
public App()
{
if (string.IsNullOrWhiteSpace(Config.Default.ASMUniqueKey))
{
Config.Default.ASMUniqueKey = Guid.NewGuid().ToString();
}
if (!string.IsNullOrWhiteSpace(Config.Default.DataDir))
{
var root = Path.GetPathRoot(Config.Default.DataDir);
if (!root.EndsWith("\\"))
{
Config.Default.DataDir = Config.Default.DataDir.Replace(root, root + "\\");
}
}
if (!string.IsNullOrWhiteSpace(Config.Default.ConfigDirectory))
{
var root = Path.GetPathRoot(Config.Default.ConfigDirectory);
if (!root.EndsWith("\\"))
{
Config.Default.ConfigDirectory = Config.Default.ConfigDirectory.Replace(root, root + "\\");
}
}
if (!string.IsNullOrWhiteSpace(Config.Default.BackupPath))
{
var root = Path.GetPathRoot(Config.Default.BackupPath);
if (!root.EndsWith("\\"))
{
Config.Default.BackupPath = Config.Default.BackupPath.Replace(root, root + "\\");
}
}
if (!string.IsNullOrWhiteSpace(Config.Default.AutoUpdate_CacheDir))
{
var root = Path.GetPathRoot(Config.Default.AutoUpdate_CacheDir);
if (!root.EndsWith("\\"))
{
Config.Default.AutoUpdate_CacheDir = Config.Default.AutoUpdate_CacheDir.Replace(root, root + "\\");
}
}
App.Instance = this;
ApplicationStarted = false;
@ -112,6 +151,18 @@ namespace ServerManagerTool
}
}
public bool DiscordBotStarted
{
get
{
return _tokenSourceDiscordBot != null;
}
set
{
OnPropertyChanged();
}
}
public string Title
{
get
@ -246,6 +297,14 @@ namespace ServerManagerTool
CommonConfig.Default.Save();
}
}
if (!Config.Default.DiscordBotPrefixFixed)
{
if (!Config.Default.DiscordBotPrefix.EndsWith("!"))
Config.Default.DiscordBotPrefix += "!";
Config.Default.DiscordBotPrefixFixed = true;
Config.Default.Save();
Config.Default.Reload();
}
Config.Default.SteamCmdRedirectOutput = false;
}
@ -451,21 +510,7 @@ namespace ServerManagerTool
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);
StartDiscordBot();
}
}
@ -507,11 +552,7 @@ namespace ServerManagerTool
private void ShutDownApplication()
{
if (!(_tokenSource is null))
{
_tokenSource.Cancel();
_tokenSource.Dispose();
}
StopDiscordBot();
if (ApplicationStarted)
{
@ -544,13 +585,68 @@ namespace ServerManagerTool
var installFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var backupFolder = includeBackup
? IOUtils.NormalizePath(string.IsNullOrWhiteSpace(Config.Default.BackupPath)
? string.IsNullOrWhiteSpace(Config.Default.BackupPath)
? Path.Combine(Config.Default.DataDir, Config.Default.BackupDir)
: Path.Combine(Config.Default.BackupPath))
: Path.Combine(Config.Default.BackupPath)
: null;
SettingsUtils.BackupUserConfigSettings(Config.Default, "userconfig.json", installFolder, backupFolder);
SettingsUtils.BackupUserConfigSettings(CommonConfig.Default, "commonconfig.json", installFolder, backupFolder);
}
public void StartDiscordBot()
{
if (_tokenSourceDiscordBot != null)
{
return;
}
_tokenSourceDiscordBot = new CancellationTokenSource();
DiscordBotStarted = true;
Task discordTask = Task.Run(async () =>
{
var discordWhiteList = new List<string>();
if (Config.Default.DiscordBotWhitelist != null)
{
discordWhiteList.AddRange(Config.Default.DiscordBotWhitelist.Cast<string>());
}
await ServerManagerBotFactory.GetServerManagerBot()?.StartAsync(Config.Default.DiscordBotLogLevel, Config.Default.DiscordBotToken, Config.Default.DiscordBotPrefix, Config.Default.DataDir, Config.Default.DiscordBotAllowAllBots, discordWhiteList, DiscordBotHelper.HandleDiscordCommand, DiscordBotHelper.HandleTranslation, _tokenSourceDiscordBot.Token);
if (_tokenSourceDiscordBot != null)
{
// cleanup the token
_tokenSourceDiscordBot.Dispose();
_tokenSourceDiscordBot = null;
}
DiscordBotStarted = false;
}, _tokenSourceDiscordBot.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);
if (_tokenSourceDiscordBot != null)
{
// cleanup the token
_tokenSourceDiscordBot.Dispose();
_tokenSourceDiscordBot = null;
}
DiscordBotStarted = false;
}, TaskContinuationOptions.OnlyOnFaulted);
}
public void StopDiscordBot()
{
if (!(_tokenSourceDiscordBot is null))
{
_tokenSourceDiscordBot.Cancel();
}
}
}
}

View file

@ -2827,7 +2827,7 @@ namespace ServerManagerTool {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("asm")]
[global::System.Configuration.DefaultSettingValueAttribute("asm!")]
public string DiscordBotPrefix {
get {
return ((string)(this["DiscordBotPrefix"]));
@ -2986,5 +2986,63 @@ namespace ServerManagerTool {
this["ServerMonitorWindow_Top"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<ArrayOfString xmlns:xsd=\"http://www.w3." +
"org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" />")]
public global::System.Collections.Specialized.StringCollection DiscordBotWhitelist {
get {
return ((global::System.Collections.Specialized.StringCollection)(this["DiscordBotWhitelist"]));
}
set {
this["DiscordBotWhitelist"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool DiscordBotPrefixFixed {
get {
return ((bool)(this["DiscordBotPrefixFixed"]));
}
set {
this["DiscordBotPrefixFixed"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Info")]
public global::ServerManagerTool.DiscordBot.Enums.LogLevel DiscordBotLogLevel {
get {
return ((global::ServerManagerTool.DiscordBot.Enums.LogLevel)(this["DiscordBotLogLevel"]));
}
set {
this["DiscordBotLogLevel"] = value;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("10")]
public int DiscordBotStatusCheckTime {
get {
return ((int)(this["DiscordBotStatusCheckTime"]));
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool DiscordBotAllowAllBots {
get {
return ((bool)(this["DiscordBotAllowAllBots"]));
}
set {
this["DiscordBotAllowAllBots"] = value;
}
}
}
}

View file

@ -783,7 +783,7 @@
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="DiscordBotPrefix" Type="System.String" Scope="User">
<Value Profile="(Default)">asm</Value>
<Value Profile="(Default)">asm!</Value>
</Setting>
<Setting Name="DiscordBotToken" Type="System.String" Scope="User">
<Value Profile="(Default)" />
@ -824,5 +824,21 @@
<Setting Name="ServerMonitorWindow_Top" Type="System.Double" Scope="User">
<Value Profile="(Default)">50</Value>
</Setting>
<Setting Name="DiscordBotWhitelist" Type="System.Collections.Specialized.StringCollection" Scope="User">
<Value Profile="(Default)">&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /&gt;</Value>
</Setting>
<Setting Name="DiscordBotPrefixFixed" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="DiscordBotLogLevel" Type="ServerManagerTool.DiscordBot.Enums.LogLevel" Scope="User">
<Value Profile="(Default)">Info</Value>
</Setting>
<Setting Name="DiscordBotStatusCheckTime" Type="System.Int32" Scope="Application">
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="DiscordBotAllowAllBots" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>

View file

@ -8,8 +8,9 @@
AutoShutdown1,
AutoShutdown2,
Backup,
Shutdown,
Restart,
Shutdown,
Stop,
Update,
}
}

View file

@ -13406,6 +13406,10 @@
{
"ModId": "CrystalIsles",
"ModName": "Crystal Isles"
},
{
"ModId": "LostIsland",
"ModName": "Lost Island"
}
]
}

View file

@ -83,12 +83,21 @@
<sys:String x:Key="ProcessorAffinity_All">All</sys:String>
<!--#endregion-->
<!--#region Processor Window States -->
<!--#region Window States -->
<sys:String x:Key="WindowState_Normal">Normal</sys:String>
<sys:String x:Key="WindowState_Minimized">Minimized</sys:String>
<sys:String x:Key="WindowState_Maximized">Maximized</sys:String>
<!--#endregion-->
<!--#region Discord Bot Log Levels -->
<sys:String x:Key="DiscordBotLogLevel_Critical">Critical</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Error">Error</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Warning">Warning</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Info">Info</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Verbose">Verbose</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Debug">Debug</sys:String>
<!--#endregion-->
<!--#region Application -->
<sys:String x:Key="Application_RunAsAdministratorTitle">Run as Administrator</sys:String>
<sys:String x:Key="Application_RunAsAdministratorLabel">This application requires administration priviledges to access ALL functionality. Would you like to Run as Administrator?</sys:String>
@ -127,6 +136,7 @@
<sys:String x:Key="AutoUpdater_Status_DownloadNewServerComplete">Server download complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Complete">Complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Cancelled">Cancelled</sys:String>
<sys:String x:Key="AutoUpdater_Status_Failed">Failed</sys:String>
<sys:String x:Key="AutoUpdater_CancelButtonLabel">Cancel</sys:String>
<!--#endregion-->
@ -621,8 +631,17 @@
<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_DiscordBotLogLevelLabel">Log Level:</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="ServerSettings_DiscordBotAllowAllBotsLabel">Allow All Bots</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotAllowAllBotsTooltip">If enabled, the server manager bot will respond to all other bots, otherwise they will be ignored unless they are in the whitelist.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistLabel">Bot Whitelist</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdLabel">Bot ID</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdTooltip">The id of the bot to whitelist.</sys:String>
<sys:String x:Key="ServerSettings_AddDiscordBotWhitelistTooltip">Add Whitelist</sys:String>
<sys:String x:Key="ServerSettings_ClearDiscordBotWhitelistTooltip">Clear Whitelists</sys:String>
<sys:String x:Key="ServerSettings_RemoveDiscordBotWhitelistTooltip">Delete Whitelist</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>
@ -773,12 +792,18 @@
<sys:String x:Key="MainWindow_AutoUpdateTaskEnableLabel">Enable</sys:String>
<sys:String x:Key="MainWindow_AutoUpdateTaskEnableTooltip">Enable the auto-update scheduled task</sys:String>
<sys:String x:Key="MainWindow_TaskRunTimeLabel">Next Run Time:</sys:String>
<sys:String x:Key="MainWindow_DiscordBotStatusLabel">Discord Bot:</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStartLabel">Start</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStartTooltip">Start the discord bot</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStopLabel">Stop</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStopTooltip">Stop the discord bot</sys:String>
<sys:String x:Key="MainWindow_TaskStateUnknownLabel">Unknown</sys:String>
<sys:String x:Key="MainWindow_TaskStateDisabledLabel">Disabled</sys:String>
<sys:String x:Key="MainWindow_TaskStateQueuedLabel">Queued</sys:String>
<sys:String x:Key="MainWindow_TaskStateReadyLabel">Ready</sys:String>
<sys:String x:Key="MainWindow_TaskStateRunningLabel">Running</sys:String>
<sys:String x:Key="MainWindow_TaskStateStoppedLabel">Stopped</sys:String>
<sys:String x:Key="MainWindow_ProfileLoad_FailedTitle">Profile failed to load</sys:String>
<sys:String x:Key="MainWindow_ProfileLoad_FailedLabel">The profile at {0} failed to load. The error was: {1}\r\n{2}</sys:String>
@ -1207,6 +1232,8 @@
<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_DiscordAliasLabel">Alias:</sys:String>
<sys:String x:Key="ServerSettings_DiscordAliasTooltip">A unique name to identify your server when using the discord commands, can be used instead of the profile id.</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>
@ -5495,6 +5522,23 @@
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Easy_C">Boss Inventory - Crystal Wyvern Queen (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Medium_C">Boss Inventory - Crystal Wyvern Queen (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Hard_C">Boss Inventory - Crystal Wyvern Queen (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Ragnarok_C">Boss Inventory - Dragon (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Ragnarok_C">Boss Inventory - Dragon (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Hard_Ragnarok_C">Boss Inventory - Dragon (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Easy_Ragnarok_C">Boss Inventory - Manticore (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Medium_Ragnarok_C">Boss Inventory - Manticore (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Hard_Ragnarok_C">Boss Inventory - Manticore (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Valguero_C">Boss Inventory - Dragon (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Valguero_C">Boss Inventory - Dragon (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Hard_Valguero_C">Boss Inventory - Dragon (Hard)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Easy_Valguero_C">Boss Inventory - Manticore (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Medium_Valguero_C">Boss Inventory - Manticore (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Hard_Valguero_C">Boss Inventory - Manticore (Hard)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Easy_Valguero_C">Boss Inventory - Megapithecus (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Medium_Valguero_C">Boss Inventory - Megapithecus (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Hard_Valguero_C">Boss Inventory - Megapithecus (Hard)</sys:String>
<!--#endregion-->
<!--#endregion-->
@ -5580,8 +5624,9 @@
<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_ProfileMissing">The '{0}' command requires a profile id or alias.</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_ProfileMultiples">Multiple profiles with '{0}' were found in the channel, command aborted.</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>

View file

@ -24,6 +24,7 @@
<sys:String x:Key="Map_Genesis">Genesis</sys:String>
<sys:String x:Key="Map_CrystalIsles">Crystal Isles</sys:String>
<sys:String x:Key="Map_Gen2">Genesis: Part 2</sys:String>
<sys:String x:Key="Map_LostIsland">Lost Island</sys:String>
<!--#endregion-->
<!--#region Total Conversion Names -->
@ -44,8 +45,8 @@
<!--#endregion-->
<!--#region Mod Names -->
<sys:String x:Key="Mod_All">All</sys:String>
<sys:String x:Key="Mod_Unknown">Unknown</sys:String>
<sys:String x:Key="Mod_All">Tout</sys:String>
<sys:String x:Key="Mod_Unknown">Inconnu</sys:String>
<sys:String x:Key="Mod_ArkPrime">ARK Prime</sys:String>
<sys:String x:Key="Mod_TheCenter">The Center</sys:String>
<sys:String x:Key="Mod_PrimitivePlus">Primitive Plus</sys:String>
@ -56,6 +57,7 @@
<sys:String x:Key="Mod_Genesis">Genesis</sys:String>
<sys:String x:Key="Mod_CrystalIsles">Crystal Isles</sys:String>
<sys:String x:Key="Mod_Genesis2">Genesis: Part 2</sys:String>
<sys:String x:Key="Mod_LostIsland">Lost Island</sys:String>
<sys:String x:Key="Mod_PGM">PGM</sys:String>
<!--#endregion-->
@ -610,6 +612,23 @@
<sys:String x:Key="GlobalSettings_ShutdownCancelTooltip">Ce message sera affiché lorsque la fermeture du serveur a été annulée.</sys:String>
<sys:String x:Key="GlobalSettings_ShutdownAllMessagesShowReasonLabel">Afficher le motif d'arrêt avec TOUS les messages d'arrêt</sys:String>
<sys:String x:Key="GlobalSettings_ShutdownAllMessagesShowReasonTooltip">Si elle est activée, la raison de l'arrêt s'affichera avec tous les messages d'arrêt; sinon, il ne sera affiché qu'au début de l'arrêt du serveur.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotLabel">Activer le Bot Discord</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotInformationLabel">Vous devrez redémarrer le gestionnaire de serveur si vous modifiez les paramètres du Bot Discord..</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotTokenLabel">Token:</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotTokenTooltip">Le token associé au bot discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotServerLabel">ID Serveur:</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotServerTooltip">L'ID du serveur que le Bot discord écoutera.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotPrefixLabel">Prefixe:</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotPrefixTooltip">Le préfixe qui doit être utilisé lors de l'envoi d'une commande via discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotApplyButtonLabel">Faire desToken...</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotHelpButtonLabel">Help...</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowBackupTooltip">Si activé, la commande de sauvegarde peut être envoyée du Discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowRestartTooltip">Si activé, la commande de redémarrage peut être envoyée du discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowShutdownTooltip">Si activé, la commande d'arrêt peut être envoyée du discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowStartTooltip">Si activé, la commande de démarrage peut être envoyée du discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowStopTooltip">Si activé, la commande stop peut être envoyée du discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowUpdateTooltip">Si activé, la commande de mise à jour peut être envoyée du discord.</sys:String>
<sys:String x:Key="GlobalSettings_EmailSettingsLabel">Paramètres de messagerie SMTP</sys:String>
<sys:String x:Key="GlobalSettings_EmailHostLabel">Host:</sys:String>
@ -662,6 +681,8 @@
<sys:String x:Key="GlobalSettings_DataDirectoryChange_ConfirmLabel">La modification du répertoire de données déplacera tous les profils existants vers le nouvel emplacement, mais ne déplacera aucune installation de serveur. Voulez-vous toujours changer ce répertoire?</sys:String>
<sys:String x:Key="GlobalSettings_DataDirectoryChange_FailedTitle">Échec de la modification du répertoire de données</sys:String>
<sys:String x:Key="GlobalSettings_DataDirectoryChange_FailedLabel">Une erreur s'est produite lors de la modification du répertoire de données: {0}\r\nVeuillez corriger l'erreur et réessayer, ou contactez le support technique pour obtenir de l'aide.</sys:String>
<sys:String x:Key="GlobalSettings_ResetDataDirectory_ConfirmTitle">Confirmer la réinitialisation du répertoire de données</sys:String>
<sys:String x:Key="GlobalSettings_ResetDataDirectory_ConfirmLabel">Cliquez sur "Oui" pour confirmer que vous souhaitez réinitialiser l'emplacement du répertoire de données. Une fois réinitialisé, le gestionnaire de serveur va arrêter et vous devrez redémarrer.</sys:String>
<sys:String x:Key="GlobalSettings_DataDirectoryTitle">Sélectionnez le répertoire de sauvegarde</sys:String>
<sys:String x:Key="GlobalSettings_CacheDirectoryTitle">Sélectionnez le répertoire du cache</sys:String>
@ -775,6 +796,9 @@
<sys:String x:Key="MainWindow_SteamCmd_FailedTitle">Erreur lors de la réinstallation de SteamCMD</sys:String>
<sys:String x:Key="MainWindow_SteamCmd_FailedLabel">Une erreur est survenue lors de la réinstallation de SteamCMD. Cela a laissé SteamCmd dans un état instable, essayez de le réinstaller à nouveau ou signalez-le.\r\nException: {0}</sys:String>
<sys:String x:Key="MainWindow_DiscordBot_RunningCommandsTitle">Discord Bot Exécute des commandes</sys:String>
<sys:String x:Key="MainWindow_DiscordBot_RunningCommandsLabel">Le Bot discord à une ou plusieurs commandes en cours d'exécution, voulez-vous continuer à arrêter le gestionnaire de serveur? </sys:String>
<sys:String x:Key="MainWindow_ServerStatus_StartServerActionTitle">Confirmer le démarage du serveur</sys:String>
<sys:String x:Key="MainWindow_ServerStatus_StartServerActionLabel">Vous êtes sur le point de démarrer le serveur, voulez-vous continuer?</sys:String>
<sys:String x:Key="MainWindow_ServerStatus_ShutdownServerActionTitle">Confirmer l'arrêt du serveur</sys:String>
@ -1178,6 +1202,24 @@
<sys:String x:Key="ServerSettings_RestartIfShutdownLabel">Redémarrer le serveur en cas d'arrêt</sys:String>
<sys:String x:Key="ServerSettings_RestartIfShutdownTooltip">Si cette option est activée, le serveur sera redémarré même s'il est arrêté pour les redémarrages automatiques et les mises à jour automatiques.</sys:String>
<!--#endregion-->
<!--#region Server Settings - Discord Bot Details -->
<sys:String x:Key="ServerSettings_DiscordBotLabel">Détail du bot Discord</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotChannelLabel">Id DU canal:</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotChannelTooltip">L'ID du canal de Discord Server que ce profil écoutera.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordBackupLabel">Autoriser la sauvegarde</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordBackupTooltip">Si activé, le profil écoutera les commandes de sauvegarde de discord.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordRestartLabel">Autoriser le redémarrage</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordRestartTooltip">Si activé, le profil écoutera les commandes de redémarrage de discord.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordShutdownLabel">Autoriser l'arrêt</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordShutdownTooltip">Si activé, le profil écoutera les commandes d'arrêt de discord.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordStartLabel">Autoriser le démarrage</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordStartTooltip">Si activé, le profil écoutera les commandes de démarrage de discord.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordStopLabel">Autoriser l'arrêt</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordStopTooltip">Si activé, le profil écoutera les commandes d'arrêt de discord.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordUpdateLabel">Autoriser la mise à jour</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordUpdateTooltip">Si activé, le profil écoutera les commandes de mise à jour de discord.</sys:String>
<!--#endregion-->
<!--#region Server Settings - Rules -->
<sys:String x:Key="ServerSettings_RulesLabel">Règles</sys:String>
@ -1598,12 +1640,16 @@
<sys:String x:Key="ServerSettings_TamedDinoPerLevelStatAddMultipliersLabel">Multiplicateurs de statistiques par niveau (apprivoisés) - Ajouter</sys:String>
<sys:String x:Key="ServerSettings_TamedDinoPerLevelStatAffinityMultipliersLabel">Multiplicateurs de statistiques par niveau (apprivoisés)- Affinité</sys:String>
<sys:String x:Key="ServerSettings_WildDinoPerLevelStatMultipliersLabel">Multiplicateurs de statistiques par niveau (sauvage)</sys:String>
<sys:String x:Key="ServerSettings_DinoWildMutagenLevelBoostLabel">Boost de niveau mutagène (sauvage)</sys:String>
<sys:String x:Key="ServerSettings_DinoBredMutagenLevelBoostLabel">Boost de niveau mutagène (élevée)</sys:String>
<sys:String x:Key="ServerSettings_DinoBreedingMultipliersLabel">Multiplicateurs d'élevage de dinosaures</sys:String>
<sys:String x:Key="ServerSettings_BaseStatMultipliersTooltip">Si activé, permet d'appliquer des facteurs d'échelle à chaque statistique de base.</sys:String>
<sys:String x:Key="ServerSettings_PerLevelStatMultipliersTooltip">Si activé, permet d'appliquer des facteurs d'échelle à chaque statistique.</sys:String>
<sys:String x:Key="ServerSettings_PerLevelStatTamedAddMultipliersTooltip">Si activé, permet d'appliquer des facteurs d'échelle à l'ajout d'apprivoisement pour chaque statistique.</sys:String>
<sys:String x:Key="ServerSettings_PerLevelStatTamedAffinityMultipliersTooltip">Si activé, permet d'appliquer des facteurs d'échelle au multiplicateur d'apprivoisement pour chaque statistique.</sys:String>
<sys:String x:Key="ServerSettings_PerLevelStatTamedMultipliersTooltip">Si activé, permet d'appliquer des facteurs d'échelle à l'augmentation de la statistique apprivoisée pour chaque statistique.</sys:String>
<sys:String x:Key="ServerSettings_DinoWildMutagenLevelBoostTooltip">Si activé, permet aux facteurs d'échelle d'être appliqués au nombre de niveaux mutagen ajoute aux Tames avec une ascendance sauvage.</sys:String>
<sys:String x:Key="ServerSettings_DinoBredMutagenLevelBoostTooltip">Si activé, permet aux facteurs d'échelle d'être appliqués au nombre de niveaux mutagen ajoute aux Tames avec ascendance élevée.</sys:String>
<sys:String x:Key="ServerSettings_ResetPerLevelStatMultipliersTooltip">Réinitialiser tous les multiplicateurs aux valeurs par défaut.</sys:String>
<sys:String x:Key="ServerSettings_ResetBaseStatMultipliersTooltip">Réinitialiser tous les multiplicateurs aux valeurs par défaut.</sys:String>
@ -5449,6 +5495,23 @@
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Easy_C">Boss Inventory - Crystal Wyvern Queen (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Medium_C">Boss Inventory - Crystal Wyvern Queen (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Hard_C">Boss Inventory - Crystal Wyvern Queen (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Ragnarok_C">Boss Inventory - Dragon (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Ragnarok_C">Boss Inventory - Dragon (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Hard_Ragnarok_C">Boss Inventory - Dragon (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Easy_Ragnarok_C">Boss Inventory - Manticore (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Medium_Ragnarok_C">Boss Inventory - Manticore (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Hard_Ragnarok_C">Boss Inventory - Manticore (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Valguero_C">Boss Inventory - Dragon (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Valguero_C">Boss Inventory - Dragon (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Hard_Valguero_C">Boss Inventory - Dragon (Hard)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Easy_Valguero_C">Boss Inventory - Manticore (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Medium_Valguero_C">Boss Inventory - Manticore (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossManticore_Hard_Valguero_C">Boss Inventory - Manticore (Hard)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Easy_Valguero_C">Boss Inventory - Megapithecus (Easy)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Medium_Valguero_C">Boss Inventory - Megapithecus (Medium)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossGorilla_Hard_Valguero_C">Boss Inventory - Megapithecus (Hard)</sys:String>
<!--#endregion-->
<!--#endregion-->
@ -5523,4 +5586,32 @@
<sys:String x:Key="ServerUpdate_WarningLabel">Un problème est survenu lors de la mise à jour du serveur. Cela peut laisser votre serveur dans un état incomplet.\r\n\r\n Souhaitez-vous continuer le démarrage du serveur, cela pourrait provoquer des problèmes?</sys:String>
<!--#endregion-->
<!--#region Discord Bot -->
<sys:String x:Key="DiscordBot_ErrorTitle">Erreur Bot Discord Bot</sys:String>
<sys:String x:Key="DiscordBot_MissingTokenError">Le bot de la discussion nécessite un Token valide afin qu'il puisse se connecter au serveur de discord\r\nthis peut être défini dans les paramètres globaux..</sys:String>
<sys:String x:Key="DiscordBot_InvalidPrefixError">Le préfixe du Bot discord contient des caractères non valides. Seules les lettres et les chiffres sont autorisés.</sys:String>
<sys:String x:Key="DiscordBot_CommandNotEnabled">Commande '{0}' n'a pas été activée.</sys:String>
<sys:String x:Key="DiscordBot_CommandUnknown">Commande inconnue '{0}'.</sys:String>
<sys:String x:Key="DiscordBot_CommandRunning">Une autre commande est en cours de traitement.</sys:String>
<sys:String x:Key="DiscordBot_CommandRunningProfile">Une autre commande '{0}' fonctionne actuellement contre le profil'{1}'.</sys:String>
<sys:String x:Key="DiscordBot_CommandDisabledProfile">Commande '{0}' a été désactivé pour le profil '{1}'.</sys:String>
<sys:String x:Key="DiscordBot_ProfileMissing">The '{0}' commande nécessite un ID du profil.</sys:String>
<sys:String x:Key="DiscordBot_ProfileNotFound">Profile '{0}' n'a pas été trouvé ou n'est pas associé au canal.</sys:String>
<sys:String x:Key="DiscordBot_ProfileBadStatus">Profile '{0}' est dans un état '{1}' qui ne peut pas exécuter cette commande.</sys:String>
<sys:String x:Key="DiscordBot_ProfileUpdating">Profile '{0}' est actuellement mis à jour.</sys:String>
<sys:String x:Key="DiscordBot_InfoFailed">Appeler au serveur '{0}' a échoué.</sys:String>
<sys:String x:Key="DiscordBot_BackupRequested">Une demande de sauvegarde pour serveur '{0}' a été envoyée.</sys:String>
<sys:String x:Key="DiscordBot_RestartRequested">Une demande de redémarrage de serveur '{0}' a été envoyée.</sys:String>
<sys:String x:Key="DiscordBot_ShutdownRequested">Une demande d'arrêt pour serveur '{0}' a été envoyée.</sys:String>
<sys:String x:Key="DiscordBot_StartRequested">Une demande de démarrage pour le serveur '{0}' a été envoyée.</sys:String>
<sys:String x:Key="DiscordBot_StopRequested">Une demande d'arrêt de serveur '{0}' a été envoyée.</sys:String>
<sys:String x:Key="DiscordBot_UpdateRequested">Une demande de mise à jour du serveur '{0}' a été envoyée.</sys:String>
<sys:String x:Key="DiscordBot_CountLabel">Dénombrer:</sys:String>
<sys:String x:Key="DiscordBot_MapLabel">Map:</sys:String>
<!--#endregion-->
</Globalization:GlobalizationResourceDictionary>

View file

@ -24,6 +24,7 @@
<sys:String x:Key="Map_Genesis">Genesis: Part 1</sys:String>
<sys:String x:Key="Map_CrystalIsles">Crystal Isles</sys:String>
<sys:String x:Key="Map_Gen2">Genesis: Part 2</sys:String>
<sys:String x:Key="Map_LostIsland">Lost Island</sys:String>
<!--#endregion-->
<!--#region Total Conversion Names -->
@ -56,6 +57,7 @@
<sys:String x:Key="Mod_Genesis">Genesis: Part 1</sys:String>
<sys:String x:Key="Mod_CrystalIsles">Crystal Isles</sys:String>
<sys:String x:Key="Mod_Genesis2">Genesis: Part 2</sys:String>
<sys:String x:Key="Mod_LostIsland">Lost Island</sys:String>
<sys:String x:Key="Mod_PGM">PGM</sys:String>
<!--#endregion-->
@ -81,10 +83,19 @@
<sys:String x:Key="ProcessorAffinity_All">Todos</sys:String>
<!--#endregion-->
<!--#region Processor Window States -->
<!--#region Window States -->
<sys:String x:Key="WindowState_Normal">Normal</sys:String>
<sys:String x:Key="WindowState_Minimized">Minimizado</sys:String>
<sys:String x:Key="WindowState_Maximized">Maximizado</sys:String>
<!--#endregion-->
<!--#region Discord Bot Log Levels -->
<sys:String x:Key="DiscordBotLogLevel_Critical">Crítico</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Error">Erro</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Warning">Aviso</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Info">Informações</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Verbose">Verboso</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Debug">Debug</sys:String>
<!--#endregion-->
<!--#region Application -->
@ -125,6 +136,7 @@
<sys:String x:Key="AutoUpdater_Status_DownloadNewServerComplete">Download do servidor concluído</sys:String>
<sys:String x:Key="AutoUpdater_Status_Complete">Completo</sys:String>
<sys:String x:Key="AutoUpdater_Status_Cancelled">Cancelado</sys:String>
<sys:String x:Key="AutoUpdater_Status_Failed">Falhou</sys:String>
<sys:String x:Key="AutoUpdater_CancelButtonLabel">Cancela</sys:String>
<!--#endregion-->
@ -619,8 +631,15 @@
<sys:String x:Key="GlobalSettings_DiscordBotServerTooltip">O id do servidor discord que o bot usará.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotPrefixLabel">Prefix:</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotPrefixTooltip">O prefixo que deve ser usado ao enviar um comando via discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotLogLevelLabel">Nível de registro:</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotApplyButtonLabel">Obter Token...</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotHelpButtonLabel">Ajuda...</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistLabel">Bot Whitelist</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdLabel">Bot ID</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdTooltip">O id do bot a ser colocado na whitelist.</sys:String>
<sys:String x:Key="ServerSettings_AddDiscordBotWhitelistTooltip">Add Whitelist</sys:String>
<sys:String x:Key="ServerSettings_ClearDiscordBotWhitelistTooltip">Limpar Whitelists</sys:String>
<sys:String x:Key="ServerSettings_RemoveDiscordBotWhitelistTooltip">Deletar Whitelist</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowBackupTooltip">Se ativado, o comando de backup pode ser enviado do discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowRestartTooltip">Se ativado, o comando de reiniciar pode ser enviado do discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowShutdownTooltip">Se habilitado, o comando de desligar pode ser enviado do discord.</sys:String>
@ -1205,6 +1224,8 @@
<sys:String x:Key="ServerSettings_DiscordBotLabel">Detalhes do Discord Bot</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotChannelLabel">Id do canal:</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotChannelTooltip">O id do canal do discord que este perfil irá usar.</sys:String>
<sys:String x:Key="ServerSettings_DiscordAliasLabel">Nome exclusivo:</sys:String>
<sys:String x:Key="ServerSettings_DiscordAliasTooltip">Um nome exclusivo para identificar seu servidor ao usar os comandos discord, pode ser usado em vez do ID do perfil.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordBackupLabel">Permitir backup</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordBackupTooltip">Se ativado, o perfil usará os comandos de backup pelo discord.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordRestartLabel">Permitir Reinício</sys:String>
@ -5504,6 +5525,10 @@
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Medium_C">Boss Inventory - Crystal Wyvern Queen (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Hard_C">Boss Inventory - Crystal Wyvern Queen (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDinopith_Easy_C">Boss Inventory - Dinopithecus (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDinopith_Medium_C">Boss Inventory - Dinopithecus (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDinopith_Hard_C">Boss Inventory - Dinopithecus (Alpha)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Ragnarok_C">Boss Inventory - Dragon (Gamma)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Ragnarok_C">Boss Inventory - Dragon (Beta)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Hard_Ragnarok_C">Boss Inventory - Dragon (Alpha)</sys:String>
@ -5597,6 +5622,7 @@
<sys:String x:Key="DiscordBot_ProfileMissing">O comando '{0}' requer um id de perfil.</sys:String>
<sys:String x:Key="DiscordBot_ProfileNotFound">O perfil '{0}' não foi encontrado ou não está associado ao canal.</sys:String>
<sys:String x:Key="DiscordBot_ProfileMultiples">Vários perfis com '{0}' foram encontrados no canal, comando abortado.</sys:String>
<sys:String x:Key="DiscordBot_ProfileBadStatus">O perfil '{0}' está em um estado '{1}' que não pode executar este comando.</sys:String>
<sys:String x:Key="DiscordBot_ProfileUpdating">O perfil '{0}' está sendo atualizado.</sys:String>

View file

@ -9,7 +9,7 @@
<!--#region Generic -->
<sys:String x:Key="Generic_TranslatedByLabel">Последнее обновление:</sys:String>
<sys:String x:Key="Generic_TranslatedBy">09.12.2021 от Varlonec, Эдван</sys:String>
<sys:String x:Key="Generic_TranslatedBy">16.12.2021 от Varlonec, Эдван</sys:String>
<sys:String x:Key="Generic_ErrorLabel">Ошибка</sys:String>
<!--#endregion-->
@ -24,6 +24,7 @@
<sys:String x:Key="Map_Genesis">Genesis: Part 1</sys:String>
<sys:String x:Key="Map_CrystalIsles">Crystal Isles</sys:String>
<sys:String x:Key="Map_Gen2">Genesis: Part 2</sys:String>
<sys:String x:Key="Map_LostIsland">Lost Island</sys:String>
<!--#endregion-->
<!--#region Total Conversion Names -->
@ -56,6 +57,7 @@
<sys:String x:Key="Mod_Genesis">Genesis: Part 1</sys:String>
<sys:String x:Key="Mod_CrystalIsles">Crystal Isles</sys:String>
<sys:String x:Key="Mod_Genesis2">Genesis: Part 2</sys:String>
<sys:String x:Key="Mod_LostIsland">Lost Island</sys:String>
<sys:String x:Key="Mod_PGM">PGM</sys:String>
<!--#endregion-->
@ -87,6 +89,15 @@
<sys:String x:Key="WindowState_Maximized">По максимуму</sys:String>
<!--#endregion-->
<!--#region Discord Bot Log Levels -->
<sys:String x:Key="DiscordBotLogLevel_Critical">Критично</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Error">Ошибка</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Warning">Внимание</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Info">Информация</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Verbose">Многословный</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Debug">Отладка</sys:String>
<!--#endregion-->
<!--#region Application -->
<sys:String x:Key="Application_RunAsAdministratorTitle">Запустить в режиме Администратора.</sys:String>
<sys:String x:Key="Application_RunAsAdministratorLabel">Это приложение требует Административных привилегий для доступа ко всем функциям. Вы хотите запустить как из режима Администратора?</sys:String>
@ -125,6 +136,7 @@
<sys:String x:Key="AutoUpdater_Status_DownloadNewServerComplete">Загрузка сервера завершена</sys:String>
<sys:String x:Key="AutoUpdater_Status_Complete">Завершено</sys:String>
<sys:String x:Key="AutoUpdater_Status_Cancelled">Отменено</sys:String>
<sys:String x:Key="AutoUpdater_Status_Failed">Ошибка</sys:String>
<sys:String x:Key="AutoUpdater_CancelButtonLabel">Отмена</sys:String>
<!--#endregion-->
@ -619,8 +631,15 @@
<sys:String x:Key="GlobalSettings_DiscordBotServerTooltip">Идентификатор сервера Discord, который бот будет слушать.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotPrefixLabel">Префикс:</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotPrefixTooltip">Префикс, который необходимо использовать при отправке команды через Discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotLogLevelLabel">Лог уровня:</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotApplyButtonLabel">Получить токен ...</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotHelpButtonLabel">Помощь...</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistLabel">Белый лист бота</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdLabel">Бот ID</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdTooltip">ID бота для внесения в белый список.</sys:String>
<sys:String x:Key="ServerSettings_AddDiscordBotWhitelistTooltip">Добавить в белый лист</sys:String>
<sys:String x:Key="ServerSettings_ClearDiscordBotWhitelistTooltip">Очистить белый лист</sys:String>
<sys:String x:Key="ServerSettings_RemoveDiscordBotWhitelistTooltip">Удалить белый лист</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowBackupTooltip">Если включено, команду резервного копирования можно отправить из Discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowRestartTooltip">Если этот параметр включен, команда перезапуска может быть отправлена из Discord.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotAllowShutdownTooltip">Если включено, команду выключения можно отправить из Discord.</sys:String>
@ -1205,6 +1224,8 @@
<sys:String x:Key="ServerSettings_DiscordBotLabel">Детали бота Discord</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotChannelLabel">Канал Id:</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotChannelTooltip">ID канала сервера Discord, который будет слушать этот профиль.</sys:String>
<sys:String x:Key="ServerSettings_DiscordAliasLabel">Псевдоним:</sys:String>
<sys:String x:Key="ServerSettings_DiscordAliasTooltip">Вместо идентификатора профиля можно использовать уникальное имя для идентификации вашего сервера при использовании команд discord.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordBackupLabel">Разрешить Бекап</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordBackupTooltip">Если этот параметр включен, профиль будет прослушивать команды Бекапа от Discord.</sys:String>
<sys:String x:Key="ServerSettings_AllowDiscordRestartLabel">Разрешить Перезагрузку</sys:String>
@ -1255,7 +1276,7 @@
<sys:String x:Key="ServerSettings_PlatformSaddleBuildAreaBoundsMultiplierTooltip">Увеличение множителя позволяет размещать структуры дальше от края платформы.</sys:String>
<sys:String x:Key="ServerSettings_MaxGateFrameOnSaddlesLabel">Макс количество ворот на седлах-платформах</sys:String>
<sys:String x:Key="ServerSettings_MaxGateFrameOnSaddlesTooltip">Ограничивает количество ворот, которые можно разместить на седлах-платформах. Этот вариант не имеет обратной силы, поэтому применение этого изменения потребует некоторой ручной административной работы, чтобы очистить все существующие платформы, превышающие лимит.</sys:String>
<sys:String x:Key="ServerSettings_EnableDifficultyOverrideLabel">Включить перераспределение сложности</sys:String>
<sys:String x:Key="ServerSettings_EnableDifficultyOverrideTooltip">Если включено, это позволит изменить максимальный уровень существ в мире.</sys:String>
<sys:String x:Key="ServerSettings_OverrideOfficialDifficultyLabel">Максимальный уровень динозавров:</sys:String>
@ -1264,7 +1285,7 @@
<sys:String x:Key="ServerSettings_DifficultyOffsetTooltip">Определяет максимальные уровни существ в мире. Чем выше значение, тем выше максимальный уровень существа.</sys:String>
<sys:String x:Key="ServerSettings_DestroyTamesOverLevelClampLabel">Destroy Tames Over Level:</sys:String>
<sys:String x:Key="ServerSettings_DestroyTamesOverLevelClampTooltip">Tames that exceed this level will be deleted on server start. To disable deletion set to 0.</sys:String>
<sys:String x:Key="ServerSettings_EnableTributeLabel">Вкл загрузку из данных кластера</sys:String>
<sys:String x:Key="ServerSettings_EnableTributeTooltip">Если включено, это позволит загружать выживших/предметов/динозавров на сервер.</sys:String>
<sys:String x:Key="ServerSettings_NoSurvivorDownloadsLabel">Откл загрузку выживших на сервер</sys:String>
@ -5678,6 +5699,7 @@
<sys:String x:Key="DiscordBot_ProfileMissing">Для команды '{0}' требуется идентификатор профиля.</sys:String>
<sys:String x:Key="DiscordBot_ProfileNotFound">Профиль '{0}' не найден или не связан с каналом.</sys:String>
<sys:String x:Key="DiscordBot_ProfileMultiples">В канале было обнаружено несколько профилей с "{0}", команда прервана.</sys:String>
<sys:String x:Key="DiscordBot_ProfileBadStatus">Профиль '{0}' находится в состоянии '{1}', и эта команда не может быть запущена.</sys:String>
<sys:String x:Key="DiscordBot_ProfileUpdating">Профиль '{0}' в настоящее время обновляется.</sys:String>

View file

@ -9,7 +9,7 @@
<!--#region Generic -->
<sys:String x:Key="Generic_TranslatedByLabel">翻译:</sys:String>
<sys:String x:Key="Generic_TranslatedBy">2021.12.09(龍柒)</sys:String>
<sys:String x:Key="Generic_TranslatedBy">2021.12.13(龍柒)</sys:String>
<sys:String x:Key="Generic_ErrorLabel">错误</sys:String>
<!--#endregion-->
@ -24,6 +24,7 @@
<sys:String x:Key="Map_Genesis">创世纪 1(Genesis: Part 1)</sys:String>
<sys:String x:Key="Map_Gen2">创世纪 2Genesis: Part 2</sys:String>
<sys:String x:Key="Map_CrystalIsles">水晶岛(Crystal Isles)</sys:String>
<sys:String x:Key="Map_LostIsland">迷失岛(Lost Island)</sys:String>
<!--#endregion-->
<!--#总转换名称 -->
@ -57,6 +58,7 @@
<sys:String x:Key="Mod_Genesis2">创世纪 2(Genesis: Part 2)</sys:String>
<sys:String x:Key="Mod_CrystalIsles">水晶岛(Crystal Isles)</sys:String>
<sys:String x:Key="Mod_PGM">程序生成地图(PGM)</sys:String>
<sys:String x:Key="Mod_LostIsland">迷失岛(Lost Island)</sys:String>
<sys:String x:Key="Mod_Valguero">瓦尔盖罗(Valguero)</sys:String>
<!--#endregion-->
@ -103,8 +105,8 @@
<sys:String x:Key="Application_DataDirectory_DialogTitle">选择一个数据目录</sys:String>
<sys:String x:Key="Application_DataDirectory_ConfirmTitle">确认位置</sys:String>
<sys:String x:Key="Application_DataDirectory_ConfirmLabel">方舟服务器管理工具将存储配置文件和steamcmd以下目录:\r\n\r\n配置文件: {0}\r\nSteamCMD: {1}\r\n\r\n这样可以吗</sys:String>
<sys:String x:Key="Application_DataDirectory_DataDirectoryFolderErrorTitle">数据目录选择错误</sys:String>
<sys:String x:Key="Application_DataDirectory_DataDirectoryWithinInstallFolderErrorLabel">您选择的目录在服务器管理器安装文件夹中。 不建议这样做,请选择另一个文件夹。</sys:String>
<sys:String x:Key="Application_DataDirectory_WithinInstallFolderErrorTitle">数据目录选择错误</sys:String>
<sys:String x:Key="Application_DataDirectory_WithinInstallFolderErrorLabel">您选择的目录在服务器管理器安装文件夹中。 不建议这样做,请选择另一个文件夹。</sys:String>
<sys:String x:Key="Application_Profile_SaveFailedTitle">保存配置文件失败</sys:String>
<sys:String x:Key="Application_Profile_SaveFailedLabel">保存配置文件失败 {0}. {1}\n{2}</sys:String>
@ -383,9 +385,9 @@
<sys:String x:Key="GameDataWindow_ValidateErrorMessage">该文件无效。 它可能包含错误或格式不正确。</sys:String>
<sys:String x:Key="GameDataWindow_AddDialogTitle">选择游戏数据文件</sys:String>
<sys:String x:Key="GameDataWindow_GameDataDefaultExtension">游戏数据</sys:String>
<sys:String x:Key="GameDataWindow_GameDataDefaultExtension">gamedata</sys:String>
<sys:String x:Key="GameDataWindow_AddFilterLabel">游戏数据文件</sys:String>
<sys:String x:Key="GameDataWindow_AddFilterExtension">*.游戏数据</sys:String>
<sys:String x:Key="GameDataWindow_AddFilterExtension">*.gamedata</sys:String>
<!--#endregion-->
<!-- 插件窗口 -->
@ -3002,6 +3004,22 @@
<sys:String x:Key="RockwellNode_Character_BP_FinalFight_Alpha_C">罗克韦尔节点 BOSS困难</sys:String>
<!--#endregion-->
<!-- 恐龙/生物类名称 - 迷失岛 -->
<sys:String x:Key="Amargasaurus_Character_BP_C">阿马加龙</sys:String>
<sys:String x:Key="Sinomacrops_Character_BP_C">中华大眼翼龙</sys:String>
<sys:String x:Key="Dinopithecus_Character_BP_C">恐狒</sys:String>
<!--#endregion-->
<!-- 恐龙/生物类名称 - 迷失岛-BOSS-->
<sys:String x:Key="BossDinopithecus_Character_BP_C">BOSS-恐狒</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDinopith_Easy_C">BOSS-恐狒(简单)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDinopith_Hard_C">BOSS-恐狒(中等)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDinopith_Medium_C">BOSS-恐狒(困难)</sys:String>
<sys:String x:Key="Amargasaurus_Character_BP_Minion_C">狒狒BOSS爪牙[阿马加龙]</sys:String>
<sys:String x:Key="Dinopithecus_Character_BP_Minion_C">狒狒BOSS爪牙</sys:String>
<sys:String x:Key="Sinomacrops_Character_BP_Minion_C">狒狒BOSS爪牙[中华大眼翼龙]</sys:String>
<!--#endregion-->
<!--#endregion-->
<!--#region Engrams -->
@ -3768,6 +3786,10 @@
<sys:String x:Key="EngramEntry_TropeSaddle_C">脊颌翼龙的鞍</sys:String>
<!--#endregion-->
<!--# 印痕技能 - 迷失岛 -->
<sys:String x:Key="EngramEntry_Saddle_Amarga_C">阿马加龙鞍</sys:String>
<!--#endregion-->
<!--#endregion-->
<!--#endregion-->
@ -5236,6 +5258,16 @@
<sys:String x:Key="PrimalItemConsumable_Seed_PlantSpeciesR_PrimeFish_C">植物R-5 种子(优质生鱼肉)</sys:String>
<!--#endregion-->
<!--#项目类别名称 - 迷失岛 -->
<sys:String x:Key="PrimalItemArmor_AmargaSaddle_C">阿马加龙鞍</sys:String>
<sys:String x:Key="PrimalItemSkin_Costume_Dinopithecus_C">恐狒皮肤</sys:String>
<sys:String x:Key="PrimalItemResource_AmargaSpike_C">阿马加龙尖刺</sys:String>
<sys:String x:Key="PrimalItemTrophy_BossDinopithecus_C">恐狒BOSS战利品(迷失岛)</sys:String>
<sys:String x:Key="PrimalItem_BossTribute_LostIsland_Easy_C">恐狒BOSS战利品(简单)(迷失岛)</sys:String>
<sys:String x:Key="PrimalItemTrophy_BossDinopithecus_Hard_C">恐狒BOSS战利品(中等)(迷失岛)</sys:String>
<sys:String x:Key="PrimalItem_BossTribute_LostIsland_Medium_C">恐狒BOSS战利品(困难)(迷失岛)</sys:String>
<!--#endregion-->
<!--#项目类别名称 - 新增(唯一集成模组) -->
<sys:String x:Key="PrimalItem_xidianka_Weiyi_C">恐龙洗点卡</sys:String>
<sys:String x:Key="PrimalItem_TEK_unlock_Weiyi_C">泰克一键解锁</sys:String>
@ -5757,9 +5789,9 @@
<sys:String x:Key="Race_HoverSkiff_Easy_C">极品飞艇(简单){任务}</sys:String>
<sys:String x:Key="Race_HoverSkiff_Medium_C">极品飞艇(中等){任务}</sys:String>
<sys:String x:Key="Race_HoverSkiff_Hard_C">极品飞艇(困难){任务}</sys:String>
<sys:String x:Key="Lootcrate_lvl1_C">资源包1级</sys:String>
<sys:String x:Key="Lootcrate_lvl2_C">资源包2级</sys:String>
<sys:String x:Key="Lootcrate_lvl3_C">资源包3级</sys:String>
<sys:String x:Key="Lootcrate_lvl1_C">一等战利品箱</sys:String>
<sys:String x:Key="Lootcrate_lvl2_C">二等战利品箱</sys:String>
<sys:String x:Key="Lootcrate_lvl3_C">三等战利品箱</sys:String>
<sys:String x:Key="SupplyCrate_Space_01_Ambergris_C">空投_白色(创世2)</sys:String>
<sys:String x:Key="SupplyCrate_Space_02_Crystal_C">空投_绿色(创世2)</sys:String>
@ -5814,6 +5846,7 @@
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Easy_C">Boss 清单 - (水晶岛)水晶女王 (简单)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Medium_C">Boss 清单 - (水晶岛)水晶女王 (中等)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_CIBoss_Hard_C">Boss 清单 - (水晶岛)水晶女王 (困难)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_Carnivore_Large_CrystalWyvern_C">水晶飞龙</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Easy_Ragnarok_C">Boss 清单 - 喷火龙 (简单)</sys:String>
<sys:String x:Key="DinoDropInventoryComponent_BossDragon_Medium_Ragnarok_C">Boss 清单 - 喷火龙 (中等)</sys:String>

View file

@ -52,7 +52,7 @@ namespace ServerManagerTool.Lib
items = gameData.Items.ConvertAll(item => new PrimalItem { ClassName = item.ClassName, Mod = item.Mod, KnownItem = true, Category = item.Category }).ToArray();
// resources
resourceMultipliers = gameData.Items.Where(item => item.IsHarvestable).ToList().ConvertAll(item => new ResourceClassMultiplier { ClassName = item.ClassName, Mod = item.Mod, KnownResource = true }).ToArray();
resourceMultipliers = gameData.Items.Where(item => item.IsHarvestable).Select(item => new ResourceClassMultiplier { ClassName = item.ClassName, Mod = item.Mod, KnownResource = true }).ToArray();
// map spawners
gameData.MapSpawners.AddRange(userGameData.MapSpawners);
@ -77,9 +77,9 @@ namespace ServerManagerTool.Lib
if (gameData.GameMaps.Count > 0)
{
var maps1 = gameMaps.ToList();
maps1.AddRange(gameData.GameMaps.Where(item => !item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
maps1.AddRange(gameData.GameMaps.Where(item => !item.IsSotF).Select(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
var maps2 = gameMapsSotF.ToList();
maps2.AddRange(gameData.GameMaps.Where(item => item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
maps2.AddRange(gameData.GameMaps.Where(item => item.IsSotF).Select(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
gameMaps = maps1.ToArray();
gameMapsSotF = maps2.ToArray();
@ -91,9 +91,9 @@ namespace ServerManagerTool.Lib
if (gameData.TotalConversions.Count > 0)
{
var mods1 = totalConversions.ToList();
mods1.AddRange(gameData.TotalConversions.Where(item => !item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
mods1.AddRange(gameData.TotalConversions.Where(item => !item.IsSotF).Select(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
var mods2 = totalConversionsSotF.ToList();
mods2.AddRange(gameData.TotalConversions.Where(item => item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
mods2.AddRange(gameData.TotalConversions.Where(item => item.IsSotF).Select(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
totalConversions = mods1.ToArray();
totalConversionsSotF = mods2.ToArray();
@ -130,9 +130,9 @@ namespace ServerManagerTool.Lib
if (gameData.Branches.Count > 0)
{
var branches1 = branches.ToList();
branches1.AddRange(gameData.Branches.Where(item => !item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.BranchName, DisplayMember = item.Description }));
branches1.AddRange(gameData.Branches.Where(item => !item.IsSotF).Select(item => new ComboBoxItem { ValueMember = item.BranchName, DisplayMember = item.Description }));
var branches2 = branchesSotF.ToList();
branches2.AddRange(gameData.Branches.Where(item => item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.BranchName, DisplayMember = item.Description }));
branches2.AddRange(gameData.Branches.Where(item => item.IsSotF).Select(item => new ComboBoxItem { ValueMember = item.BranchName, DisplayMember = item.Description }));
branches = branches1.ToArray();
branchesSotF = branches2.ToArray();
@ -144,9 +144,9 @@ namespace ServerManagerTool.Lib
if (gameData.Events.Count > 0)
{
var events1 = events.ToList();
events1.AddRange(gameData.Events.Where(item => !item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.EventName, DisplayMember = item.Description }));
events1.AddRange(gameData.Events.Where(item => !item.IsSotF).Select(item => new ComboBoxItem { ValueMember = item.EventName, DisplayMember = item.Description }));
var events2 = eventsSotF.ToList();
events2.AddRange(gameData.Events.Where(item => item.IsSotF).ToList().ConvertAll(item => new ComboBoxItem { ValueMember = item.EventName, DisplayMember = item.Description }));
events2.AddRange(gameData.Events.Where(item => item.IsSotF).Select(item => new ComboBoxItem { ValueMember = item.EventName, DisplayMember = item.Description }));
events = events1.ToArray();
eventsSotF = events2.ToArray();
@ -157,7 +157,7 @@ namespace ServerManagerTool.Lib
if (gameData.OfficialMods.Count > 0)
{
ModUtils.AddOfficialMods(gameData.OfficialMods.Where(m => !string.IsNullOrWhiteSpace(m.ModId)).Select(m => m.ModId));
ModUtils.AddOfficialMods(gameData.OfficialMods.Where(m => !string.IsNullOrWhiteSpace(m.ModId)).Select(m => m.ModId).ToList());
}
}

View file

@ -17,15 +17,13 @@ namespace ServerManagerTool.Lib
public override void FromIniValues(IEnumerable<string> iniValues)
{
var items = iniValues?.Select(AggregateIniValue.FromINIValue<EngramAutoUnlock>).ToArray();
var items = iniValues?.Select(AggregateIniValue.FromINIValue<EngramAutoUnlock>);
Clear();
var itemsToAdd = items.Where(i => !this.Any(e => e.IsEquivalent(i))).ToArray();
AddRange(itemsToAdd);
AddRange(items.Where(i => !this.Any(e => e.IsEquivalent(i))));
var itemsToUpdate = items.Where(i => this.Any(e => e.IsEquivalent(i))).ToArray();
foreach (var item in itemsToUpdate)
foreach (var item in items.Where(i => this.Any(e => e.IsEquivalent(i))))
{
var e = this.FirstOrDefault(r => r.IsEquivalent(item));
e.LevelToAutoUnlock = item.LevelToAutoUnlock;

View file

@ -18,15 +18,13 @@ namespace ServerManagerTool.Lib
public override void FromIniValues(IEnumerable<string> iniValues)
{
var items = iniValues?.Select(AggregateIniValue.FromINIValue<EngramEntry>).ToArray();
var items = iniValues?.Select(AggregateIniValue.FromINIValue<EngramEntry>);
Clear();
var itemsToAdd = items.Where(i => !this.Any(e => e.IsEquivalent(i))).ToArray();
AddRange(itemsToAdd);
AddRange(items.Where(i => !this.Any(e => e.IsEquivalent(i))));
var itemsToUpdate = items.Where(i => this.Any(e => e.IsEquivalent(i))).ToArray();
foreach (var item in itemsToUpdate)
foreach (var item in items.Where(i => this.Any(e => e.IsEquivalent(i))))
{
var e = this.FirstOrDefault(r => r.IsEquivalent(item));
e.EngramLevelRequirement = item.EngramLevelRequirement;

View file

@ -61,7 +61,7 @@ namespace ServerManagerTool.Lib
int index = 0;
int xpTotal = 0;
int engramTotal = 0;
foreach (var existingLevel in this.OrderBy(l => l.XPRequired).ToArray())
foreach (var existingLevel in this.OrderBy(l => l.XPRequired))
{
xpTotal += existingLevel.XPRequired;
engramTotal += existingLevel.EngramPoints;

View file

@ -6,7 +6,6 @@ using ServerManagerTool.Enums;
using ServerManagerTool.Interface;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

View file

@ -14,11 +14,9 @@ namespace ServerManagerTool.Lib
{
}
public string[] RenderToView()
public IEnumerable<string> RenderToView()
{
List<string> errors = new List<string>();
return errors.ToArray();
return new List<string>();
}
public void RenderToModel()

View file

@ -1,5 +1,4 @@
using ServerManagerTool.Common.Model;
using ServerManagerTool.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
@ -18,22 +17,20 @@ namespace ServerManagerTool.Lib
public override void FromIniValues(IEnumerable<string> iniValues)
{
var items = iniValues?.Select(AggregateIniValue.FromINIValue<ResourceClassMultiplier>).ToArray();
var items = iniValues?.Select(AggregateIniValue.FromINIValue<ResourceClassMultiplier>);
Clear();
if (this._resetFunc != null)
this.AddRange(this._resetFunc());
var itemsToAdd = items.Where(i => !this.Any(r => r.IsEquivalent(i))).ToArray();
AddRange(itemsToAdd);
AddRange(items.Where(i => !this.Any(r => r.IsEquivalent(i))));
var itemsToUpdate = items.Where(i => this.Any(r => r.IsEquivalent(i))).ToArray();
foreach (var item in itemsToUpdate)
foreach (var item in items.Where(i => this.Any(r => r.IsEquivalent(i))))
{
this.FirstOrDefault(r => r.IsEquivalent(item)).Multiplier = item.Multiplier;
}
IsEnabled = (items.Length > 0);
IsEnabled = (Count > 0);
Sort(AggregateIniValue.SortKeySelector);
}

View file

@ -14,7 +14,7 @@ namespace ServerManagerTool.Lib
{
}
public string[] RenderToView()
public IEnumerable<string> RenderToView()
{
List<string> errors = new List<string>();
@ -27,7 +27,7 @@ namespace ServerManagerTool.Lib
}
}
return errors.ToArray();
return errors;
}
public void RenderToModel()

View file

@ -17,7 +17,7 @@ namespace ServerManagerTool.Lib
{
}
public string[] RenderToView()
public IEnumerable<string> RenderToView()
{
List<string> errors = new List<string>();
@ -48,7 +48,7 @@ namespace ServerManagerTool.Lib
Update();
return errors.ToArray();
return errors;
}
public void RenderToModel()

View file

@ -422,6 +422,16 @@ namespace ServerManagerTool.Lib
LogProfileMessage("Starting shutdown timer...");
var minutesLeft = ShutdownInterval;
if (ServerProcess == ServerProcessType.Stop)
{
LogProfileMessage($"Server shutdown type is {ServerProcess}, shutdown timer cancelled.");
minutesLeft = 0;
}
else if (!CheckForOnlinePlayers)
{
LogProfileMessage("CheckForOnlinePlayers disabled, shutdown timer will not perform online player check.");
}
while (minutesLeft > 0)
{
if (cancellationToken.IsCancellationRequested)
@ -442,8 +452,8 @@ namespace ServerManagerTool.Lib
{
try
{
var playerInfo = gameServer?.GetPlayers()?.Where(p => !string.IsNullOrWhiteSpace(p.Name?.Trim())).ToList();
var playerCount = playerInfo?.Count ?? -1;
var playerInfo = gameServer?.GetPlayers()?.Where(p => !string.IsNullOrWhiteSpace(p.Name?.Trim()));
var playerCount = playerInfo?.Count() ?? -1;
// check if anyone is logged into the server
if (playerCount <= 0)
@ -462,7 +472,6 @@ namespace ServerManagerTool.Lib
else
{
Debug.WriteLine($"CheckForOnlinePlayers disabled, shutdown timer cancelled.");
break;
}
var message = string.Empty;
@ -1866,7 +1875,7 @@ namespace ServerManagerTool.Lib
comment.AppendLine($"PGM Server: {_profile.PGM_Enabled}");
comment.AppendLine($"Process: {ServerProcess}");
ZipUtils.ZipFiles(backupFile, files.ToArray(), comment.ToString(), false);
ZipUtils.ZipFiles(backupFile, files, comment.ToString(), false);
LogProfileMessage($"Backup file created - {backupFile}");
}
@ -2016,7 +2025,7 @@ namespace ServerManagerTool.Lib
comment.AppendLine($"PGM Server: {_profile.PGM_Enabled}");
comment.AppendLine($"Process: {ServerProcess}");
ZipUtils.ZipFiles(backupFile, files.ToArray(), comment.ToString(), false);
ZipUtils.ZipFiles(backupFile, files, comment.ToString(), false);
LogProfileMessage($"Backed up world files - {saveFolder}");
LogProfileMessage($"Backup file created - {backupFile}");
@ -2989,7 +2998,7 @@ namespace ServerManagerTool.Lib
if (ExitCode == EXITCODE_NORMALEXIT)
{
// get the profile associated with the branch
var profiles = _profiles.Keys.Where(p => p.EnableAutoUpdate && p.BranchName.Equals(branch.BranchName, StringComparison.OrdinalIgnoreCase)).ToArray();
var profiles = _profiles.Keys.Where(p => p.EnableAutoUpdate && p.BranchName.Equals(branch.BranchName, StringComparison.OrdinalIgnoreCase));
var profileExitCodes = new ConcurrentDictionary<ServerProfileSnapshot, int>();
if (Config.Default.AutoUpdate_ParallelUpdate)
@ -3240,7 +3249,7 @@ namespace ServerManagerTool.Lib
if (exitCode == EXITCODE_NORMALEXIT)
{
var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => BranchSnapshot.Create(p)).Distinct(new BranchSnapshotComparer()).ToArray();
var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => BranchSnapshot.Create(p)).Distinct(new BranchSnapshotComparer());
var exitCodes = new ConcurrentDictionary<BranchSnapshot, int>();
// update the server cache for each branch

View file

@ -223,7 +223,7 @@ namespace ServerManagerTool.Lib
token.ThrowIfCancellationRequested();
// remove any players that do not have a player file.
var droppedPlayers = _players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null).ToArray();
var droppedPlayers = _players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null);
foreach (var droppedPlayer in droppedPlayers)
{
_players.TryRemove(droppedPlayer.PlayerId, out PlayerInfo player);

View file

@ -968,6 +968,14 @@ namespace ServerManagerTool.Lib
set { SetValue(DiscordChannelIdProperty, value); }
}
public static readonly DependencyProperty DiscordAliasProperty = DependencyProperty.Register(nameof(DiscordAlias), typeof(string), typeof(ServerProfile), new PropertyMetadata(String.Empty));
[DataMember]
public string DiscordAlias
{
get { return (string)GetValue(DiscordAliasProperty); }
set { SetValue(DiscordAliasProperty, value); }
}
public static readonly DependencyProperty AllowDiscordBackupProperty = DependencyProperty.Register(nameof(AllowDiscordBackup), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
[DataMember]
public bool AllowDiscordBackup
@ -3473,9 +3481,7 @@ namespace ServerManagerTool.Lib
{
InstallDirectory = folder;
LoadServerFileAdministrators();
LoadServerFileExclusive();
LoadServerFileWhitelisted();
LoadServerFiles(true, true, true);
SetupServerFilesWatcher();
}
@ -3561,9 +3567,7 @@ namespace ServerManagerTool.Lib
settings.MutagenLevelBoostBred.Reset();
settings.PerLevelStatsMultiplier_Player.Reset();
settings.PlayerBaseStatMultipliers.Reset();
settings.LoadServerFileAdministrators();
settings.LoadServerFileExclusive();
settings.LoadServerFileWhitelisted();
settings.LoadServerFiles(true, true, true);
settings.SetupServerFilesWatcher();
return settings;
}
@ -3597,7 +3601,7 @@ namespace ServerManagerTool.Lib
}
}
private static Enum[] GetExclusions()
private static IEnumerable<Enum> GetExclusions()
{
var exclusions = new List<Enum>();
@ -3641,7 +3645,7 @@ namespace ServerManagerTool.Lib
exclusions.Add(ServerProfileCategory.SOTF);
}
return exclusions.ToArray();
return exclusions;
}
private LevelList GetLevelList(LevelProgression levelProgression)
@ -4026,7 +4030,7 @@ namespace ServerManagerTool.Lib
return profile;
}
public static ServerProfile LoadFromINIFiles(string file, ServerProfile profile, Enum[] exclusions = null)
public static ServerProfile LoadFromINIFiles(string file, ServerProfile profile, IEnumerable<Enum> exclusions = null)
{
if (string.IsNullOrWhiteSpace(file) || !File.Exists(file))
return null;
@ -4140,9 +4144,7 @@ namespace ServerManagerTool.Lib
if (Config.Default.SectionPreventTransferOverridesEnabled)
profile.PreventTransferForClassNames.RenderToView();
profile.LoadServerFileAdministrators();
profile.LoadServerFileExclusive();
profile.LoadServerFileWhitelisted();
profile.LoadServerFiles(true, true, true);
profile.SetupServerFilesWatcher();
profile._lastSaveLocation = file;
@ -4400,7 +4402,7 @@ namespace ServerManagerTool.Lib
SaveINIFile(configDir);
}
public void SaveINIFile(string profileIniDir, Enum[] exclusions = null)
public void SaveINIFile(string profileIniDir, IEnumerable<Enum> exclusions = null)
{
if (exclusions == null)
exclusions = GetExclusions();
@ -4424,7 +4426,7 @@ namespace ServerManagerTool.Lib
filteredValues.AddRange(this.PlayerLevels.ToINIValuesForEngramPoints());
}
iniFile.WriteSection(IniFiles.Game, IniSections.Game_ShooterGameMode, filteredValues.ToArray());
iniFile.WriteSection(IniFiles.Game, IniSections.Game_ShooterGameMode, filteredValues);
}
public bool UpdateDirectoryPermissions()
@ -4984,7 +4986,7 @@ namespace ServerManagerTool.Lib
var csvMapper = new CsvDinoLevelMapping();
var csvParser = new CsvParser<ImportLevel>(csvParserOptions, csvMapper);
var result = csvParser.ReadFromFile(fileName, Encoding.ASCII).ToList();
var result = csvParser.ReadFromFile(fileName, Encoding.ASCII);
if (result.Any(r => !r.IsValid))
{
var error = result.First(r => r.Error != null);
@ -5011,7 +5013,7 @@ namespace ServerManagerTool.Lib
var csvMapper = new CsvPlayerLevelMapping();
var csvParser = new CsvParser<ImportLevel>(csvParserOptions, csvMapper);
var result = csvParser.ReadFromFile(fileName, Encoding.ASCII).ToList();
var result = csvParser.ReadFromFile(fileName, Encoding.ASCII);
if (result.Any(r => !r.IsValid))
{
var error = result.First(r => r.Error != null);
@ -5762,9 +5764,9 @@ namespace ServerManagerTool.Lib
this.SetValue(AutoSavePeriodMinutesProperty, sourceProfile.AutoSavePeriodMinutes);
this.SetValue(MOTDProperty, sourceProfile.MOTD);
this.SetValue(MOTDDurationProperty, sourceProfile.MOTDDuration);
this.SetNullableValue(MOTDIntervalProperty, sourceProfile.MOTDInterval);
//this.SetValue(MOTDProperty, sourceProfile.MOTD);
//this.SetValue(MOTDDurationProperty, sourceProfile.MOTDDuration);
//this.SetNullableValue(MOTDIntervalProperty, sourceProfile.MOTDInterval);
this.SetValue(EnableExtinctionEventProperty, sourceProfile.EnableExtinctionEvent);
this.SetValue(ExtinctionEventTimeIntervalProperty, sourceProfile.ExtinctionEventTimeInterval);
@ -5802,7 +5804,7 @@ namespace ServerManagerTool.Lib
this.SetValue(CrossplayProperty, sourceProfile.Crossplay);
this.SetValue(EpicOnlyProperty, sourceProfile.EpicOnly);
this.SetValue(EnablePublicIPForEpicProperty, sourceProfile.EnablePublicIPForEpic);
this.SetValue(AltSaveDirectoryNameProperty, sourceProfile.AltSaveDirectoryName);
//this.SetValue(AltSaveDirectoryNameProperty, sourceProfile.AltSaveDirectoryName);
this.SetValue(CrossArkClusterIdProperty, sourceProfile.CrossArkClusterId);
this.SetValue(ClusterDirOverrideProperty, sourceProfile.ClusterDirOverride);
@ -5866,7 +5868,7 @@ namespace ServerManagerTool.Lib
this.CustomEngineSettings.Clear();
foreach (var section in sourceProfile.CustomEngineSettings)
{
this.CustomEngineSettings.Add(section.SectionName, section.ToIniValues().ToArray());
this.CustomEngineSettings.Add(section.SectionName, section.ToIniValues());
}
}
@ -5875,7 +5877,7 @@ namespace ServerManagerTool.Lib
this.CustomGameSettings.Clear();
foreach (var section in sourceProfile.CustomGameSettings)
{
this.CustomGameSettings.Add(section.SectionName, section.ToIniValues().ToArray());
this.CustomGameSettings.Add(section.SectionName, section.ToIniValues());
}
}
@ -5884,7 +5886,7 @@ namespace ServerManagerTool.Lib
this.CustomGameUserSettings.Clear();
foreach (var section in sourceProfile.CustomGameUserSettings)
{
this.CustomGameUserSettings.Add(section.SectionName, section.ToIniValues().ToArray());
this.CustomGameUserSettings.Add(section.SectionName, section.ToIniValues());
}
}
@ -6364,18 +6366,24 @@ namespace ServerManagerTool.Lib
#region Server Files
private void ServerFilesWatcher_Changed(object sender, FileSystemEventArgs e)
{
var adminFile = false;
var exclusiveFile = false;
var whitelistFile = false;
if (e.Name.Equals(Config.Default.ArkAdminFile, StringComparison.OrdinalIgnoreCase))
{
TaskUtils.RunOnUIThreadAsync(() => LoadServerFileAdministrators()).DoNotWait();
adminFile = true;
}
else if (e.Name.Equals(Config.Default.ArkExclusiveFile, StringComparison.OrdinalIgnoreCase))
if (e.Name.Equals(Config.Default.ArkExclusiveFile, StringComparison.OrdinalIgnoreCase))
{
TaskUtils.RunOnUIThreadAsync(() => LoadServerFileExclusive()).DoNotWait();
exclusiveFile = true;
}
else if (e.Name.Equals(Config.Default.ArkWhitelistFile, StringComparison.OrdinalIgnoreCase))
if (e.Name.Equals(Config.Default.ArkWhitelistFile, StringComparison.OrdinalIgnoreCase))
{
TaskUtils.RunOnUIThreadAsync(() => LoadServerFileWhitelisted()).DoNotWait();
whitelistFile = true;
}
TaskUtils.RunOnUIThreadAsync(() => LoadServerFiles(adminFile, exclusiveFile, whitelistFile)).DoNotWait();
}
private void ServerFilesWatcher_Error(object sender, ErrorEventArgs e)
@ -6447,74 +6455,76 @@ namespace ServerManagerTool.Lib
_serverFilesWatcherSaved.EnableRaisingEvents = true;
}
public void LoadServerFileAdministrators()
public void LoadServerFiles(bool adminFile, bool exclusiveFile, bool whitelistFile)
{
try
{
var list = this.ServerFilesAdmins ?? new PlayerUserList();
var list1 = this.ServerFilesAdmins ?? new PlayerUserList();
var list2 = this.ServerFilesExclusive ?? new PlayerUserList();
var list3 = this.ServerFilesWhitelisted ?? new PlayerUserList();
var file = Path.Combine(InstallDirectory, Config.Default.SavedRelativePath, Config.Default.ArkAdminFile);
if (File.Exists(file))
var allSteamIds = new List<string>();
string[] adminSteamIds = null;
string[] exclusiveSteamIds = null;
string[] whitelistSteamIds = null;
if (adminFile)
{
var steamIds = File.ReadAllLines(file);
var steamUsers = SteamUtils.GetSteamUserDetails(steamIds.ToList());
list = PlayerUserList.GetList(steamUsers, steamIds);
var file = Path.Combine(InstallDirectory, Config.Default.SavedRelativePath, Config.Default.ArkAdminFile);
if (File.Exists(file))
{
adminSteamIds = File.ReadAllLines(file);
allSteamIds.AddRange(adminSteamIds);
}
}
this.ServerFilesAdmins = list;
if (exclusiveFile)
{
var file = Path.Combine(InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ArkExclusiveFile);
if (File.Exists(file))
{
exclusiveSteamIds = File.ReadAllLines(file);
allSteamIds.AddRange(exclusiveSteamIds);
}
}
if (whitelistFile)
{
var file = Path.Combine(InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ArkWhitelistFile);
if (File.Exists(file))
{
whitelistSteamIds = File.ReadAllLines(file);
allSteamIds.AddRange(whitelistSteamIds);
}
}
// remove all duplicates
allSteamIds = allSteamIds.Distinct().ToList();
// fetch the details of all steam users in the list
var steamUsers = SteamUtils.GetSteamUserDetails(allSteamIds);
if (adminFile && adminSteamIds != null)
{
list1 = PlayerUserList.GetList(steamUsers, adminSteamIds);
}
if (exclusiveFile && exclusiveSteamIds != null)
{
list2 = PlayerUserList.GetList(steamUsers, exclusiveSteamIds);
}
if (whitelistFile && whitelistSteamIds != null)
{
list3 = PlayerUserList.GetList(steamUsers, whitelistSteamIds);
}
this.ServerFilesAdmins = list1;
this.ServerFilesExclusive = list2;
this.ServerFilesWhitelisted = list3;
}
catch (Exception ex)
{
this.ServerFilesAdmins = new PlayerUserList();
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_ServerFilesLoadErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public void LoadServerFileExclusive()
{
try
{
var list = this.ServerFilesExclusive ?? new PlayerUserList();
var file = Path.Combine(InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ArkExclusiveFile);
if (File.Exists(file))
{
var steamIds = File.ReadAllLines(file);
var steamUsers = SteamUtils.GetSteamUserDetails(steamIds.ToList());
list = PlayerUserList.GetList(steamUsers, steamIds);
}
this.ServerFilesExclusive = list;
}
catch (Exception ex)
{
this.ServerFilesExclusive = new PlayerUserList();
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_ServerFilesLoadErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public void LoadServerFileWhitelisted()
{
try
{
var list = this.ServerFilesWhitelisted ?? new PlayerUserList();
var file = Path.Combine(InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ArkWhitelistFile);
if (File.Exists(file))
{
var steamIds = File.ReadAllLines(file);
var steamUsers = SteamUtils.GetSteamUserDetails(steamIds.ToList());
list = PlayerUserList.GetList(steamUsers, steamIds);
}
this.ServerFilesWhitelisted = list;
}
catch (Exception ex)
{
this.ServerFilesWhitelisted = new PlayerUserList();
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_ServerFilesLoadErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@ -6528,7 +6538,7 @@ namespace ServerManagerTool.Lib
Directory.CreateDirectory(folder);
var file = Path.Combine(folder, Config.Default.ArkAdminFile);
File.WriteAllLines(file, this.ServerFilesAdmins.ToArray());
File.WriteAllLines(file, this.ServerFilesAdmins.ToEnumerable());
}
catch (Exception ex)
{
@ -6545,7 +6555,7 @@ namespace ServerManagerTool.Lib
Directory.CreateDirectory(folder);
var file = Path.Combine(folder, Config.Default.ArkExclusiveFile);
File.WriteAllLines(file, this.ServerFilesExclusive.ToArray());
File.WriteAllLines(file, this.ServerFilesExclusive.ToEnumerable());
}
catch (Exception ex)
{
@ -6562,7 +6572,7 @@ namespace ServerManagerTool.Lib
Directory.CreateDirectory(folder);
var file = Path.Combine(folder, Config.Default.ArkWhitelistFile);
File.WriteAllLines(file, this.ServerFilesWhitelisted.ToArray());
File.WriteAllLines(file, this.ServerFilesWhitelisted.ToEnumerable());
}
catch (Exception ex)
{

View file

@ -29,7 +29,7 @@ namespace ServerManagerTool.Lib
public string ServerMap;
public string ServerMapModId;
public string TotalConversionModId;
public List<string> ServerModIds;
public IEnumerable<string> ServerModIds;
public string MOTD;
public int MotDDuration;
public bool MOTDIntervalEnabled;

View file

@ -1,5 +1,6 @@
using ArkData;
using NLog;
using ServerManagerTool.Common.Extensions;
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Lib;
using ServerManagerTool.Common.Model;
@ -325,8 +326,8 @@ namespace ServerManagerTool.Lib
else if (command.command.Equals(RCON_COMMAND_GETCHAT, StringComparison.OrdinalIgnoreCase))
{
// TODO: Extract the player name from the chat
var lines = command.lines.Where(l => !String.IsNullOrEmpty(l) && l != NoResponseOutput).ToArray();
if (lines.Length == 0 && command.suppressCommand)
var lines = command.lines.Where(l => !string.IsNullOrEmpty(l) && l != NoResponseOutput);
if (lines.IsEmpty() && command.suppressCommand)
{
command.suppressOutput = true;
}
@ -398,7 +399,7 @@ namespace ServerManagerTool.Lib
}
}
var droppedPlayers = this.players.Values.Where(p => onlinePlayers.FirstOrDefault(np => np.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null).ToArray();
var droppedPlayers = this.players.Values.Where(p => onlinePlayers.FirstOrDefault(np => np.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null);
foreach (var droppedPlayer in droppedPlayers)
{
if (droppedPlayer.IsOnline)
@ -604,7 +605,7 @@ namespace ServerManagerTool.Lib
token.ThrowIfCancellationRequested();
// remove any players that do not have a player file.
var droppedPlayers = this.players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null).ToArray();
var droppedPlayers = this.players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null);
foreach (var droppedPlayer in droppedPlayers)
{
players.TryRemove(droppedPlayer.PlayerId, out PlayerInfo player);

View file

@ -87,20 +87,24 @@ namespace ServerManagerTool.Lib.ViewModel
{
Reset();
foreach(var entry in this.DinoSpawnWeightMultipliers)
foreach(var entry in this.DinoSpawnWeightMultipliers.Where(e => !string.IsNullOrWhiteSpace(e.DinoNameTag)))
{
if (string.IsNullOrWhiteSpace(entry.DinoNameTag))
continue;
var dinoSettings = this.Where(vi => vi.NameTag == entry.DinoNameTag).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
if (this.Any(d => d.NameTag == entry.DinoNameTag))
{
this.Add(CreateDinoSetting(entry.DinoNameTag, entry.Mod, entry.KnownDino, true, false));
foreach (var dinoSetting in this.Where(d => d.NameTag == entry.DinoNameTag))
{
dinoSetting.SpawnWeightMultiplier = entry.SpawnWeightMultiplier;
dinoSetting.OverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage;
dinoSetting.SpawnLimitPercentage = entry.SpawnLimitPercentage;
dinoSetting.OriginalSpawnWeightMultiplier = entry.SpawnWeightMultiplier;
dinoSetting.OriginalOverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage;
dinoSetting.OriginalSpawnLimitPercentage = entry.SpawnLimitPercentage;
}
}
dinoSettings = this.Where(vi => vi.NameTag == entry.DinoNameTag).ToArray();
foreach (var dinoSetting in dinoSettings)
else
{
var dinoSetting = CreateDinoSetting(entry.DinoNameTag, entry.Mod, entry.KnownDino, true, false);
dinoSetting.SpawnWeightMultiplier = entry.SpawnWeightMultiplier;
dinoSetting.OverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage;
dinoSetting.SpawnLimitPercentage = entry.SpawnLimitPercentage;
@ -108,115 +112,118 @@ namespace ServerManagerTool.Lib.ViewModel
dinoSetting.OriginalSpawnWeightMultiplier = entry.SpawnWeightMultiplier;
dinoSetting.OriginalOverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage;
dinoSetting.OriginalSpawnLimitPercentage = entry.SpawnLimitPercentage;
this.Add(dinoSetting);
}
}
foreach(var entry in this.PreventDinoTameClassNames)
foreach(var entry in this.PreventDinoTameClassNames.Where(e => !string.IsNullOrWhiteSpace(e)))
{
if (string.IsNullOrWhiteSpace(entry))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
if (this.Any(d => d.ClassName == entry))
{
this.Add(CreateDinoSetting(entry, GameData.MOD_UNKNOWN, false, false, true));
foreach (var dinoSetting in this.Where(d => d.ClassName == entry && !d.CanTame))
{
dinoSetting.CanTame = false;
}
}
dinoSettings = this.Where(vi => vi.ClassName == entry).ToArray();
foreach (var dinoSetting in dinoSettings)
else
{
var dinoSetting = CreateDinoSetting(entry, GameData.MOD_UNKNOWN, false, false, true);
dinoSetting.CanTame = false;
this.Add(dinoSetting);
}
}
foreach(var entry in this.NpcReplacements)
foreach(var entry in this.NpcReplacements.Where(e => !string.IsNullOrWhiteSpace(e.FromClassName)))
{
if (string.IsNullOrWhiteSpace(entry.FromClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.FromClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
if (this.Any(d => d.ClassName == entry.FromClassName))
{
this.Add(CreateDinoSetting(entry.FromClassName, GameData.MOD_UNKNOWN, false, false, true));
foreach (var dinoSetting in this.Where(d => d.ClassName == entry.FromClassName))
{
dinoSetting.CanSpawn = !string.IsNullOrWhiteSpace(entry.ToClassName);
dinoSetting.ReplacementClass = dinoSetting.CanSpawn ? entry.ToClassName : dinoSetting.ClassName;
}
}
dinoSettings = this.Where(vi => vi.ClassName == entry.FromClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
else
{
var dinoSetting = CreateDinoSetting(entry.FromClassName, GameData.MOD_UNKNOWN, false, false, true);
dinoSetting.CanSpawn = !string.IsNullOrWhiteSpace(entry.ToClassName);
dinoSetting.ReplacementClass = dinoSetting.CanSpawn ? entry.ToClassName : dinoSetting.ClassName;
this.Add(dinoSetting);
}
}
foreach (var entry in this.TamedDinoClassDamageMultipliers)
foreach (var entry in this.TamedDinoClassDamageMultipliers.Where(e => !string.IsNullOrWhiteSpace(e.ClassName)))
{
if (string.IsNullOrWhiteSpace(entry.ClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
if (this.Any(d => d.ClassName == entry.ClassName))
{
this.Add(CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true));
foreach (var dinoSetting in this.Where(d => d.ClassName == entry.ClassName && d.TamedDamageMultiplier != entry.Multiplier))
{
dinoSetting.TamedDamageMultiplier = entry.Multiplier;
}
}
dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
else
{
var dinoSetting = CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true);
dinoSetting.TamedDamageMultiplier = entry.Multiplier;
this.Add(dinoSetting);
}
}
foreach(var entry in this.TamedDinoClassResistanceMultipliers)
foreach(var entry in this.TamedDinoClassResistanceMultipliers.Where(e => !string.IsNullOrWhiteSpace(e.ClassName)))
{
if (string.IsNullOrWhiteSpace(entry.ClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
if (this.Any(d => d.ClassName == entry.ClassName))
{
this.Add(CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true));
foreach (var dinoSetting in this.Where(d => d.ClassName == entry.ClassName && d.TamedResistanceMultiplier != entry.Multiplier))
{
dinoSetting.TamedResistanceMultiplier = entry.Multiplier;
}
}
dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
else
{
var dinoSetting = CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true);
dinoSetting.TamedResistanceMultiplier = entry.Multiplier;
this.Add(dinoSetting);
}
}
foreach (var entry in this.DinoClassDamageMultipliers)
foreach (var entry in this.DinoClassDamageMultipliers.Where(e => !string.IsNullOrWhiteSpace(e.ClassName)))
{
if (string.IsNullOrWhiteSpace(entry.ClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
if (this.Any(d => d.ClassName == entry.ClassName))
{
this.Add(CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true));
foreach (var dinoSetting in this.Where(d => d.ClassName == entry.ClassName && d.WildDamageMultiplier != entry.Multiplier))
{
dinoSetting.WildDamageMultiplier = entry.Multiplier;
}
}
dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
else
{
var dinoSetting = CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true);
dinoSetting.WildDamageMultiplier = entry.Multiplier;
this.Add(dinoSetting);
}
}
foreach (var entry in this.DinoClassResistanceMultipliers)
foreach (var entry in this.DinoClassResistanceMultipliers.Where(e => !string.IsNullOrWhiteSpace(e.ClassName)))
{
if (string.IsNullOrWhiteSpace(entry.ClassName))
continue;
var dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
if (dinoSettings == null || dinoSettings.Length == 0)
if (this.Any(d => d.ClassName == entry.ClassName))
{
this.Add(CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true));
foreach (var dinoSetting in this.Where(d => d.ClassName == entry.ClassName && d.WildResistanceMultiplier != entry.Multiplier))
{
dinoSetting.WildResistanceMultiplier = entry.Multiplier;
}
}
dinoSettings = this.Where(vi => vi.ClassName == entry.ClassName).ToArray();
foreach (var dinoSetting in dinoSettings)
else
{
var dinoSetting = CreateDinoSetting(entry.ClassName, GameData.MOD_UNKNOWN, false, false, true);
dinoSetting.WildResistanceMultiplier = entry.Multiplier;
this.Add(dinoSetting);
}
}
@ -244,22 +251,9 @@ namespace ServerManagerTool.Lib.ViewModel
!entry.SpawnLimitPercentage.Equals(DinoSpawn.DEFAULT_SPAWN_LIMIT_PERCENTAGE) ||
!entry.SpawnWeightMultiplier.Equals(DinoSpawn.DEFAULT_SPAWN_WEIGHT_MULTIPLIER))
{
var dinoSpawns = this.DinoSpawnWeightMultipliers.Where(d => d.DinoNameTag.Equals(entry.NameTag, StringComparison.OrdinalIgnoreCase)).ToArray();
if (dinoSpawns == null || dinoSpawns.Length == 0)
if (this.DinoSpawnWeightMultipliers.Any(d => d.DinoNameTag.Equals(entry.NameTag, StringComparison.OrdinalIgnoreCase)))
{
this.DinoSpawnWeightMultipliers.Add(new DinoSpawn()
{
ClassName = entry.ClassName,
DinoNameTag = entry.NameTag,
OverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage,
SpawnLimitPercentage = entry.SpawnLimitPercentage,
SpawnWeightMultiplier = entry.SpawnWeightMultiplier
});
}
else
{
foreach (var dinoSpawn in dinoSpawns)
foreach (var dinoSpawn in this.DinoSpawnWeightMultipliers.Where(d => d.DinoNameTag.Equals(entry.NameTag, StringComparison.OrdinalIgnoreCase)))
{
if (entry.SpawnWeightMultiplier != entry.OriginalSpawnWeightMultiplier ||
entry.OverrideSpawnLimitPercentage != entry.OriginalOverrideSpawnLimitPercentage ||
@ -271,6 +265,17 @@ namespace ServerManagerTool.Lib.ViewModel
}
}
}
else
{
this.DinoSpawnWeightMultipliers.Add(new DinoSpawn()
{
ClassName = entry.ClassName,
DinoNameTag = entry.NameTag,
OverrideSpawnLimitPercentage = entry.OverrideSpawnLimitPercentage,
SpawnLimitPercentage = entry.SpawnLimitPercentage,
SpawnWeightMultiplier = entry.SpawnWeightMultiplier
});
}
}
}
@ -287,20 +292,28 @@ namespace ServerManagerTool.Lib.ViewModel
{
// check if the value has changed.
if (!entry.TamedDamageMultiplier.Equals(ClassMultiplier.DEFAULT_MULTIPLIER))
{
this.TamedDinoClassDamageMultipliers.Add(new ClassMultiplier() { ClassName = entry.ClassName, Multiplier = entry.TamedDamageMultiplier });
}
// check if the value has changed.
if (!entry.TamedResistanceMultiplier.Equals(ClassMultiplier.DEFAULT_MULTIPLIER))
{
this.TamedDinoClassResistanceMultipliers.Add(new ClassMultiplier() { ClassName = entry.ClassName, Multiplier = entry.TamedResistanceMultiplier });
}
}
// check if the value has changed.
if (!entry.WildDamageMultiplier.Equals(ClassMultiplier.DEFAULT_MULTIPLIER))
{
this.DinoClassDamageMultipliers.Add(new ClassMultiplier() { ClassName = entry.ClassName, Multiplier = entry.WildDamageMultiplier });
}
// check if the value has changed.
if (!entry.WildResistanceMultiplier.Equals(ClassMultiplier.DEFAULT_MULTIPLIER))
{
this.DinoClassResistanceMultipliers.Add(new ClassMultiplier() { ClassName = entry.ClassName, Multiplier = entry.WildResistanceMultiplier });
}
}
}
}

View file

@ -80,14 +80,13 @@ namespace ServerManagerTool.Lib.ViewModel
if (string.IsNullOrWhiteSpace(entry.EngramClassName))
continue;
var engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName).ToArray();
if (engramSettings == null || engramSettings.Length == 0)
if (!this.Any(vi => vi.EngramClassName == entry.EngramClassName))
{
var engram = GameData.GetEngramForClass(entry.EngramClassName);
this.Add(CreateEngramSetting(entry.EngramClassName, engram?.Mod ?? GameData.MOD_UNKNOWN, engram?.KnownEngram ?? false, engram?.IsTekgram ?? false));
}
engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName).ToArray();
var engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName);
foreach (var engramSetting in engramSettings)
{
engramSetting.EngramLevelRequirement = entry.EngramLevelRequirement;
@ -117,14 +116,13 @@ namespace ServerManagerTool.Lib.ViewModel
if (string.IsNullOrWhiteSpace(entry.EngramClassName))
continue;
var engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName).ToArray();
if (engramSettings == null || engramSettings.Length == 0)
if (!this.Any(vi => vi.EngramClassName == entry.EngramClassName))
{
var engram = GameData.GetEngramForClass(entry.EngramClassName);
this.Add(CreateEngramSetting(entry.EngramClassName, engram?.Mod ?? GameData.MOD_UNKNOWN, engram?.KnownEngram ?? false, engram?.IsTekgram ?? false));
}
engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName).ToArray();
var engramSettings = this.Where(vi => vi.EngramClassName == entry.EngramClassName);
foreach (var engramSetting in engramSettings)
{
engramSetting.EngramAutoUnlock = true;

View file

@ -60,22 +60,22 @@
<Label DockPanel.Dock="Right" Content="{DynamicResource GlobalSettings_VersionLabel}" FontSize="15" VerticalAlignment="Center" />
</DockPanel>
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_RunAsAdministratorLabel}" IsChecked="{Binding CurrentConfig.RunAsAdministratorPrompt, Mode=TwoWay}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_RunAsAdministratorLabel}" IsChecked="{Binding Config.RunAsAdministratorPrompt, Mode=TwoWay}" HorizontalAlignment="Left"/>
<Label Grid.Row="2" Grid.Column="0" Margin="1" Content="{DynamicResource GlobalSettings_StartModeLabel}" VerticalAlignment="Center"/>
<ComboBox Name="WindowStateComboBox" Grid.Row="2" Grid.Column="1" Margin="5" ItemsSource="{Binding ElementName=GlobalSettings, Path=WindowStates}" SelectedValue="{Binding CurrentConfig.MainWindow_WindowState}" SelectedValuePath="ValueMember" DisplayMemberPath="DisplayMember" PreviewMouseWheel="ComboBox_PreviewMouseWheel"/>
<CheckBox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_MinimizeToTrayLabel}" IsChecked="{Binding CurrentConfig.MainWindow_MinimizeToTray, Mode=TwoWay}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<ComboBox Name="WindowStateComboBox" Grid.Row="2" Grid.Column="1" Margin="5" ItemsSource="{Binding ElementName=GlobalSettings, Path=WindowStates}" SelectedValue="{Binding Config.MainWindow_WindowState}" SelectedValuePath="ValueMember" DisplayMemberPath="DisplayMember" PreviewMouseWheel="ComboBox_PreviewMouseWheel"/>
<CheckBox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_MinimizeToTrayLabel}" IsChecked="{Binding Config.MainWindow_MinimizeToTray, Mode=TwoWay}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_ManageFirewallLabel}" IsChecked="{Binding CurrentConfig.ManageFirewallAutomatically, Mode=TwoWay}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_ManagePublicIPLabel}" IsChecked="{Binding CurrentConfig.ManagePublicIPAutomatically, Mode=TwoWay}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_ManageFirewallLabel}" IsChecked="{Binding Config.ManageFirewallAutomatically, Mode=TwoWay}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="2" Margin="5" Content="{DynamicResource GlobalSettings_ManagePublicIPLabel}" IsChecked="{Binding Config.ManagePublicIPAutomatically, Mode=TwoWay}" HorizontalAlignment="Left"/>
<Label Grid.Row="4" Grid.Column="0" Margin="1" Content="{DynamicResource GlobalSettings_DataDirectoryLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Margin="1" Text="{Binding CurrentConfig.DataDir, Mode=TwoWay}" IsReadOnly="True" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" />
<TextBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" Margin="1" Text="{Binding Config.DataDir, Mode=TwoWay}" IsReadOnly="True" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" />
<Button Grid.Row="4" Grid.Column="3" Grid.ColumnSpan="2" Margin="5,1,0,1" VerticalAlignment="Center" HorizontalAlignment="Right" Content="{DynamicResource DataDirectoryButtonContent}" Click="SetDataDir_Click" Visibility="Hidden" />
<Button Grid.Row="4" Grid.Column="3" Grid.ColumnSpan="2" Margin="5,1,0,1" VerticalAlignment="Center" HorizontalAlignment="Right" Content="{DynamicResource DataDirectoryResetButtonContent}" Click="ResetDataDir_Click" />
<Label Grid.Row="5" Grid.Column="0" Margin="1" Content="{DynamicResource GlobalSettings_BackupDirectoryLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Margin="1" Text="{Binding CurrentConfig.BackupPath, Mode=TwoWay}" IsReadOnly="True" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center"/>
<TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Margin="1" Text="{Binding Config.BackupPath, Mode=TwoWay}" IsReadOnly="True" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center"/>
<StackPanel Grid.Row="5" Grid.Column="3" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Margin="5,1,0,1" VerticalAlignment="Center" Content="{DynamicResource BackupDirectoryButtonContent}" Click="SetBackupDir_Click"/>
<Button Margin="5,1,0,1" VerticalAlignment="Center" Content="{DynamicResource ClearButtonContent}" Click="ClearBackupDir_Click"/>
@ -141,24 +141,24 @@
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" Margin="5" IsChecked="{Binding CurrentConfig.SteamCmd_UseAnonymousCredentials}" Content="{DynamicResource GlobalSettings_SteamCmdCredentialsLabel}" VerticalAlignment="Bottom" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_SteamCmdCredentialsTooltip}" HorizontalAlignment="Left">
<CheckBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="4" Margin="5" IsChecked="{Binding Config.SteamCmd_UseAnonymousCredentials}" Content="{DynamicResource GlobalSettings_SteamCmdCredentialsLabel}" VerticalAlignment="Bottom" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_SteamCmdCredentialsTooltip}" HorizontalAlignment="Left">
<CheckBox.Style>
<Style BasedOn="{StaticResource {x:Type CheckBox}}" TargetType="{x:Type CheckBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmdRedirectOutput}" Value="true">
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<CheckBox Grid.Row="2" Grid.Column="4" Grid.ColumnSpan="4" Margin="5" Content="{DynamicResource GlobalSettings_SteamCmdRedirectOutputLabel}" IsChecked="{Binding CurrentConfig.SteamCmdRedirectOutput, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SteamCmdRedirectOutputTooltip}" HorizontalAlignment="Left" Visibility="Collapsed"/>
<CheckBox Grid.Row="2" Grid.Column="4" Grid.ColumnSpan="4" Margin="5" Content="{DynamicResource GlobalSettings_SteamCmdRedirectOutputLabel}" IsChecked="{Binding Config.SteamCmdRedirectOutput, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SteamCmdRedirectOutputTooltip}" HorizontalAlignment="Left" Visibility="Collapsed"/>
<Label Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="9" Content="{DynamicResource GlobalSettings_SteamCMDAuthentication_DisabledTooltip}" VerticalAlignment="Center">
<Label.Style>
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmdRedirectOutput}" Value="false">
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="false">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
@ -167,14 +167,14 @@
</Label>
<Label Grid.Row="4" Grid.Column="0" Margin="1" Content="{DynamicResource GlobalSettings_SteamCmdUsernameLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="4" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.SteamCmd_Username}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_SteamCmdUsernameTooltip}">
<TextBox Grid.Row="4" Grid.Column="1" Margin="1" Text="{Binding Config.SteamCmd_Username}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_SteamCmdUsernameTooltip}">
<TextBox.Style>
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmdRedirectOutput}" Value="true">
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmd_UseAnonymousCredentials}" Value="true">
<DataTrigger Binding="{Binding Config.SteamCmd_UseAnonymousCredentials}" Value="true">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
@ -186,24 +186,24 @@
<TextBox.Style>
<Style BasedOn="{StaticResource HiddenTextBoxStyle}" TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmdRedirectOutput}" Value="true">
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmd_UseAnonymousCredentials}" Value="true">
<DataTrigger Binding="{Binding Config.SteamCmd_UseAnonymousCredentials}" Value="true">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<TextBox Grid.Row="4" Grid.Column="4" Margin="1" Name="SteamPasswordTextBox" Text="{Binding CurrentConfig.SteamCmd_Password, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SteamCmdPasswordTooltip}" LostFocus="HiddenField_LostFocus" VerticalContentAlignment="Center" Visibility="Collapsed">
<TextBox Grid.Row="4" Grid.Column="4" Margin="1" Name="SteamPasswordTextBox" Text="{Binding Config.SteamCmd_Password, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SteamCmdPasswordTooltip}" LostFocus="HiddenField_LostFocus" VerticalContentAlignment="Center" Visibility="Collapsed">
<TextBox.Style>
<Style BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmdRedirectOutput}" Value="true">
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmd_UseAnonymousCredentials}" Value="true">
<DataTrigger Binding="{Binding Config.SteamCmd_UseAnonymousCredentials}" Value="true">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
@ -214,10 +214,10 @@
<Button.Style>
<Style BasedOn="{StaticResource {x:Type Button}}" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmdRedirectOutput}" Value="true">
<DataTrigger Binding="{Binding Config.SteamCmdRedirectOutput}" Value="true">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
<DataTrigger Binding="{Binding CurrentConfig.SteamCmd_UseAnonymousCredentials}" Value="true">
<DataTrigger Binding="{Binding Config.SteamCmd_UseAnonymousCredentials}" Value="true">
<Setter Property="IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
@ -251,16 +251,16 @@
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideCraftingLabel}" IsChecked="{Binding CurrentConfig.SectionCraftingOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideCraftingTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideStackSizeLabel}" IsChecked="{Binding CurrentConfig.SectionStackSizeOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideStackSizeTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="2" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideCustomEngineSettingsLabel}" IsChecked="{Binding CurrentConfig.SectionCustomEngineSettingsEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideCustomEngineSettingsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideCraftingLabel}" IsChecked="{Binding Config.SectionCraftingOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideCraftingTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideStackSizeLabel}" IsChecked="{Binding Config.SectionStackSizeOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideStackSizeTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="2" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideCustomEngineSettingsLabel}" IsChecked="{Binding Config.SectionCustomEngineSettingsEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideCustomEngineSettingsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideMapSpawnerLabel}" IsChecked="{Binding CurrentConfig.SectionMapSpawnerOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideMapSpawnerTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideSupplyCrateLabel}" IsChecked="{Binding CurrentConfig.SectionSupplyCrateOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideSupplyCrateTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="2" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverridePreventTransferLabel}" IsChecked="{Binding CurrentConfig.SectionPreventTransferOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverridePreventTransferTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideMapSpawnerLabel}" IsChecked="{Binding Config.SectionMapSpawnerOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideMapSpawnerTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideSupplyCrateLabel}" IsChecked="{Binding Config.SectionSupplyCrateOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideSupplyCrateTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="2" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverridePreventTransferLabel}" IsChecked="{Binding Config.SectionPreventTransferOverridesEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverridePreventTransferTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverridePGMLabel}" IsChecked="{Binding CurrentConfig.SectionPGMEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverridePGMTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideSOTFLabel}" IsChecked="{Binding CurrentConfig.SectionSOTFEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideSOTFTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverridePGMLabel}" IsChecked="{Binding Config.SectionPGMEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverridePGMTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CustomOverrideSOTFLabel}" IsChecked="{Binding Config.SectionSOTFEnabled, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CustomOverrideSOTFTooltip}" HorizontalAlignment="Left"/>
<TextBlock Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" Margin="5" Text="{DynamicResource GlobalSettings_CustomOverrideOptionsWarningLabel}" TextWrapping="Wrap" VerticalAlignment="Center" Foreground="Red"/>
</Grid>
@ -281,8 +281,8 @@
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<cctl:AnnotatedSlider Grid.Row="0" Grid.Column="0" Margin="0,0,5,0" Label="{DynamicResource GlobalSettings_CustomLevelXPIncreasePlayerLabel}" Value="{Binding CurrentConfig.CustomLevelXPIncrease_Player}" Minimum="1" Maximum="100000" SmallChange="1" LargeChange="10" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_XP}" ToolTip="{DynamicResource GlobalSettings_CustomLevelXPIncreasePlayerTooltip}"/>
<cctl:AnnotatedSlider Grid.Row="0" Grid.Column="1" Margin="5,0,0,0" Label="{DynamicResource GlobalSettings_CustomLevelXPIncreaseDinoLabel}" Value="{Binding CurrentConfig.CustomLevelXPIncrease_Dino}" Minimum="1" Maximum="100000" SmallChange="1" LargeChange="10" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_XP}" ToolTip="{DynamicResource GlobalSettings_CustomLevelXPIncreaseDinoTooltip}"/>
<cctl:AnnotatedSlider Grid.Row="0" Grid.Column="0" Margin="0,0,5,0" Label="{DynamicResource GlobalSettings_CustomLevelXPIncreasePlayerLabel}" Value="{Binding Config.CustomLevelXPIncrease_Player}" Minimum="1" Maximum="100000" SmallChange="1" LargeChange="10" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_XP}" ToolTip="{DynamicResource GlobalSettings_CustomLevelXPIncreasePlayerTooltip}"/>
<cctl:AnnotatedSlider Grid.Row="0" Grid.Column="1" Margin="5,0,0,0" Label="{DynamicResource GlobalSettings_CustomLevelXPIncreaseDinoLabel}" Value="{Binding Config.CustomLevelXPIncrease_Dino}" Minimum="1" Maximum="100000" SmallChange="1" LargeChange="10" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_XP}" ToolTip="{DynamicResource GlobalSettings_CustomLevelXPIncreaseDinoTooltip}"/>
</Grid>
</GroupBox>
@ -302,8 +302,8 @@
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EnableServerStatusActionsLabel}" IsChecked="{Binding CurrentConfig.ServerStatus_EnableActions, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_EnableServerStatusActionsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,0,0,5" Content="{DynamicResource GlobalSettings_ShowServerStatusActionConfirmationLabel}" IsChecked="{Binding CurrentConfig.ServerStatus_ShowActionConfirmation, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ShowServerStatusActionConfirmationTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EnableServerStatusActionsLabel}" IsChecked="{Binding Config.ServerStatus_EnableActions, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_EnableServerStatusActionsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,0,0,5" Content="{DynamicResource GlobalSettings_ShowServerStatusActionConfirmationLabel}" IsChecked="{Binding Config.ServerStatus_ShowActionConfirmation, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ShowServerStatusActionConfirmationTooltip}" HorizontalAlignment="Left"/>
</Grid>
</GroupBox>
@ -323,8 +323,8 @@
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_ValidateProfileOnServerStartLabel}" IsChecked="{Binding CurrentConfig.ValidateProfileOnServerStart, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ValidateProfileOnServerStartTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,0,0,5" Content="{DynamicResource GlobalSettings_ServerUpdateOnServerStartLabel}" IsChecked="{Binding CurrentConfig.ServerUpdate_OnServerStart, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ServerUpdateOnServerStartTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_ValidateProfileOnServerStartLabel}" IsChecked="{Binding Config.ValidateProfileOnServerStart, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ValidateProfileOnServerStartTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,0,0,5" Content="{DynamicResource GlobalSettings_ServerUpdateOnServerStartLabel}" IsChecked="{Binding Config.ServerUpdate_OnServerStart, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ServerUpdateOnServerStartTooltip}" HorizontalAlignment="Left"/>
</Grid>
</GroupBox>
@ -353,22 +353,22 @@
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Margin="5,0,0,5" IsChecked="{Binding CurrentConfig.ServerUpdate_UpdateModsWhenUpdatingServer, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_UpdateModWithServerLabel}" ToolTip="{DynamicResource GlobalSettings_UpdateModWithServerTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="3" Margin="0,0,0,5" IsChecked="{Binding CurrentConfig.ServerUpdate_ForceUpdateMods, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_ForceUpdateModsLabel}" ToolTip="{DynamicResource GlobalSettings_ForceUpdateModsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="6" Margin="0,0,0,5" IsChecked="{Binding CurrentConfig.ServerUpdate_ForceCopyMods, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_ForceCopyModsLabel}" ToolTip="{DynamicResource GlobalSettings_ForceCopyModsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Margin="5,0,0,5" IsChecked="{Binding Config.ServerUpdate_UpdateModsWhenUpdatingServer, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_UpdateModWithServerLabel}" ToolTip="{DynamicResource GlobalSettings_UpdateModWithServerTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="3" Margin="0,0,0,5" IsChecked="{Binding Config.ServerUpdate_ForceUpdateMods, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_ForceUpdateModsLabel}" ToolTip="{DynamicResource GlobalSettings_ForceUpdateModsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="6" Margin="0,0,0,5" IsChecked="{Binding Config.ServerUpdate_ForceCopyMods, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_ForceCopyModsLabel}" ToolTip="{DynamicResource GlobalSettings_ForceCopyModsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="6" Margin="5,0,0,0" IsChecked="{Binding CurrentConfig.ServerUpdate_ForceUpdateModsIfNoSteamInfo, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_ForceUpdateModsIfNoSteamInfoLabel}" ToolTip="{DynamicResource GlobalSettings_ForceUpdateModsIfNoSteamInfoTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="6" Margin="5,0,0,0" IsChecked="{Binding Config.ServerUpdate_ForceUpdateModsIfNoSteamInfo, Mode=TwoWay}" Content="{DynamicResource GlobalSettings_ForceUpdateModsIfNoSteamInfoLabel}" ToolTip="{DynamicResource GlobalSettings_ForceUpdateModsIfNoSteamInfoTooltip}" HorizontalAlignment="Left"/>
<cctl:AnnotatedSlider Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="4" Margin="0,0,5,0" Label="{DynamicResource GlobalSettings_WorkshopCacheExpiredHoursLabel}" Value="{Binding CurrentConfig.WorkshopCache_ExpiredHours}" Minimum="0" Maximum="1000" SmallChange="1" LargeChange="12" TickFrequency="24" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Hours}" ToolTip="{DynamicResource GlobalSettings_WorkshopCacheExpiredHoursTooltip}"/>
<cctl:AnnotatedSlider Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="4" Margin="0,0,5,0" Label="{DynamicResource GlobalSettings_WorkshopCacheExpiredHoursLabel}" Value="{Binding Config.WorkshopCache_ExpiredHours}" Minimum="0" Maximum="1000" SmallChange="1" LargeChange="12" TickFrequency="24" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Hours}" ToolTip="{DynamicResource GlobalSettings_WorkshopCacheExpiredHoursTooltip}"/>
</Grid>
</GroupBox>
<GroupBox Grid.Row="14" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}" IsEnabled="{Binding IsAdministrator}">
<GroupBox.Header>
<CheckBox IsChecked="{Binding CurrentConfig.AutoBackup_EnableBackup}" Content="{DynamicResource GlobalSettings_AutoBackupLabel}" VerticalAlignment="Center"/>
<CheckBox IsChecked="{Binding Config.AutoBackup_EnableBackup}" Content="{DynamicResource GlobalSettings_AutoBackupLabel}" VerticalAlignment="Center"/>
</GroupBox.Header>
<Grid IsEnabled="{Binding CurrentConfig.AutoBackup_EnableBackup}">
<Grid IsEnabled="{Binding Config.AutoBackup_EnableBackup}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
@ -385,25 +385,25 @@
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource GlobalSettings_BackupIntervalLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Width="100" HorizontalAlignment="Left" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_BackupIntervalTooltip}">
<TextBox.Text>
<Binding Path="CurrentConfig.AutoBackup_BackupPeriod" Converter="{StaticResource MinutesToTimeValueConverter}"/>
<Binding Path="Config.AutoBackup_BackupPeriod" Converter="{StaticResource MinutesToTimeValueConverter}"/>
</TextBox.Text>
</TextBox>
<CheckBox Grid.Row="0" Grid.Column="2" Margin="5,0,0,0" Content="{DynamicResource GlobalSettings_DeleteOldFilesLabel}" IsChecked="{Binding CurrentConfig.AutoBackup_DeleteOldFiles, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UseSmartCopyTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<cctl:AnnotatedSlider Grid.Row="0" Grid.Column="3" Grid.ColumnSpan="2" Margin="5,0,5,0" Label="{DynamicResource GlobalSettings_DeleteIntervalLabel}" Value="{Binding CurrentConfig.AutoBackup_DeleteInterval}" Minimum="1" Maximum="1000" SmallChange="1" LargeChange="2" TickFrequency="5" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Days}" ToolTip="{DynamicResource GlobalSettings_DeleteIntervalTooltip}" IsEnabled="{Binding CurrentConfig.AutoBackup_DeleteOldFiles}"/>
<CheckBox Grid.Row="0" Grid.Column="2" Margin="5,0,0,0" Content="{DynamicResource GlobalSettings_DeleteOldFilesLabel}" IsChecked="{Binding Config.AutoBackup_DeleteOldFiles, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UseSmartCopyTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<cctl:AnnotatedSlider Grid.Row="0" Grid.Column="3" Grid.ColumnSpan="2" Margin="5,0,5,0" Label="{DynamicResource GlobalSettings_DeleteIntervalLabel}" Value="{Binding Config.AutoBackup_DeleteInterval}" Minimum="1" Maximum="1000" SmallChange="1" LargeChange="2" TickFrequency="5" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Days}" ToolTip="{DynamicResource GlobalSettings_DeleteIntervalTooltip}" IsEnabled="{Binding Config.AutoBackup_DeleteOldFiles}"/>
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource GlobalSettings_BackupWorldSaveLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="4" Margin="1" Text="{Binding CurrentConfig.ServerBackup_WorldSaveMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_BackupWorldSaveTooltip}"/>
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="4" Margin="1" Text="{Binding Config.ServerBackup_WorldSaveMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_BackupWorldSaveTooltip}"/>
</Grid>
</GroupBox>
<GroupBox Grid.Row="15" Grid.Column="0" Grid.ColumnSpan="4" Style="{StaticResource GroupBoxStyle}" IsEnabled="{Binding IsAdministrator}">
<GroupBox.Header>
<CheckBox IsChecked="{Binding CurrentConfig.AutoUpdate_EnableUpdate}" Content="{DynamicResource GlobalSettings_AutoUpdateLabel}" VerticalAlignment="Center"/>
<CheckBox IsChecked="{Binding Config.AutoUpdate_EnableUpdate}" Content="{DynamicResource GlobalSettings_AutoUpdateLabel}" VerticalAlignment="Center"/>
</GroupBox.Header>
<Grid IsEnabled="{Binding CurrentConfig.AutoUpdate_EnableUpdate}">
<Grid IsEnabled="{Binding Config.AutoUpdate_EnableUpdate}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
@ -421,30 +421,30 @@
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource GlobalSettings_CacheDirectoryLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Grid.ColumnSpan="4" Text="{Binding CurrentConfig.AutoUpdate_CacheDir}" IsReadOnly="True" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_CacheDirectoryTooltip}"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Grid.ColumnSpan="4" Text="{Binding Config.AutoUpdate_CacheDir}" IsReadOnly="True" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_CacheDirectoryTooltip}"/>
<Button Grid.Row="0" Grid.Column="5" Margin="5,1,0,1" Content="{StaticResource CacheDirectoryButtonContent}" VerticalAlignment="Center" Click="SetCacheDir_Click"/>
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource GlobalSettings_UpdateIntervalLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="1" Width="100" HorizontalAlignment="Left" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_UpdateIntervalTooltip}">
<TextBox.Text>
<Binding Path="CurrentConfig.AutoUpdate_UpdatePeriod" Converter="{StaticResource MinutesToTimeValueConverter}"/>
<Binding Path="Config.AutoUpdate_UpdatePeriod" Converter="{StaticResource MinutesToTimeValueConverter}"/>
</TextBox.Text>
</TextBox>
<CheckBox Grid.Row="1" Grid.Column="2" Margin="5,0,0,0" Content="{DynamicResource GlobalSettings_ValidateServerFilesLabel}" IsChecked="{Binding CurrentConfig.AutoUpdate_ValidateServerFiles, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ValidateServerFilesTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="2" Margin="5,0,0,0" Content="{DynamicResource GlobalSettings_ValidateServerFilesLabel}" IsChecked="{Binding Config.AutoUpdate_ValidateServerFiles, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ValidateServerFilesTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="3" Margin="5,0,0,0" Content="{DynamicResource GlobalSettings_UseSmartCopyLabel}" IsChecked="{Binding CurrentConfig.AutoUpdate_UseSmartCopy, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UseSmartCopyTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="3" Margin="5,0,0,0" Content="{DynamicResource GlobalSettings_UseSmartCopyLabel}" IsChecked="{Binding Config.AutoUpdate_UseSmartCopy, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UseSmartCopyTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="4" Margin="5,0,0,0" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_RetryOnFailLabel}" IsChecked="{Binding CurrentConfig.AutoUpdate_RetryOnFail, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_RetryOnFailTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="4" Margin="5,0,0,0" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_RetryOnFailLabel}" IsChecked="{Binding Config.AutoUpdate_RetryOnFail, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_RetryOnFailTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="0" Margin="0,2,0,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_OverrideServerStartupLabel}" IsChecked="{Binding CurrentConfig.AutoUpdate_OverrideServerStartup, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_OverrideServerStartupTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="0" Margin="0,2,0,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_OverrideServerStartupLabel}" IsChecked="{Binding Config.AutoUpdate_OverrideServerStartup, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_OverrideServerStartupTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="3" Grid.Column="0" Margin="0,2,0,2" Grid.ColumnSpan="3" Content="{DynamicResource GlobalSettings_ParallelUpdateLabel}" IsChecked="{Binding CurrentConfig.AutoUpdate_ParallelUpdate, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ParallelUpdateTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<cctl:AnnotatedSlider Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="4" Margin="0,2,0,2" Label="{DynamicResource GlobalSettings_SequencialDelayPeriodLabel}" Value="{Binding CurrentConfig.AutoUpdate_SequencialDelayPeriod}" Minimum="0" Maximum="1200" SmallChange="1" LargeChange="2" TickFrequency="5" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Seconds}" ToolTip="{DynamicResource GlobalSettings_SequencialDelayPeriodTooltip}" IsEnabled="{Binding CurrentConfig.AutoUpdate_ParallelUpdate, Converter={StaticResource InvertBooleanConverter}}"/>
<CheckBox Grid.Row="3" Grid.Column="0" Margin="0,2,0,2" Grid.ColumnSpan="3" Content="{DynamicResource GlobalSettings_ParallelUpdateLabel}" IsChecked="{Binding Config.AutoUpdate_ParallelUpdate, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ParallelUpdateTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<cctl:AnnotatedSlider Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="4" Margin="0,2,0,2" Label="{DynamicResource GlobalSettings_SequencialDelayPeriodLabel}" Value="{Binding Config.AutoUpdate_SequencialDelayPeriod}" Minimum="0" Maximum="1200" SmallChange="1" LargeChange="2" TickFrequency="5" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Seconds}" ToolTip="{DynamicResource GlobalSettings_SequencialDelayPeriodTooltip}" IsEnabled="{Binding Config.AutoUpdate_ParallelUpdate, Converter={StaticResource InvertBooleanConverter}}"/>
<CheckBox Grid.Row="4" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_ShowUpdateReasonLabel}" IsChecked="{Binding CurrentConfig.AutoUpdate_ShowUpdateReason, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ShowUpdateReasonTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="4" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_ShowUpdateReasonLabel}" IsChecked="{Binding Config.AutoUpdate_ShowUpdateReason, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ShowUpdateReasonTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<Label Grid.Row="4" Grid.Column="2" Margin="0,2,0,2" Content="{DynamicResource GlobalSettings_UpdateReasonPrefixLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="4" Grid.Column="3" Margin="1" Grid.ColumnSpan="2" IsEnabled="{Binding CurrentConfig.AutoUpdate_ShowUpdateReason}" Text="{Binding CurrentConfig.AutoUpdate_UpdateReasonPrefix}" MaxLength="50" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_UpdateReasonPrefixTooltip}"/>
<TextBox Grid.Row="4" Grid.Column="3" Margin="1" Grid.ColumnSpan="2" IsEnabled="{Binding Config.AutoUpdate_ShowUpdateReason}" Text="{Binding Config.AutoUpdate_UpdateReasonPrefix}" MaxLength="50" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_UpdateReasonPrefixTooltip}"/>
</Grid>
</GroupBox>
@ -466,12 +466,12 @@
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Text="{DynamicResource GlobalSettings_RestartGraceIntervalInformationLabel}" TextWrapping="Wrap" VerticalAlignment="Center" FontWeight="Bold" Foreground="{DynamicResource WarningMessage}"/>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_EnableRestartGraceIntervalLabel}" IsChecked="{Binding CurrentConfig.AutoRestart_EnabledGracePeriod, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_EnableRestartGraceIntervalTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_EnableRestartGraceIntervalLabel}" IsChecked="{Binding Config.AutoRestart_EnabledGracePeriod, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_EnableRestartGraceIntervalTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource GlobalSettings_RestartGraceIntervalLabel}" ToolTip="{DynamicResource GlobalSettings_RestartGraceIntervalTooltip}" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Width="100" HorizontalAlignment="Left" VerticalContentAlignment="Center" IsEnabled="{Binding CurrentConfig.AutoRestart_EnabledGracePeriod}" ToolTip="{DynamicResource GlobalSettings_RestartGraceIntervalTooltip}">
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Width="100" HorizontalAlignment="Left" VerticalContentAlignment="Center" IsEnabled="{Binding Config.AutoRestart_EnabledGracePeriod}" ToolTip="{DynamicResource GlobalSettings_RestartGraceIntervalTooltip}">
<TextBox.Text>
<Binding Path="CurrentConfig.AutoRestart_GracePeriod" Converter="{StaticResource MinutesToTimeValueConverter}"/>
<Binding Path="Config.AutoRestart_GracePeriod" Converter="{StaticResource MinutesToTimeValueConverter}"/>
</TextBox.Text>
</TextBox>
</Grid>
@ -504,24 +504,24 @@
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4" Margin="5" Text="{DynamicResource GlobalSettings_ShutdownMessageInformationLabel}" TextWrapping="Wrap" VerticalAlignment="Center" FontWeight="Bold" Foreground="{DynamicResource WarningMessage}"/>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_CheckForOnlinePlayersLabel}" IsChecked="{Binding CurrentConfig.ServerShutdown_CheckForOnlinePlayers, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CheckForOnlinePlayersTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="2" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_SendShutdownMessagesLabel}" IsChecked="{Binding CurrentConfig.ServerShutdown_SendShutdownMessages, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SendShutdownMessagesTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_CheckForOnlinePlayersLabel}" IsChecked="{Binding Config.ServerShutdown_CheckForOnlinePlayers, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CheckForOnlinePlayersTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="2" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_SendShutdownMessagesLabel}" IsChecked="{Binding Config.ServerShutdown_SendShutdownMessages, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SendShutdownMessagesTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<cctl:AnnotatedSlider Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="1" Label="{DynamicResource GlobalSettings_ShutdownGraceIntervalLabel}" Value="{Binding CurrentConfig.ServerShutdown_GracePeriod}" Minimum="0" Maximum="60" SmallChange="1" LargeChange="5" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Minutes}" ToolTip="{DynamicResource GlobalSettings_ShutdownGraceIntervalTooltip}"/>
<cctl:AnnotatedSlider Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="1" Label="{DynamicResource GlobalSettings_ShutdownGraceIntervalLabel}" Value="{Binding Config.ServerShutdown_GracePeriod}" Minimum="0" Maximum="60" SmallChange="1" LargeChange="5" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Minutes}" ToolTip="{DynamicResource GlobalSettings_ShutdownGraceIntervalTooltip}"/>
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownMessage1Label}" VerticalAlignment="Center"/>
<TextBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding CurrentConfig.ServerShutdown_GraceMessage1}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownMessage1Tooltip}"/>
<TextBox Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_GraceMessage1}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownMessage1Tooltip}"/>
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownMessage2Label}" VerticalAlignment="Center"/>
<TextBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding CurrentConfig.ServerShutdown_GraceMessage2}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownMessage2Tooltip}"/>
<TextBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_GraceMessage2}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownMessage2Tooltip}"/>
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownMessage3Label}" VerticalAlignment="Center"/>
<TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding CurrentConfig.ServerShutdown_GraceMessage3}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownMessage3Tooltip}"/>
<TextBox Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_GraceMessage3}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownMessage3Tooltip}"/>
<Label Grid.Row="6" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownWorldSaveLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding CurrentConfig.ServerShutdown_WorldSaveMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownWorldSaveTooltip}"/>
<TextBox Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_WorldSaveMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownWorldSaveTooltip}"/>
<Label Grid.Row="8" Grid.Column="0" Content="{DynamicResource GlobalSettings_ShutdownCancelLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="8" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding CurrentConfig.ServerShutdown_CancelMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownCancelTooltip}"/>
<TextBox Grid.Row="8" Grid.Column="1" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.ServerShutdown_CancelMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_ShutdownCancelTooltip}"/>
<CheckBox Grid.Row="9" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_ShutdownAllMessagesShowReasonLabel}" IsChecked="{Binding CurrentConfig.ServerShutdown_AllMessagesShowReason, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ShutdownAllMessagesShowReasonTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="9" Grid.Column="0" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_ShutdownAllMessagesShowReasonLabel}" IsChecked="{Binding Config.ServerShutdown_AllMessagesShowReason, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_ShutdownAllMessagesShowReasonTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
</Grid>
</GroupBox>
@ -552,45 +552,48 @@
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerStopMessageLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_ServerStopMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStopMessageTooltip}"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerStopMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStopMessageTooltip}"/>
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerShutdownMessageLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_ServerShutdownMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerShutdownMessageTooltip}"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerShutdownMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerShutdownMessageTooltip}"/>
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_ServerStartedMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageTooltip}"/>
<CheckBox Grid.Row="3" Grid.Column="1" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageIncludeIPandPortLabel}" IsChecked="{Binding CurrentConfig.Alert_ServerStartedMessageIncludeIPandPort, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageIncludeIPandPortTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerStartedMessage}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageTooltip}"/>
<CheckBox Grid.Row="3" Grid.Column="1" Margin="0,2,20,2" Grid.ColumnSpan="2" Content="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageIncludeIPandPortLabel}" IsChecked="{Binding Config.Alert_ServerStartedMessageIncludeIPandPort, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStartedMessageIncludeIPandPortTooltip}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_BackupProcessErrorLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="4" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_BackupProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_BackupProcessErrorTooltip}"/>
<TextBox Grid.Row="4" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_BackupProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_BackupProcessErrorTooltip}"/>
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ShutdownProcessErrorLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="5" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_ShutdownProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ShutdownProcessErrorTooltip}"/>
<TextBox Grid.Row="5" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ShutdownProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ShutdownProcessErrorTooltip}"/>
<Label Grid.Row="6" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_RestartProcessErrorLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="6" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_RestartProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_RestartProcessErrorTooltip}"/>
<TextBox Grid.Row="6" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_RestartProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_RestartProcessErrorTooltip}"/>
<Label Grid.Row="7" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_UpdateProcessErrorLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="7" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_UpdateProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_UpdateProcessErrorTooltip}"/>
<TextBox Grid.Row="7" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_UpdateProcessError}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_UpdateProcessErrorTooltip}"/>
<Label Grid.Row="8" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_UpdateResultsLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="8" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_UpdateResults}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_UpdateResultsTooltip}"/>
<TextBox Grid.Row="8" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_UpdateResults}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_UpdateResultsTooltip}"/>
<Label Grid.Row="9" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerUpdateLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="9" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_ServerUpdate}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerUpdateTooltip}"/>
<TextBox Grid.Row="9" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerUpdate}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerUpdateTooltip}"/>
<Label Grid.Row="10" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ServerStatusChangeLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="10" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_ServerStatusChange}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStatusChangeTooltip}"/>
<TextBox Grid.Row="10" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ServerStatusChange}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ServerStatusChangeTooltip}"/>
<Label Grid.Row="11" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ModUpdateDetectedLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="11" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_ModUpdateDetected}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ModUpdateDetectedTooltip}"/>
<TextBox Grid.Row="11" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ModUpdateDetected}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ModUpdateDetectedTooltip}"/>
<Label Grid.Row="12" Grid.Column="0" Content="{DynamicResource GlobalSettings_Alerts_ForceRespawnDinosLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="12" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Alert_ForceRespawnDinos}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ForceRespawnDinosTooltip}"/>
<TextBox Grid.Row="12" Grid.Column="1" Margin="1" Text="{Binding Config.Alert_ForceRespawnDinos}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_Alerts_ForceRespawnDinosTooltip}"/>
</Grid>
</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"/>
<CheckBox IsChecked="{Binding Config.DiscordBotEnabled}" Content="{DynamicResource GlobalSettings_DiscordBotLabel}" VerticalAlignment="Center"/>
</GroupBox.Header>
<Grid IsEnabled="{Binding CurrentConfig.DiscordBotEnabled}">
<Grid IsEnabled="{Binding Config.DiscordBotEnabled}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" MinHeight="25"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="60"/>
@ -607,24 +610,77 @@
<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"/>
<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 CurrentConfig.DiscordBotServerId}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_DiscordBotServerTooltip}"/>
<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 CurrentConfig.DiscordBotPrefix}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_DiscordBotPrefixTooltip}"/>
<TextBox Grid.Row="2" Grid.Column="4" Margin="1" Text="{Binding Config.DiscordBotPrefix}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_DiscordBotPrefixTooltip}"/>
<Label Grid.Row="2" Grid.Column="6" Margin="1" Content="{DynamicResource GlobalSettings_DiscordBotLogLevelLabel}" VerticalAlignment="Center"/>
<ComboBox Name="DiscordBotLogLevelComboBox" Grid.Row="2" Grid.Column="7" Margin="1" ItemsSource="{Binding ElementName=GlobalSettings, Path=DiscordBotLogLevels}" SelectedValue="{Binding Config.DiscordBotLogLevel}" SelectedValuePath="ValueMember" DisplayMemberPath="DisplayMember" VerticalContentAlignment="Center" PreviewMouseWheel="ComboBox_PreviewMouseWheel"/>
<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="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 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}"/>
<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}"/>
<GroupBox Grid.Row="5" Grid.Column="3" Grid.RowSpan="3" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" MinHeight="200" IsEnabled="{Binding Config.DiscordBotAllowAllBots, Converter={StaticResource InvertBooleanConverter}}">
<GroupBox.Header>
<StackPanel Orientation="Horizontal">
<Label Content="{DynamicResource GlobalSettings_DiscordBotWhitelistLabel}"/>
<Button Click="AddDiscordBotWhitelist_Click" Margin="20,0,0,0" ToolTip="{DynamicResource ServerSettings_AddDiscordBotWhitelistTooltip}" Style="{StaticResource ButtonStyle1}">
<Image Source="../Art/Add.ico"/>
</Button>
<Button Click="ClearDiscordBotWhitelists_Click" Margin="5,0,0,0" ToolTip="{DynamicResource ServerSettings_ClearDiscordBotWhitelistTooltip}" Style="{StaticResource ButtonStyle1}">
<Image Source="../Art/Delete.ico"/>
</Button>
</StackPanel>
</GroupBox.Header>
<DataGrid x:Name="DiscordBotWhitelistGrid" ItemsSource="{Binding DiscordBotWhitelist, ElementName=GlobalSettings}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="true" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25" IsReadOnly="False">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>
</Style.Resources>
</Style>
</DataGrid.Resources>
<DataGrid.HorizontalGridLinesBrush>
<SolidColorBrush Color="#FFB4B4B4"/>
</DataGrid.HorizontalGridLinesBrush>
<DataGrid.VerticalGridLinesBrush>
<SolidColorBrush Color="#FFB4B4B4"/>
</DataGrid.VerticalGridLinesBrush>
<DataGrid.Columns>
<DataGridTextColumn Width="*" Binding="{Binding BotId}">
<DataGridTextColumn.Header>
<TextBlock Text="{DynamicResource GlobalSettings_DiscordBotWhitelistIdLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTemplateColumn Width="30" CanUserReorder="False" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Width="22" Height="22" Margin="0" IsTabStop="False" HorizontalAlignment="Center" VerticalAlignment="Center" Click="RemoveDiscordBotWhitelist_Click" ToolTip="{DynamicResource ServerSettings_RemoveDiscordBotWhitelistTooltip}">
<Image Source="../Art/Delete.ico"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</GroupBox>
<CheckBox Grid.Row="6" Grid.Column="1" Margin="0,5,0,5" IsChecked="{Binding Config.DiscordBotAllowAllBots}" Content="{DynamicResource ServerSettings_DiscordBotAllowAllBotsLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_DiscordBotAllowAllBotsTooltip}"/>
</Grid>
</GroupBox>
@ -651,22 +707,22 @@
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource GlobalSettings_EmailHostLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Email_Host}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailHostTooltip}"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="1" Text="{Binding Config.Email_Host}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailHostTooltip}"/>
<Label Grid.Row="0" Grid.Column="3" Content="{DynamicResource GlobalSettings_EmailPortLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="4" Margin="1" Text="{Binding CurrentConfig.Email_Port}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailPortTooltip}"/>
<CheckBox Grid.Row="0" Grid.Column="7" Content="{DynamicResource GlobalSettings_EmailUseSSLLabel}" IsChecked="{Binding CurrentConfig.Email_UseSSL}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailUseSSLTooltip}" HorizontalAlignment="Left"/>
<TextBox Grid.Row="0" Grid.Column="4" Margin="1" Text="{Binding Config.Email_Port}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailPortTooltip}"/>
<CheckBox Grid.Row="0" Grid.Column="7" Content="{DynamicResource GlobalSettings_EmailUseSSLLabel}" IsChecked="{Binding Config.Email_UseSSL}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailUseSSLTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="1" Content="{DynamicResource GlobalSettings_EmailUseDefaultCredentialsLabel}" IsChecked="{Binding CurrentConfig.Email_UseDetaultCredentials}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailUseDefaultCredentialsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="1" Content="{DynamicResource GlobalSettings_EmailUseDefaultCredentialsLabel}" IsChecked="{Binding Config.Email_UseDetaultCredentials}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailUseDefaultCredentialsTooltip}" HorizontalAlignment="Left"/>
<Label Grid.Row="1" Grid.Column="3" Content="{DynamicResource GlobalSettings_EmailUsernameLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="4" Margin="1" Text="{Binding CurrentConfig.Email_Username}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailUsernameTooltip}" IsEnabled="{Binding CurrentConfig.Email_UseDetaultCredentials, Converter={StaticResource InvertBooleanConverter}}"/>
<TextBox Grid.Row="1" Grid.Column="4" Margin="1" Text="{Binding Config.Email_Username}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailUsernameTooltip}" IsEnabled="{Binding Config.Email_UseDetaultCredentials, Converter={StaticResource InvertBooleanConverter}}"/>
<Label Grid.Row="1" Grid.Column="6" Content="{DynamicResource GlobalSettings_EmailPasswordLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="7" Margin="1" Name="HideEmailPasswordTextBox" Text="{DynamicResource ServerSettings_HidePasswordText}" IsEnabled="{Binding CurrentConfig.Email_UseDetaultCredentials, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ServerSettings_HidePasswordTooltip}" GotFocus="HiddenField_GotFocus" Style="{StaticResource HiddenTextBoxStyle}"/>
<TextBox Grid.Row="1" Grid.Column="7" Margin="1" Name="EmailPasswordTextBox" Text="{Binding CurrentConfig.Email_Password, Mode=TwoWay}" IsEnabled="{Binding CurrentConfig.Email_UseDetaultCredentials, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource GlobalSettings_EmailPasswordTooltip}" LostFocus="HiddenField_LostFocus" VerticalContentAlignment="Center" Visibility="Collapsed"/>
<TextBox Grid.Row="1" Grid.Column="7" Margin="1" Name="HideEmailPasswordTextBox" Text="{DynamicResource ServerSettings_HidePasswordText}" IsEnabled="{Binding Config.Email_UseDetaultCredentials, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource ServerSettings_HidePasswordTooltip}" GotFocus="HiddenField_GotFocus" Style="{StaticResource HiddenTextBoxStyle}"/>
<TextBox Grid.Row="1" Grid.Column="7" Margin="1" Name="EmailPasswordTextBox" Text="{Binding Config.Email_Password, Mode=TwoWay}" IsEnabled="{Binding Config.Email_UseDetaultCredentials, Converter={StaticResource InvertBooleanConverter}}" ToolTip="{DynamicResource GlobalSettings_EmailPasswordTooltip}" LostFocus="HiddenField_LostFocus" VerticalContentAlignment="Center" Visibility="Collapsed"/>
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource GlobalSettings_EmailFromLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Text="{Binding CurrentConfig.Email_From}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailFromTooltip}"/>
<TextBox Grid.Row="2" Grid.Column="1" Margin="1" Text="{Binding Config.Email_From}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailFromTooltip}"/>
<Label Grid.Row="2" Grid.Column="3" Content="{DynamicResource GlobalSettings_EmailToLabel}" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="4" Grid.ColumnSpan="3" Margin="1" Text="{Binding CurrentConfig.Email_To}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailToTooltip}"/>
<TextBox Grid.Row="2" Grid.Column="4" Grid.ColumnSpan="3" Margin="1" Text="{Binding Config.Email_To}" IsReadOnlyCaretVisible="True" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailToTooltip}"/>
<Button Grid.Row="2" Grid.Column="7" Margin="1" Padding="5,2,5,0" Content="{DynamicResource GlobalSettings_EmailTestButtonLabel}" Click="SendTestEmail_Click" HorizontalAlignment="Right"/>
</Grid>
</GroupBox>
@ -688,10 +744,10 @@
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_AutoBackupLabel}" IsChecked="{Binding CurrentConfig.EmailNotify_AutoBackup}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_AutoBackupTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_AutoUpdateLabel}" IsChecked="{Binding CurrentConfig.EmailNotify_AutoUpdate}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_AutoUpdateTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="2" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_AutoRestartLabel}" IsChecked="{Binding CurrentConfig.EmailNotify_AutoRestart}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_AutoRestartTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="3" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_ShutdownRestartLabel}" IsChecked="{Binding CurrentConfig.EmailNotify_ShutdownRestart}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_ShutdownRestartTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_AutoBackupLabel}" IsChecked="{Binding Config.EmailNotify_AutoBackup}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_AutoBackupTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_AutoUpdateLabel}" IsChecked="{Binding Config.EmailNotify_AutoUpdate}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_AutoUpdateTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="2" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_AutoRestartLabel}" IsChecked="{Binding Config.EmailNotify_AutoRestart}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_AutoRestartTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="0" Grid.Column="3" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_EmailNotify_ShutdownRestartLabel}" IsChecked="{Binding Config.EmailNotify_ShutdownRestart}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_EmailNotify_ShutdownRestartTooltip}" HorizontalAlignment="Left"/>
</Grid>
</GroupBox>
@ -715,16 +771,16 @@
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" Text="{DynamicResource GlobalSettings_AdvancedSettingsInformationLabel}" TextWrapping="Wrap" VerticalAlignment="Center" FontWeight="Bold" Foreground="{DynamicResource WarningMessage}"/>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_UseShutdownCommandLabel}" IsChecked="{Binding CurrentConfig.ServerShutdown_UseShutdownCommand}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_UseShutdownCommandTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_BackupWorldFileLabel}" IsChecked="{Binding CurrentConfig.BackupWorldFile, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_BackupWorldFileTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_UseShutdownCommandLabel}" IsChecked="{Binding Config.ServerShutdown_UseShutdownCommand}" VerticalAlignment="Center" VerticalContentAlignment="Center" ToolTip="{DynamicResource GlobalSettings_UseShutdownCommandTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="1" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_BackupWorldFileLabel}" IsChecked="{Binding Config.BackupWorldFile, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_BackupWorldFileTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CloseShutdownWindowWhenFinishedLabel}" IsChecked="{Binding CurrentConfig.CloseShutdownWindowWhenFinished, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CloseShutdownWindowWhenFinishedTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_VerifyServerAfterUpdateLabel}" IsChecked="{Binding CurrentConfig.AutoUpdate_VerifyServerAfterUpdate, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_VerifyServerAfterUpdateTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_CloseShutdownWindowWhenFinishedLabel}" IsChecked="{Binding Config.CloseShutdownWindowWhenFinished, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_CloseShutdownWindowWhenFinishedTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="2" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_VerifyServerAfterUpdateLabel}" IsChecked="{Binding Config.AutoUpdate_VerifyServerAfterUpdate, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_VerifyServerAfterUpdateTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="3" Grid.Column="0" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_SteamCmdRemoveQuitLabel}" IsChecked="{Binding CommonConfig.SteamCmdRemoveQuit, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_SteamCmdRemoveQuitTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="3" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_UpdateDirectoryPermissionsLabel}" IsChecked="{Binding CurrentConfig.UpdateDirectoryPermissions, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UpdateDirectoryPermissionsTooltip}" HorizontalAlignment="Left"/>
<CheckBox Grid.Row="3" Grid.Column="1" Margin="5,0,5,5" Content="{DynamicResource GlobalSettings_UpdateDirectoryPermissionsLabel}" IsChecked="{Binding Config.UpdateDirectoryPermissions, Mode=TwoWay}" ToolTip="{DynamicResource GlobalSettings_UpdateDirectoryPermissionsTooltip}" HorizontalAlignment="Left"/>
<cctl:AnnotatedSlider Grid.Row="4" Grid.Column="0" Margin="1" Label="{DynamicResource GlobalSettings_WorldSaveDelayLabel}" Value="{Binding CurrentConfig.ServerShutdown_WorldSaveDelay, Converter={cc:IntRangeValueConverter 10, 300}}" Minimum="10" Maximum="300" SmallChange="10" LargeChange="50" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Seconds}" ToolTip="{DynamicResource GlobalSettings_WorldSaveDelayTooltip}"/>
<cctl:AnnotatedSlider Grid.Row="4" Grid.Column="0" Margin="1" Label="{DynamicResource GlobalSettings_WorldSaveDelayLabel}" Value="{Binding Config.ServerShutdown_WorldSaveDelay, Converter={cc:IntRangeValueConverter 10, 300}}" Minimum="10" Maximum="300" SmallChange="10" LargeChange="50" TickFrequency="1" LabelRelativeWidth="Auto" SliderRelativeWidth="15*" SuffixRelativeWidth="Auto" Suffix="{DynamicResource SliderUnits_Seconds}" ToolTip="{DynamicResource GlobalSettings_WorldSaveDelayTooltip}"/>
</Grid>
</GroupBox>

View file

@ -5,13 +5,16 @@ using ServerManagerTool.Common.Lib;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Xml;
using WPFSharp.Globalizer;
@ -24,27 +27,46 @@ namespace ServerManagerTool
public partial class GlobalSettingsControl : UserControl
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
public static readonly DependencyProperty AppInstanceProperty = DependencyProperty.Register(nameof(AppInstance), typeof(App), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty IsAdministratorProperty = DependencyProperty.Register(nameof(IsAdministrator), typeof(bool), typeof(GlobalSettingsControl), new PropertyMetadata(false));
public static readonly DependencyProperty CurrentConfigProperty = DependencyProperty.Register(nameof(CurrentConfig), typeof(Config), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(nameof(Config), typeof(Config), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty CommonConfigProperty = DependencyProperty.Register(nameof(CommonConfig), typeof(CommonConfig), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty WindowStatesProperty = DependencyProperty.Register(nameof(WindowStates), typeof(ComboBoxItemList), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty DiscordBotLogLevelsProperty = DependencyProperty.Register(nameof(DiscordBotLogLevels), typeof(ComboBoxItemList), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty DiscordBotWhitelistProperty = DependencyProperty.Register(nameof(DiscordBotWhitelist), typeof(List<DiscordBotWhitelist>), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public GlobalSettingsControl()
{
this.Version = GetDeployedVersion();
this.CurrentConfig = Config.Default;
this.AppInstance = App.Instance;
this.Config = Config.Default;
this.CommonConfig = CommonConfig.Default;
this.DataContext = this;
PopulateWindowsStatesComboBox();
this.IsAdministrator = SecurityUtils.IsAdministrator();
this.Version = GetDeployedVersion();
InitializeComponent();
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
this.IsAdministrator = SecurityUtils.IsAdministrator();
PopulateWindowsStatesComboBox();
PopulateDiscordBotLogLevelsComboBox();
DiscordBotWhitelist = new List<DiscordBotWhitelist>();
if (Config.DiscordBotWhitelist != null)
{
foreach (var item in Config.DiscordBotWhitelist)
{
DiscordBotWhitelist.Add(new DiscordBotWhitelist() { BotId = item });
}
}
this.DataContext = this;
}
public App AppInstance
{
get { return GetValue(AppInstanceProperty) as App; }
set { SetValue(AppInstanceProperty, value); }
}
public string Version
@ -53,10 +75,10 @@ namespace ServerManagerTool
set;
}
public Config CurrentConfig
public Config Config
{
get { return GetValue(CurrentConfigProperty) as Config; }
set { SetValue(CurrentConfigProperty, value); }
get { return GetValue(ConfigProperty) as Config; }
set { SetValue(ConfigProperty, value); }
}
public CommonConfig CommonConfig
@ -77,6 +99,27 @@ namespace ServerManagerTool
set { SetValue(WindowStatesProperty, value); }
}
public ComboBoxItemList DiscordBotLogLevels
{
get { return (ComboBoxItemList)GetValue(DiscordBotLogLevelsProperty); }
set { SetValue(DiscordBotLogLevelsProperty, value); }
}
public List<DiscordBotWhitelist> DiscordBotWhitelist
{
get { return (List<DiscordBotWhitelist>)GetValue(DiscordBotWhitelistProperty); }
set { SetValue(DiscordBotWhitelistProperty, value); }
}
public void ApplyChangesToConfig()
{
if (Config.DiscordBotWhitelist is null)
Config.DiscordBotWhitelist = new System.Collections.Specialized.StringCollection();
Config.DiscordBotWhitelist.Clear();
Config.DiscordBotWhitelist.AddRange(DiscordBotWhitelist.Select(i => i.BotId).ToArray());
}
private string GetDeployedVersion()
{
XmlDocument xmlDoc = new XmlDocument();
@ -148,14 +191,24 @@ namespace ServerManagerTool
if (result == CommonFileDialogResult.Ok)
{
if (!String.Equals(dialog.FileName, Config.Default.DataDir))
if (!string.Equals(dialog.FileName, Config.Default.DataDir))
{
try
{
var newDataDirectory = dialog.FileName;
if (!string.IsNullOrWhiteSpace(newDataDirectory))
{
var root = Path.GetPathRoot(newDataDirectory);
if (!root.EndsWith("\\"))
{
newDataDirectory = newDataDirectory.Replace(root, root + "\\");
}
}
// Set up the destination directories
string newConfigDirectory = Path.Combine(dialog.FileName, Config.Default.ProfilesDir);
string newConfigDirectory = Path.Combine(newDataDirectory, Config.Default.ProfilesDir);
string oldSteamDirectory = Path.Combine(Config.Default.DataDir, Config.Default.SteamCmdDir);
string newSteamDirectory = Path.Combine(dialog.FileName, Config.Default.SteamCmdDir);
string newSteamDirectory = Path.Combine(newDataDirectory, Config.Default.SteamCmdDir);
Directory.CreateDirectory(newConfigDirectory);
Directory.CreateDirectory(newSteamDirectory);
@ -189,7 +242,7 @@ namespace ServerManagerTool
Directory.Delete(oldSteamDirectory, true);
// Update the config
Config.Default.DataDir = dialog.FileName;
Config.Default.DataDir = newDataDirectory;
Config.Default.ConfigDirectory = newConfigDirectory;
App.ReconfigureLogging();
}
@ -228,9 +281,18 @@ namespace ServerManagerTool
if (result == CommonFileDialogResult.Ok)
{
if (!String.Equals(dialog.FileName, Config.Default.BackupPath))
if (!string.Equals(dialog.FileName, Config.Default.BackupPath))
{
Config.Default.BackupPath = dialog.FileName;
if (!string.IsNullOrWhiteSpace(Config.Default.BackupPath))
{
var root = Path.GetPathRoot(Config.Default.BackupPath);
if (!root.EndsWith("\\"))
{
Config.Default.BackupPath = Config.Default.BackupPath.Replace(root, root + "\\");
}
}
}
}
}
@ -250,9 +312,18 @@ namespace ServerManagerTool
if (result == CommonFileDialogResult.Ok)
{
if (!String.Equals(dialog.FileName, Config.Default.AutoUpdate_CacheDir))
if (!string.Equals(dialog.FileName, Config.Default.AutoUpdate_CacheDir))
{
Config.Default.AutoUpdate_CacheDir = dialog.FileName;
if (!string.IsNullOrWhiteSpace(Config.Default.AutoUpdate_CacheDir))
{
var root = Path.GetPathRoot(Config.Default.AutoUpdate_CacheDir);
if (!root.EndsWith("\\"))
{
Config.Default.AutoUpdate_CacheDir = Config.Default.AutoUpdate_CacheDir.Replace(root, root + "\\");
}
}
}
}
}
@ -328,16 +399,16 @@ namespace ServerManagerTool
private void LanguageSelectionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CurrentConfig.CultureName = AvailableLanguages.Instance.SelectedLanguage;
Config.CultureName = AvailableLanguages.Instance.SelectedLanguage;
PopulateWindowsStatesComboBox();
App.Instance.OnResourceDictionaryChanged(CurrentConfig.CultureName);
App.Instance.OnResourceDictionaryChanged(Config.CultureName);
}
private void StyleSelectionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CurrentConfig.StyleName = AvailableStyles.Instance.SelectedStyle;
Config.StyleName = AvailableStyles.Instance.SelectedStyle;
}
private void HiddenField_GotFocus(object sender, RoutedEventArgs e)
@ -419,20 +490,68 @@ namespace ServerManagerTool
private void PopulateWindowsStatesComboBox()
{
var selectedValue = this.WindowStateComboBox?.SelectedValue ?? CurrentConfig.MainWindow_WindowState;
var windowStates = new ComboBoxItemList();
var selectedValue = this.WindowStateComboBox?.SelectedValue ?? Config.MainWindow_WindowState;
var comboBoxList = new ComboBoxItemList();
foreach (WindowState windowState in Enum.GetValues(typeof(WindowState)))
{
var displayMember = _globalizer.GetResourceString($"WindowState_{windowState}") ?? windowState.ToString();
windowStates.Add(new Common.Model.ComboBoxItem(windowState.ToString(), displayMember));
comboBoxList.Add(new Common.Model.ComboBoxItem(windowState.ToString(), displayMember));
}
this.WindowStates = windowStates;
this.WindowStates = comboBoxList;
if (this.WindowStateComboBox != null)
{
this.WindowStateComboBox.SelectedValue = selectedValue;
}
}
private void PopulateDiscordBotLogLevelsComboBox()
{
var selectedValue = this.DiscordBotLogLevelComboBox?.SelectedValue ?? Config.DiscordBotLogLevel;
var comboBoxList = new ComboBoxItemList();
foreach (DiscordBot.Enums.LogLevel logLevel in Enum.GetValues(typeof(DiscordBot.Enums.LogLevel)))
{
var displayMember = _globalizer.GetResourceString($"DiscordBotLogLevel_{logLevel}") ?? logLevel.ToString();
comboBoxList.Add(new Common.Model.ComboBoxItem(logLevel.ToString(), displayMember));
}
this.DiscordBotLogLevels = comboBoxList;
if (this.DiscordBotLogLevelComboBox != null)
{
this.DiscordBotLogLevelComboBox.SelectedValue = selectedValue;
}
}
#region Discord Bot Whitelist
private void AddDiscordBotWhitelist_Click(object sender, RoutedEventArgs e)
{
DiscordBotWhitelist.Add(new DiscordBotWhitelist());
CollectionViewSource.GetDefaultView(DiscordBotWhitelistGrid.ItemsSource).Refresh();
}
private void ClearDiscordBotWhitelists_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show(_globalizer.GetResourceString("ServerSettings_ClearLabel"), _globalizer.GetResourceString("ServerSettings_ClearTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
return;
DiscordBotWhitelist.Clear();
CollectionViewSource.GetDefaultView(DiscordBotWhitelistGrid.ItemsSource).Refresh();
}
private void RemoveDiscordBotWhitelist_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show(_globalizer.GetResourceString("ServerSettings_DeleteLabel"), _globalizer.GetResourceString("ServerSettings_DeleteTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
return;
var item = ((DiscordBotWhitelist)((Button)e.Source).DataContext);
DiscordBotWhitelist.Remove(item);
CollectionViewSource.GetDefaultView(DiscordBotWhitelistGrid.ItemsSource).Refresh();
}
#endregion
}
}

View file

@ -528,7 +528,7 @@
<ScrollViewer DataContext="{Binding Profile}" VerticalScrollBarVisibility="Visible">
<StackPanel CanVerticallyScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto">
<Expander Name="SectionAdministration" IsExpanded="{Binding CurrentConfig.SectionAdministrationIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionAdministration" IsExpanded="{Binding Config.SectionAdministrationIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_AdministrationSectionLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -869,7 +869,7 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="{Binding CurrentConfig.MOTDHeight, ElementName=SettingsControl, FallbackValue=100, Mode=TwoWay}" MinHeight="100"/>
<RowDefinition Height="{Binding Config.MOTDHeight, ElementName=SettingsControl, FallbackValue=100, Mode=TwoWay}" MinHeight="100"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
@ -1395,7 +1395,7 @@
</Grid>
</Expander>
<Expander Name="SectionAutomaticManagement" IsExpanded="{Binding CurrentConfig.SectionAutomaticManagementIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionAutomaticManagement" IsExpanded="{Binding Config.SectionAutomaticManagementIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<DockPanel>
<TextBlock DockPanel.Dock="Left" Text="{DynamicResource ServerSettings_AutomaticManagementLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -1579,7 +1579,7 @@
</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 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}"/>
@ -1618,6 +1618,9 @@
<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" />
<Label Grid.Row="0" Grid.Column="2" Content="{DynamicResource ServerSettings_DiscordAliasLabel}" ToolTip="{DynamicResource ServerSettings_DiscordAliasTooltip}" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="3" Margin="1" Text="{Binding DiscordAlias, Mode=TwoWay}" ToolTip="{DynamicResource ServerSettings_DiscordAliasTooltip}" 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}"/>
@ -1628,7 +1631,7 @@
</Grid>
</Expander>
<Expander Name="SectionRules" IsExpanded="{Binding CurrentConfig.SectionRulesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionRules" IsExpanded="{Binding Config.SectionRulesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_RulesLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -2071,7 +2074,7 @@
</Grid>
</Expander>
<Expander Name="SectionChatAndNotifications" IsExpanded="{Binding CurrentConfig.SectionChatAndNotificationsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionChatAndNotifications" IsExpanded="{Binding Config.SectionChatAndNotificationsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_ChatAndNotificationsLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -2118,7 +2121,7 @@
</Grid>
</Expander>
<Expander Name="SectionHUDAndVisuals" IsExpanded="{Binding CurrentConfig.SectionHUDAndVisualsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionHUDAndVisuals" IsExpanded="{Binding Config.SectionHUDAndVisualsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_HUDAndVisualsLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -2170,7 +2173,7 @@
</Grid>
</Expander>
<Expander Name="SectionPlayerSettings" IsExpanded="{Binding CurrentConfig.SectionPlayerSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionPlayerSettings" IsExpanded="{Binding Config.SectionPlayerSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_PlayerSettingsLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -2283,7 +2286,7 @@
</Grid>
</Expander>
<Expander Name="SectionDinoSettings" IsExpanded="{Binding CurrentConfig.SectionDinoSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionDinoSettings" IsExpanded="{Binding Config.SectionDinoSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_DinoSettingsLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -2420,7 +2423,7 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="{Binding CurrentConfig.DinoSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.DinoSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -2729,6 +2732,9 @@
<DataTrigger Binding="{Binding Mod}" Value="CrystalIsles">
<Setter Property="Background" Value="#FFD6D6" />
</DataTrigger>
<DataTrigger Binding="{Binding Mod}" Value="LostIsland">
<Setter Property="Background" Value="#D9F7C4" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
@ -2976,7 +2982,7 @@
</Grid>
</Expander>
<Expander Name="SectionEnvironment" IsExpanded="{Binding CurrentConfig.SectionEnvironmentIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionEnvironment" IsExpanded="{Binding Config.SectionEnvironmentIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_EnvironmentLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -3035,7 +3041,7 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="{Binding CurrentConfig.EnvironmentListBoxHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.EnvironmentListBoxHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -3121,6 +3127,9 @@
<DataTrigger Binding="{Binding Mod}" Value="CrystalIsles">
<Setter Property="Background" Value="#FFD6D6" />
</DataTrigger>
<DataTrigger Binding="{Binding Mod}" Value="LostIsland">
<Setter Property="Background" Value="#D9F7C4" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
@ -3162,7 +3171,7 @@
</Grid>
</Expander>
<Expander Name="SectionStructures" IsExpanded="{Binding CurrentConfig.SectionStructuresIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionStructures" IsExpanded="{Binding Config.SectionStructuresIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_StructuresLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -3283,7 +3292,7 @@
</Grid>
</Expander>
<Expander Name="SectionEngrams" IsExpanded="{Binding CurrentConfig.SectionEngramsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionEngrams" IsExpanded="{Binding Config.SectionEngramsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_EngramsLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -3312,7 +3321,7 @@
<Grid Margin="-8,0,2,0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="{Binding CurrentConfig.EngramsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.EngramsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -3640,6 +3649,9 @@
<DataTrigger Binding="{Binding Mod}" Value="CrystalIsles">
<Setter Property="Background" Value="#FFD6D6" />
</DataTrigger>
<DataTrigger Binding="{Binding Mod}" Value="LostIsland">
<Setter Property="Background" Value="#D9F7C4" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
@ -3651,7 +3663,7 @@
</Grid>
</Expander>
<Expander Name="SectionServerFiles" IsExpanded="{Binding CurrentConfig.SectionServerFilesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionServerFiles" IsExpanded="{Binding Config.SectionServerFilesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_ServerFilesLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -3675,7 +3687,7 @@
<Grid Margin="-8,0,2,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="{Binding CurrentConfig.ServerFilesGridHeight, ElementName=SettingsControl, FallbackValue=250, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.ServerFilesGridHeight, ElementName=SettingsControl, FallbackValue=250, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -3955,7 +3967,7 @@
</Grid>
</Expander>
<Expander Name="SectionCustomGameUserSettings" IsExpanded="{Binding CurrentConfig.SectionCustomGameUserSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionCustomGameUserSettings" IsExpanded="{Binding Config.SectionCustomGameUserSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_CustomGameUserSettingsLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -3978,7 +3990,7 @@
<Grid Margin="-8,0,2,0">
<Grid.RowDefinitions>
<RowDefinition Height="{Binding CurrentConfig.CustomGameUserSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.CustomGameUserSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -4114,7 +4126,7 @@
</Grid>
</Expander>
<Expander Name="SectionCustomGameSettings" IsExpanded="{Binding CurrentConfig.SectionCustomGameSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionCustomGameSettings" IsExpanded="{Binding Config.SectionCustomGameSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_CustomGameSettingsLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -4137,7 +4149,7 @@
<Grid Margin="-8,0,2,0">
<Grid.RowDefinitions>
<RowDefinition Height="{Binding CurrentConfig.CustomGameSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.CustomGameSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -4273,7 +4285,7 @@
</Grid>
</Expander>
<Expander Name="SectionCustomEngineSettings" IsExpanded="{Binding CurrentConfig.SectionCustomEngineSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding CurrentConfig.SectionCustomEngineSettingsEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander Name="SectionCustomEngineSettings" IsExpanded="{Binding Config.SectionCustomEngineSettingsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding Config.SectionCustomEngineSettingsEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_CustomEngineSettingsLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -4296,7 +4308,7 @@
<Grid Margin="-8,0,2,0">
<Grid.RowDefinitions>
<RowDefinition Height="{Binding CurrentConfig.CustomEngineSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.CustomEngineSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -4432,7 +4444,7 @@
</Grid>
</Expander>
<Expander Name="SectionCustomLevels" IsExpanded="{Binding CurrentConfig.SectionCustomLevelsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander Name="SectionCustomLevels" IsExpanded="{Binding Config.SectionCustomLevelsIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_LevelProgressionsLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -4464,7 +4476,7 @@
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="{Binding CurrentConfig.CustomLevelsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.CustomLevelsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -4650,7 +4662,7 @@
</Grid>
</Expander>
<Expander Name="SectionCraftingOverrides" IsExpanded="{Binding CurrentConfig.SectionCraftingOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding CurrentConfig.SectionCraftingOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander Name="SectionCraftingOverrides" IsExpanded="{Binding Config.SectionCraftingOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding Config.SectionCraftingOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_CraftingOverridesLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -4680,7 +4692,7 @@
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="{Binding CurrentConfig.CraftingOverrideItemGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.CraftingOverrideItemGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -4846,7 +4858,7 @@
</Grid>
</Expander>
<Expander Name="SectionStackSizeOverrides" IsExpanded="{Binding CurrentConfig.SectionStackSizeOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding CurrentConfig.SectionStackSizeOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander Name="SectionStackSizeOverrides" IsExpanded="{Binding Config.SectionStackSizeOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding Config.SectionStackSizeOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_StackSizeOverridesLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -4876,7 +4888,7 @@
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="{Binding CurrentConfig.StackSizeOverrideGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.StackSizeOverrideGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -4985,7 +4997,7 @@
</Grid>
</Expander>
<Expander Name="SectionMapSpawnerOverrides" IsExpanded="{Binding CurrentConfig.SectionMapSpawnerOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding CurrentConfig.SectionMapSpawnerOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander Name="SectionMapSpawnerOverrides" IsExpanded="{Binding Config.SectionMapSpawnerOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding Config.SectionMapSpawnerOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_MapSpawnerOverridesLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -5014,7 +5026,7 @@
<Grid Margin="-8,0,2,0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="{Binding CurrentConfig.NPCSpawnSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.NPCSpawnSettingsGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -5185,7 +5197,7 @@
</Grid>
</Expander>
<Expander Name="SectionSupplyCrateOverrides" IsExpanded="{Binding CurrentConfig.SectionSupplyCrateOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding CurrentConfig.SectionSupplyCrateOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander Name="SectionSupplyCrateOverrides" IsExpanded="{Binding Config.SectionSupplyCrateOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding Config.SectionSupplyCrateOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_SupplyCrateOverridesLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -5215,13 +5227,13 @@
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="{Binding CurrentConfig.SupplyCratesGridHeight, ElementName=SettingsControl, FallbackValue=200, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.SupplyCratesGridHeight, ElementName=SettingsControl, FallbackValue=200, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="{Binding CurrentConfig.SupplyCrateItemSetsGridHeight, ElementName=SettingsControl, FallbackValue=200, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.SupplyCrateItemSetsGridHeight, ElementName=SettingsControl, FallbackValue=200, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="{Binding CurrentConfig.SupplyCrateItemSetEntriesGridHeight, ElementName=SettingsControl, FallbackValue=200, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.SupplyCrateItemSetEntriesGridHeight, ElementName=SettingsControl, FallbackValue=200, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="{Binding CurrentConfig.SupplyCrateItemsGridHeight, ElementName=SettingsControl, FallbackValue=200, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.SupplyCrateItemsGridHeight, ElementName=SettingsControl, FallbackValue=200, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -5719,7 +5731,7 @@
</Grid>
</Expander>
<Expander Name="SectionPreventTransferOverrides" IsExpanded="{Binding CurrentConfig.SectionPreventTransferOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding CurrentConfig.SectionPreventTransferOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander Name="SectionPreventTransferOverrides" IsExpanded="{Binding Config.SectionPreventTransferOverridesIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding Config.SectionPreventTransferOverridesEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_PreventTransferOverridesLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -5749,7 +5761,7 @@
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="{Binding CurrentConfig.PreventTransferOverrideGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="{Binding Config.PreventTransferOverrideGridHeight, ElementName=SettingsControl, FallbackValue=400, Mode=TwoWay}" MinHeight="200"/>
<RowDefinition Height="Auto"/> <!--Splitter Row-->
<RowDefinition Height="1" MinHeight="1"/> <!--Empty Row for Last Splitter-->
</Grid.RowDefinitions>
@ -5836,7 +5848,7 @@
</Grid>
</Expander>
<Expander Name="SectionPGM" IsExpanded="{Binding CurrentConfig.SectionPGMIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding CurrentConfig.SectionPGMEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander Name="SectionPGM" IsExpanded="{Binding Config.SectionPGMIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding Config.SectionPGMEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_PGMLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>
@ -6128,7 +6140,7 @@
</Grid>
</Expander>
<Expander Name="SectionSOTF" IsExpanded="{Binding CurrentConfig.SectionSOTFIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding CurrentConfig.SectionSOTFEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander Name="SectionSOTF" IsExpanded="{Binding Config.SectionSOTFIsExpanded, ElementName=SettingsControl, FallbackValue=True, Mode=TwoWay}" Visibility="{Binding Config.SectionSOTFEnabled, ElementName=SettingsControl, Converter={StaticResource BooleanToVisibilityConverter}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{DynamicResource ServerSettings_SOTFLabel}" Style="{StaticResource ExpanderHeaderTextStyle}"/>

View file

@ -100,7 +100,7 @@ namespace ServerManagerTool
public static readonly DependencyProperty BaseBranchesProperty = DependencyProperty.Register(nameof(BaseBranches), typeof(ComboBoxItemList), typeof(ServerSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty BaseEventsProperty = DependencyProperty.Register(nameof(BaseEvents), typeof(ComboBoxItemList), typeof(ServerSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty BetaVersionProperty = DependencyProperty.Register(nameof(BetaVersion), typeof(bool), typeof(ServerSettingsControl), new PropertyMetadata(false));
public static readonly DependencyProperty CurrentConfigProperty = DependencyProperty.Register(nameof(CurrentConfig), typeof(Config), typeof(ServerSettingsControl));
public static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(nameof(Config), typeof(Config), typeof(ServerSettingsControl));
public static readonly DependencyProperty IsAdministratorProperty = DependencyProperty.Register(nameof(IsAdministrator), typeof(bool), typeof(ServerSettingsControl), new PropertyMetadata(false));
public static readonly DependencyProperty NetworkInterfacesProperty = DependencyProperty.Register(nameof(NetworkInterfaces), typeof(List<NetworkAdapterEntry>), typeof(ServerSettingsControl), new PropertyMetadata(new List<NetworkAdapterEntry>()));
public static readonly DependencyProperty RuntimeProperty = DependencyProperty.Register(nameof(Runtime), typeof(ServerRuntime), typeof(ServerSettingsControl));
@ -201,10 +201,10 @@ namespace ServerManagerTool
set { SetValue(BetaVersionProperty, value); }
}
public Config CurrentConfig
public Config Config
{
get { return GetValue(CurrentConfigProperty) as Config; }
set { SetValue(CurrentConfigProperty, value); }
get { return GetValue(ConfigProperty) as Config; }
set { SetValue(ConfigProperty, value); }
}
public bool IsAdministrator
@ -367,7 +367,7 @@ namespace ServerManagerTool
public ServerSettingsControl()
{
this.BetaVersion = App.Instance.BetaVersion;
this.CurrentConfig = Config.Default;
this.Config = Config.Default;
this.CurrentCulture = Thread.CurrentThread.CurrentCulture;
InitializeComponent();
@ -966,7 +966,7 @@ namespace ServerManagerTool
comment.AppendLine($"ServerUpdate_OnServerStart: {Config.Default.ServerUpdate_OnServerStart}");
comment.AppendLine($"DiscordBotEnabled: {Config.Default.DiscordBotEnabled}");
comment.AppendLine($"HasDiscordBotToken: {string.IsNullOrWhiteSpace(Config.Default.DiscordBotToken)}");
comment.AppendLine($"HasDiscordBotToken: {!string.IsNullOrWhiteSpace(Config.Default.DiscordBotToken)}");
comment.AppendLine($"DiscordBotServerId: {Config.Default.DiscordBotServerId}");
comment.AppendLine($"DiscordBotPrefix: {Config.Default.DiscordBotPrefix}");
comment.AppendLine($"AllowDiscordBackup: {Config.Default.AllowDiscordBackup}");
@ -990,7 +990,7 @@ namespace ServerManagerTool
var zipFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), this.Settings.ProfileID + ".zip");
if (File.Exists(zipFile)) File.Delete(zipFile);
ZipUtils.ZipFiles(zipFile, files.ToArray(), comment.ToString());
ZipUtils.ZipFiles(zipFile, files, comment.ToString());
foreach (var kvp in obfuscateFiles)
{
ZipUtils.ZipAFile(zipFile, kvp.Key, kvp.Value);
@ -1348,37 +1348,37 @@ namespace ServerManagerTool
foreach (var section in iniFile.Sections.Where(s => s.SectionName != null && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
var dinoSpawnWeightMultipliers = new AggregateIniValueList<DinoSpawn>(nameof(Server.Profile.DinoSpawnWeightMultipliers), null);
dinoSpawnWeightMultipliers.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{dinoSpawnWeightMultipliers.IniCollectionKey}=")));
dinoSpawnWeightMultipliers.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{dinoSpawnWeightMultipliers.IniCollectionKey}=")));
Server.Profile.DinoSpawnWeightMultipliers.AddRange(dinoSpawnWeightMultipliers);
Server.Profile.DinoSpawnWeightMultipliers.IsEnabled |= dinoSpawnWeightMultipliers.IsEnabled;
var preventDinoTameClassNames = new StringIniValueList(nameof(Server.Profile.PreventDinoTameClassNames), null);
preventDinoTameClassNames.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{preventDinoTameClassNames.IniCollectionKey}=")));
preventDinoTameClassNames.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{preventDinoTameClassNames.IniCollectionKey}=")));
Server.Profile.PreventDinoTameClassNames.AddRange(preventDinoTameClassNames);
Server.Profile.PreventDinoTameClassNames.IsEnabled |= preventDinoTameClassNames.IsEnabled;
var npcReplacements = new AggregateIniValueList<NPCReplacement>(nameof(Server.Profile.NPCReplacements), null);
npcReplacements.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{npcReplacements.IniCollectionKey}=")));
npcReplacements.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{npcReplacements.IniCollectionKey}=")));
Server.Profile.NPCReplacements.AddRange(npcReplacements);
Server.Profile.NPCReplacements.IsEnabled |= npcReplacements.IsEnabled;
var tamedDinoClassDamageMultipliers = new AggregateIniValueList<ClassMultiplier>(nameof(Server.Profile.TamedDinoClassDamageMultipliers), null);
tamedDinoClassDamageMultipliers.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{tamedDinoClassDamageMultipliers.IniCollectionKey}=")));
tamedDinoClassDamageMultipliers.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{tamedDinoClassDamageMultipliers.IniCollectionKey}=")));
Server.Profile.TamedDinoClassDamageMultipliers.AddRange(tamedDinoClassDamageMultipliers);
Server.Profile.TamedDinoClassDamageMultipliers.IsEnabled |= tamedDinoClassDamageMultipliers.IsEnabled;
var tamedDinoClassResistanceMultipliers = new AggregateIniValueList<ClassMultiplier>(nameof(Server.Profile.TamedDinoClassResistanceMultipliers), null);
tamedDinoClassResistanceMultipliers.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{tamedDinoClassResistanceMultipliers.IniCollectionKey}=")));
tamedDinoClassResistanceMultipliers.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{tamedDinoClassResistanceMultipliers.IniCollectionKey}=")));
Server.Profile.TamedDinoClassResistanceMultipliers.AddRange(tamedDinoClassResistanceMultipliers);
Server.Profile.TamedDinoClassResistanceMultipliers.IsEnabled |= tamedDinoClassResistanceMultipliers.IsEnabled;
var dinoClassDamageMultipliers = new AggregateIniValueList<ClassMultiplier>(nameof(Server.Profile.DinoClassDamageMultipliers), null);
dinoClassDamageMultipliers.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{dinoClassDamageMultipliers.IniCollectionKey}=")));
dinoClassDamageMultipliers.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{dinoClassDamageMultipliers.IniCollectionKey}=")));
Server.Profile.DinoClassDamageMultipliers.AddRange(dinoClassDamageMultipliers);
Server.Profile.DinoClassDamageMultipliers.IsEnabled |= dinoClassDamageMultipliers.IsEnabled;
var dinoClassResistanceMultipliers = new AggregateIniValueList<ClassMultiplier>(nameof(Server.Profile.DinoClassResistanceMultipliers), null);
dinoClassResistanceMultipliers.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{dinoClassResistanceMultipliers.IniCollectionKey}=")));
dinoClassResistanceMultipliers.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{dinoClassResistanceMultipliers.IniCollectionKey}=")));
Server.Profile.DinoClassResistanceMultipliers.AddRange(dinoClassResistanceMultipliers);
Server.Profile.DinoClassResistanceMultipliers.IsEnabled |= dinoClassResistanceMultipliers.IsEnabled;
}
@ -1406,7 +1406,8 @@ namespace ServerManagerTool
{
Settings.DinoSettings.RenderToModel();
var iniValues = Settings.DinoSpawnWeightMultipliers.ToIniValues().ToList();
var iniValues = new List<string>();
iniValues.AddRange(Settings.DinoSpawnWeightMultipliers.ToIniValues());
iniValues.AddRange(Settings.PreventDinoTameClassNames.ToIniValues());
iniValues.AddRange(Settings.NPCReplacements.ToIniValues());
iniValues.AddRange(Settings.DinoClassDamageMultipliers.ToIniValues());
@ -1458,7 +1459,7 @@ namespace ServerManagerTool
foreach (var section in iniFile.Sections.Where(s => s.SectionName != null && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
var harvestResourceItemAmountClassMultipliers = new AggregateIniValueList<ResourceClassMultiplier>(nameof(Server.Profile.HarvestResourceItemAmountClassMultipliers), null);
harvestResourceItemAmountClassMultipliers.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{harvestResourceItemAmountClassMultipliers.IniCollectionKey}=")));
harvestResourceItemAmountClassMultipliers.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{harvestResourceItemAmountClassMultipliers.IniCollectionKey}=")));
Server.Profile.HarvestResourceItemAmountClassMultipliers.AddRange(harvestResourceItemAmountClassMultipliers);
Server.Profile.HarvestResourceItemAmountClassMultipliers.IsEnabled |= harvestResourceItemAmountClassMultipliers.IsEnabled;
}
@ -1487,7 +1488,7 @@ namespace ServerManagerTool
private void SaveCustomResources_Click(object sender, RoutedEventArgs e)
{
var iniValues = Settings.HarvestResourceItemAmountClassMultipliers.ToIniValues().ToList();
var iniValues = Settings.HarvestResourceItemAmountClassMultipliers.ToIniValues();
var iniValue = string.Join("\r\n", iniValues);
var window = new CommandLineWindow(iniValue);
@ -1686,12 +1687,12 @@ namespace ServerManagerTool
foreach (var section in iniFile.Sections.Where(s => s.SectionName != null && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
var overrideNamedEngramEntries = new EngramEntryList(nameof(Server.Profile.OverrideNamedEngramEntries));
overrideNamedEngramEntries.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{overrideNamedEngramEntries.IniCollectionKey}=")));
overrideNamedEngramEntries.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{overrideNamedEngramEntries.IniCollectionKey}=")));
Server.Profile.OverrideNamedEngramEntries.AddRange(overrideNamedEngramEntries);
Server.Profile.OverrideNamedEngramEntries.IsEnabled |= overrideNamedEngramEntries.IsEnabled;
var engramEntryAutoUnlocks = new EngramAutoUnlockList(nameof(Server.Profile.EngramEntryAutoUnlocks));
engramEntryAutoUnlocks.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{engramEntryAutoUnlocks.IniCollectionKey}=")));
engramEntryAutoUnlocks.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{engramEntryAutoUnlocks.IniCollectionKey}=")));
Server.Profile.EngramEntryAutoUnlocks.AddRange(engramEntryAutoUnlocks);
Server.Profile.EngramEntryAutoUnlocks.IsEnabled |= engramEntryAutoUnlocks.IsEnabled;
}
@ -1716,7 +1717,8 @@ namespace ServerManagerTool
Settings.EngramSettings.OnlyAllowSpecifiedEngrams = Settings.OnlyAllowSpecifiedEngrams;
Settings.EngramSettings.RenderToModel();
var iniValues = Settings.OverrideNamedEngramEntries.ToIniValues().ToList();
var iniValues = new List<string>();
iniValues.AddRange(Settings.OverrideNamedEngramEntries.ToIniValues());
iniValues.AddRange(Settings.EngramEntryAutoUnlocks.ToIniValues());
var iniValue = string.Join("\r\n", iniValues);
@ -1790,7 +1792,7 @@ namespace ServerManagerTool
foreach (var section in iniFile.Sections.Where(s => s.SectionName != null && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
var configOverrideItemCraftingCosts = new AggregateIniValueList<CraftingOverride>(nameof(Server.Profile.ConfigOverrideItemCraftingCosts), null);
configOverrideItemCraftingCosts.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{configOverrideItemCraftingCosts.IniCollectionKey}=")));
configOverrideItemCraftingCosts.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{configOverrideItemCraftingCosts.IniCollectionKey}=")));
Server.Profile.ConfigOverrideItemCraftingCosts.AddRange(configOverrideItemCraftingCosts);
Server.Profile.ConfigOverrideItemCraftingCosts.IsEnabled |= configOverrideItemCraftingCosts.IsEnabled;
}
@ -1822,7 +1824,8 @@ namespace ServerManagerTool
private void SaveCraftingOverride_Click(object sender, RoutedEventArgs e)
{
var iniValues = Settings.ConfigOverrideItemCraftingCosts.ToIniValues().ToList();
var iniValues = new List<string>();
iniValues.AddRange(Settings.ConfigOverrideItemCraftingCosts.ToIniValues());
var iniValue = string.Join("\r\n", iniValues);
var window = new CommandLineWindow(iniValue);
@ -1898,7 +1901,7 @@ namespace ServerManagerTool
// cycle through the sections, adding them to the custom section list. Will bypass any sections that are named as per the ARK default sections.
foreach (var section in iniFile.Sections.Where(s => !string.IsNullOrWhiteSpace(s.SectionName) && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
Settings.CustomGameUserSettings.Add(section.SectionName, section.KeysToStringArray(), false);
Settings.CustomGameUserSettings.Add(section.SectionName, section.KeysToStringEnumerable(), false);
}
MessageBox.Show(_globalizer.GetResourceString("ServerSettings_LoadCustomConfig_Label"), _globalizer.GetResourceString("ServerSettings_LoadCustomConfig_Title"), MessageBoxButton.OK, MessageBoxImage.Information);
@ -1957,7 +1960,7 @@ namespace ServerManagerTool
// cycle through the sections, adding them to the custom section list. Will bypass any sections that are named as per the ARK default sections.
foreach (var section in iniFile.Sections.Where(s => !string.IsNullOrWhiteSpace(s.SectionName) && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
Settings.CustomGameUserSettings.Add(section.SectionName, section.KeysToStringArray(), false);
Settings.CustomGameUserSettings.Add(section.SectionName, section.KeysToStringEnumerable(), false);
}
}
@ -1980,7 +1983,7 @@ namespace ServerManagerTool
var configIniFile = Path.Combine(ServerProfile.GetProfileServerConfigDir(Settings), Config.Default.ServerGameUserSettingsConfigFile);
// load only this section, using the full exclusion list
var tempServerProfile = ServerProfile.LoadFromINIFiles(configIniFile, null, exclusions.ToArray());
var tempServerProfile = ServerProfile.LoadFromINIFiles(configIniFile, null, exclusions);
// perform a profile sync
Settings.SyncSettings(ServerProfileCategory.CustomGameUserSettings, tempServerProfile);
}
@ -2059,7 +2062,7 @@ namespace ServerManagerTool
// cycle through the sections, adding them to the custom section list. Will bypass any sections that are named as per the ARK default sections.
foreach (var section in iniFile.Sections.Where(s => !string.IsNullOrWhiteSpace(s.SectionName) && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
Settings.CustomGameSettings.Add(section.SectionName, section.KeysToStringArray(), false);
Settings.CustomGameSettings.Add(section.SectionName, section.KeysToStringEnumerable(), false);
}
MessageBox.Show(_globalizer.GetResourceString("ServerSettings_LoadCustomConfig_Label"), _globalizer.GetResourceString("ServerSettings_LoadCustomConfig_Title"), MessageBoxButton.OK, MessageBoxImage.Information);
@ -2118,7 +2121,7 @@ namespace ServerManagerTool
// cycle through the sections, adding them to the custom section list. Will bypass any sections that are named as per the ARK default sections.
foreach (var section in iniFile.Sections.Where(s => !string.IsNullOrWhiteSpace(s.SectionName) && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
Settings.CustomGameSettings.Add(section.SectionName, section.KeysToStringArray(), false);
Settings.CustomGameSettings.Add(section.SectionName, section.KeysToStringEnumerable(), false);
}
}
@ -2141,7 +2144,7 @@ namespace ServerManagerTool
var configIniFile = Path.Combine(ServerProfile.GetProfileServerConfigDir(Settings), Config.Default.ServerGameUserSettingsConfigFile);
// load only this section, using the full exclusion list
var tempServerProfile = ServerProfile.LoadFromINIFiles(configIniFile, null, exclusions.ToArray());
var tempServerProfile = ServerProfile.LoadFromINIFiles(configIniFile, null, exclusions);
// perform a profile sync
Settings.SyncSettings(ServerProfileCategory.CustomGameSettings, tempServerProfile);
}
@ -2220,7 +2223,7 @@ namespace ServerManagerTool
// cycle through the sections, adding them to the custom section list. Will bypass any sections that are named as per the ARK default sections.
foreach (var section in iniFile.Sections.Where(s => !string.IsNullOrWhiteSpace(s.SectionName) && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
Settings.CustomEngineSettings.Add(section.SectionName, section.KeysToStringArray(), false);
Settings.CustomEngineSettings.Add(section.SectionName, section.KeysToStringEnumerable(), false);
}
MessageBox.Show(_globalizer.GetResourceString("ServerSettings_LoadCustomConfig_Label"), _globalizer.GetResourceString("ServerSettings_LoadCustomConfig_Title"), MessageBoxButton.OK, MessageBoxImage.Information);
@ -2279,7 +2282,7 @@ namespace ServerManagerTool
// cycle through the sections, adding them to the custom section list. Will bypass any sections that are named as per the ARK default sections.
foreach (var section in iniFile.Sections.Where(s => !string.IsNullOrWhiteSpace(s.SectionName) && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
Settings.CustomEngineSettings.Add(section.SectionName, section.KeysToStringArray(), false);
Settings.CustomEngineSettings.Add(section.SectionName, section.KeysToStringEnumerable(), false);
}
}
@ -2302,7 +2305,7 @@ namespace ServerManagerTool
var configIniFile = Path.Combine(ServerProfile.GetProfileServerConfigDir(Settings), Config.Default.ServerGameUserSettingsConfigFile);
// load only this section, using the full exclusion list
var tempServerProfile = ServerProfile.LoadFromINIFiles(configIniFile, null, exclusions.ToArray());
var tempServerProfile = ServerProfile.LoadFromINIFiles(configIniFile, null, exclusions);
// perform a profile sync
Settings.SyncSettings(ServerProfileCategory.CustomEngineSettings, tempServerProfile);
}
@ -2693,7 +2696,7 @@ namespace ServerManagerTool
Application.Current.Dispatcher.Invoke(() => this.Cursor = Cursors.Wait);
await Task.Delay(500);
Settings.LoadServerFileAdministrators();
Settings.LoadServerFiles(true, false, false);
}
catch (Exception ex)
{
@ -2714,7 +2717,7 @@ namespace ServerManagerTool
Application.Current.Dispatcher.Invoke(() => this.Cursor = Cursors.Wait);
await Task.Delay(500);
Settings.LoadServerFileExclusive();
Settings.LoadServerFiles(false, true, false);
}
catch (Exception ex)
{
@ -2735,7 +2738,7 @@ namespace ServerManagerTool
Application.Current.Dispatcher.Invoke(() => this.Cursor = Cursors.Wait);
await Task.Delay(500);
Settings.LoadServerFileWhitelisted();
Settings.LoadServerFiles(false, false, true);
}
catch (Exception ex)
{
@ -2919,17 +2922,17 @@ namespace ServerManagerTool
foreach (var section in iniFile.Sections.Where(s => s.SectionName != null && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
var configAddNPCSpawnEntriesContainer = new NPCSpawnContainerList<NPCSpawnContainer>(nameof(Server.Profile.ConfigAddNPCSpawnEntriesContainer), NPCSpawnContainerType.Add);
configAddNPCSpawnEntriesContainer.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{configAddNPCSpawnEntriesContainer.IniCollectionKey}=")));
configAddNPCSpawnEntriesContainer.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{configAddNPCSpawnEntriesContainer.IniCollectionKey}=")));
Server.Profile.ConfigAddNPCSpawnEntriesContainer.AddRange(configAddNPCSpawnEntriesContainer);
Server.Profile.ConfigAddNPCSpawnEntriesContainer.IsEnabled |= configAddNPCSpawnEntriesContainer.IsEnabled;
var configSubtractNPCSpawnEntriesContainer = new NPCSpawnContainerList<NPCSpawnContainer>(nameof(Server.Profile.ConfigSubtractNPCSpawnEntriesContainer), NPCSpawnContainerType.Subtract);
configSubtractNPCSpawnEntriesContainer.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{configSubtractNPCSpawnEntriesContainer.IniCollectionKey}=")));
configSubtractNPCSpawnEntriesContainer.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{configSubtractNPCSpawnEntriesContainer.IniCollectionKey}=")));
Server.Profile.ConfigSubtractNPCSpawnEntriesContainer.AddRange(configSubtractNPCSpawnEntriesContainer);
Server.Profile.ConfigSubtractNPCSpawnEntriesContainer.IsEnabled |= configSubtractNPCSpawnEntriesContainer.IsEnabled;
var configOverrideNPCSpawnEntriesContainer = new NPCSpawnContainerList<NPCSpawnContainer>(nameof(Server.Profile.ConfigOverrideNPCSpawnEntriesContainer), NPCSpawnContainerType.Override);
configOverrideNPCSpawnEntriesContainer.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{configOverrideNPCSpawnEntriesContainer.IniCollectionKey}=")));
configOverrideNPCSpawnEntriesContainer.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{configOverrideNPCSpawnEntriesContainer.IniCollectionKey}=")));
Server.Profile.ConfigOverrideNPCSpawnEntriesContainer.AddRange(configOverrideNPCSpawnEntriesContainer);
Server.Profile.ConfigOverrideNPCSpawnEntriesContainer.IsEnabled |= configOverrideNPCSpawnEntriesContainer.IsEnabled;
}
@ -2966,7 +2969,8 @@ namespace ServerManagerTool
{
Settings.NPCSpawnSettings.RenderToModel();
var iniValues = Settings.ConfigAddNPCSpawnEntriesContainer.ToIniValues().ToList();
var iniValues = new List<string>();
iniValues.AddRange(Settings.ConfigAddNPCSpawnEntriesContainer.ToIniValues());
iniValues.AddRange(Settings.ConfigSubtractNPCSpawnEntriesContainer.ToIniValues());
iniValues.AddRange(Settings.ConfigOverrideNPCSpawnEntriesContainer.ToIniValues());
var iniValue = string.Join("\r\n", iniValues);
@ -3123,7 +3127,7 @@ namespace ServerManagerTool
foreach (var section in iniFile.Sections.Where(s => s.SectionName != null && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
var configOverrideSupplyCrateItems = new SupplyCrateOverrideList(nameof(Server.Profile.ConfigOverrideSupplyCrateItems));
configOverrideSupplyCrateItems.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{configOverrideSupplyCrateItems.IniCollectionKey}=")));
configOverrideSupplyCrateItems.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{configOverrideSupplyCrateItems.IniCollectionKey}=")));
Server.Profile.ConfigOverrideSupplyCrateItems.AddRange(configOverrideSupplyCrateItems);
Server.Profile.ConfigOverrideSupplyCrateItems.IsEnabled |= configOverrideSupplyCrateItems.IsEnabled;
}
@ -3133,7 +3137,7 @@ namespace ServerManagerTool
RefreshBaseSupplyCrateList();
RefreshBasePrimalItemList();
if (errors.Length > 0)
if (errors.Any())
{
var error = $"The following errors have been found:\r\n\r\n{string.Join("\r\n", errors)}";
@ -3199,7 +3203,8 @@ namespace ServerManagerTool
{
Settings.ConfigOverrideSupplyCrateItems.RenderToModel();
var iniValues = Settings.ConfigOverrideSupplyCrateItems.ToIniValues().ToList();
var iniValues = new List<string>();
iniValues.AddRange(Settings.ConfigOverrideSupplyCrateItems.ToIniValues());
var iniValue = string.Join("\r\n", iniValues);
var window = new CommandLineWindow(iniValue);
@ -3265,7 +3270,7 @@ namespace ServerManagerTool
foreach (var section in iniFile.Sections.Where(s => s.SectionName != null && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
var configOverrideItemMaxQuantity = new AggregateIniValueList<StackSizeOverride>(nameof(Server.Profile.ConfigOverrideItemMaxQuantity), null);
configOverrideItemMaxQuantity.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{configOverrideItemMaxQuantity.IniCollectionKey}=")));
configOverrideItemMaxQuantity.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{configOverrideItemMaxQuantity.IniCollectionKey}=")));
Server.Profile.ConfigOverrideItemMaxQuantity.AddRange(configOverrideItemMaxQuantity);
Server.Profile.ConfigOverrideItemMaxQuantity.IsEnabled |= configOverrideItemMaxQuantity.IsEnabled;
}
@ -3274,7 +3279,7 @@ namespace ServerManagerTool
RefreshBasePrimalItemList();
if (errors.Length > 0)
if (errors.Any())
{
var error = $"The following errors have been found:\r\n\r\n{string.Join("\r\n", errors)}";
@ -3301,7 +3306,8 @@ namespace ServerManagerTool
{
Settings.ConfigOverrideItemMaxQuantity.RenderToModel();
var iniValues = Settings.ConfigOverrideItemMaxQuantity.ToIniValues().ToList();
var iniValues = new List<string>();
iniValues.AddRange(Settings.ConfigOverrideItemMaxQuantity.ToIniValues());
var iniValue = string.Join("\r\n", iniValues);
var window = new CommandLineWindow(iniValue);
@ -3365,7 +3371,7 @@ namespace ServerManagerTool
foreach (var section in iniFile.Sections.Where(s => s.SectionName != null && !SystemIniFile.IniSectionNames.ContainsValue(s.SectionName)))
{
var preventTransferForClassNames = new AggregateIniValueList<PreventTransferOverride>(nameof(Server.Profile.PreventTransferForClassNames), null);
preventTransferForClassNames.FromIniValues(section.KeysToStringArray().Where(s => s.StartsWith($"{preventTransferForClassNames.IniCollectionKey}=")));
preventTransferForClassNames.FromIniValues(section.KeysToStringEnumerable().Where(s => s.StartsWith($"{preventTransferForClassNames.IniCollectionKey}=")));
Server.Profile.PreventTransferForClassNames.AddRange(preventTransferForClassNames);
Server.Profile.PreventTransferForClassNames.IsEnabled |= preventTransferForClassNames.IsEnabled;
}
@ -3374,7 +3380,7 @@ namespace ServerManagerTool
RefreshBaseDinoList();
if (errors.Length > 0)
if (errors.Any())
{
var error = $"The following errors have been found:\r\n\r\n{string.Join("\r\n", errors)}";
@ -3401,7 +3407,8 @@ namespace ServerManagerTool
{
Settings.PreventTransferForClassNames.RenderToModel();
var iniValues = Settings.PreventTransferForClassNames.ToIniValues().ToList();
var iniValues = new List<string>();
iniValues.AddRange(Settings.PreventTransferForClassNames.ToIniValues());
var iniValue = string.Join("\r\n", iniValues);
var window = new CommandLineWindow(iniValue);
@ -3442,7 +3449,7 @@ namespace ServerManagerTool
var name = _globalizer.GetResourceString($"Mod_{value}");
newList.Add(new Common.Model.ComboBoxItem(value, name));
var values = GameData.GetDinoSpawns().GroupBy(d => d.Mod).OrderBy(g => g.Key).Select(g => g.Key).ToList();
var values = GameData.GetDinoSpawns().GroupBy(d => d.Mod).OrderBy(g => g.Key).Select(g => g.Key);
foreach (var modValue in values)
{
if (string.IsNullOrWhiteSpace(modValue))
@ -3472,7 +3479,7 @@ namespace ServerManagerTool
var name = _globalizer.GetResourceString($"Mod_{value}");
newList.Add(new Common.Model.ComboBoxItem(value, name));
var values = GameData.GetEngrams().GroupBy(d => d.Mod).OrderBy(g => g.Key).Select(g => g.Key).ToList();
var values = GameData.GetEngrams().GroupBy(d => d.Mod).OrderBy(g => g.Key).Select(g => g.Key);
foreach (var modValue in values)
{
if (string.IsNullOrWhiteSpace(modValue))
@ -3502,7 +3509,7 @@ namespace ServerManagerTool
var name = _globalizer.GetResourceString($"Mod_{value}");
newList.Add(new Common.Model.ComboBoxItem(value, name));
var values = GameData.GetResourceMultipliers().GroupBy(d => d.Mod).OrderBy(g => g.Key).Select(g => g.Key).ToList();
var values = GameData.GetResourceMultipliers().GroupBy(d => d.Mod).OrderBy(g => g.Key).Select(g => g.Key);
foreach (var modValue in values)
{
if (string.IsNullOrWhiteSpace(modValue))

View file

@ -1,11 +1,11 @@
using QueryMaster;
using ServerManagerTool.Common.Extensions;
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;
@ -23,7 +23,7 @@ namespace ServerManagerTool.Utils
public static bool HasRunningCommands => _currentProfileCommands.Count > 0;
public static IList<string> HandleDiscordCommand(CommandType commandType, string serverId, string channelId, string profileId, CancellationToken token)
public static IList<string> HandleDiscordCommand(CommandType commandType, string serverId, string channelId, string profileIdOrAlias, CancellationToken token)
{
// check if incoming values are valid
if (string.IsNullOrWhiteSpace(serverId) || string.IsNullOrWhiteSpace(channelId))
@ -42,35 +42,35 @@ namespace ServerManagerTool.Utils
switch (commandType)
{
case CommandType.Info:
return GetServerInfo(channelId, profileId);
return GetServerInfo(channelId, profileIdOrAlias);
case CommandType.List:
return GetServerList(channelId);
case CommandType.Status:
return GetServerStatus(channelId, profileId);
return GetServerStatus(channelId, profileIdOrAlias);
case CommandType.Backup:
if (Config.Default.AllowDiscordBackup)
return BackupServer(channelId, profileId, token);
return BackupServer(channelId, profileIdOrAlias, 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 RestartServer(channelId, profileIdOrAlias, 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 ShutdownServer(channelId, profileIdOrAlias, 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 StopServer(channelId, profileIdOrAlias, 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 StartServer(channelId, profileIdOrAlias, 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 UpdateServer(channelId, profileIdOrAlias, token);
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
default:
@ -93,19 +93,14 @@ namespace ServerManagerTool.Utils
return string.IsNullOrWhiteSpace(translationKey) ? string.Empty : _globalizer.GetResourceString(translationKey) ?? translationKey;
}
private static IList<string> GetServerInfo(string channelId, string profileId)
private static IList<string> GetServerInfo(string channelId, string profileIdOrAlias)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
try
{
@ -115,12 +110,29 @@ namespace ServerManagerTool.Utils
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Info);
switch (server.Runtime.Status)
{
@ -130,7 +142,7 @@ namespace ServerManagerTool.Utils
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
}
serverName = server.Profile.ServerName;
@ -155,7 +167,9 @@ namespace ServerManagerTool.Utils
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}```");
response.Add($"```{info.Name}\n" +
$"{_globalizer.GetResourceString("DiscordBot_MapLabel")} {mapName}\n" +
$"{_globalizer.GetResourceString("ServerSettings_PlayersLabel")} {info.Players} / {info.MaxPlayers}```");
}
}
}
@ -168,7 +182,7 @@ namespace ServerManagerTool.Utils
}
finally
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
@ -178,49 +192,55 @@ namespace ServerManagerTool.Utils
TaskUtils.RunOnUIThreadAsync(() =>
{
var serverList = ServerManager.Instance.Servers.Where(s => Equals(channelId, s.Profile.DiscordChannelId));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase));
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}```");
response.Add($"```{_globalizer.GetResourceString("ServerSettings_ProfileLabel")} {server.Profile.ProfileName}\n" +
$"{_globalizer.GetResourceString("ServerSettings_ProfileIdLabel")} {server.Profile.ProfileID}\n" +
(string.IsNullOrWhiteSpace(server.Profile.DiscordAlias) ? "" : $"{_globalizer.GetResourceString("ServerSettings_DiscordAliasLabel")} {server.Profile.DiscordAlias}\n") +
$"{_globalizer.GetResourceString("ServerSettings_ServerNameLabel")} {server.Profile.ServerName}```");
}
}).Wait();
return response;
}
private static IList<string> GetServerStatus(string channelId, string profileId)
private static IList<string> GetServerStatus(string channelId, string profileIdOrAlias)
{
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)));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.IsNullOrWhiteSpace(profileIdOrAlias)
|| string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
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}")}```");
response.Add($"```{_globalizer.GetResourceString("ServerSettings_ProfileLabel")} {server.Profile.ProfileName}\n" +
$"{_globalizer.GetResourceString("ServerSettings_ProfileIdLabel")} {server.Profile.ProfileID}\n" +
(string.IsNullOrWhiteSpace(server.Profile.DiscordAlias) ? "" : $"{_globalizer.GetResourceString("ServerSettings_DiscordAliasLabel")} {server.Profile.DiscordAlias}\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)
private static IList<string> BackupServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -229,18 +249,35 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordBackup)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Backup, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Backup, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Backup);
switch (server.Runtime.Status)
{
case ServerStatus.Initializing:
@ -248,7 +285,7 @@ namespace ServerManagerTool.Utils
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -267,7 +304,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -276,7 +315,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileBackup(profile, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_BackupRequested"), profile.ServerName));
@ -287,24 +326,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> RestartServer(string channelId, string profileId, CancellationToken token)
private static IList<string> RestartServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -313,28 +347,45 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordRestart)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Restart, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Restart, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Restart);
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));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -354,7 +405,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -363,7 +416,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, true, false, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_RestartRequested"), profile.ServerName));
@ -374,24 +427,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> ShutdownServer(string channelId, string profileId, CancellationToken token)
private static IList<string> ShutdownServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -400,18 +448,35 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordShutdown)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Shutdown, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Shutdown, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Shutdown);
switch (server.Runtime.Status)
{
case ServerStatus.Initializing:
@ -419,10 +484,10 @@ namespace ServerManagerTool.Utils
case ServerStatus.Stopped:
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -441,7 +506,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -450,7 +517,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, false, false, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_ShutdownRequested"), profile.ServerName));
@ -461,24 +528,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> StopServer(string channelId, string profileId, CancellationToken token)
private static IList<string> StopServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -487,18 +549,35 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordStop)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Stop, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Stop, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Stop);
switch (server.Runtime.Status)
{
case ServerStatus.Initializing:
@ -506,10 +585,10 @@ namespace ServerManagerTool.Utils
case ServerStatus.Stopped:
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -523,13 +602,15 @@ namespace ServerManagerTool.Utils
OutputLogs = false,
SendAlerts = true,
SendEmails = false,
ServerProcess = ServerProcessType.Shutdown,
ServerProcess = ServerProcessType.Stop,
ShutdownInterval = 0,
ServerStatusChangeCallback = (ServerStatus serverStatus) =>
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -538,7 +619,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, false, false, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_StopRequested"), profile.ServerName));
@ -549,24 +630,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> StartServer(string channelId, string profileId, CancellationToken token)
private static IList<string> StartServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -575,18 +651,35 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordStart)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Start, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Start, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Start);
switch (server.Runtime.Status)
{
case ServerStatus.Initializing:
@ -594,10 +687,10 @@ namespace ServerManagerTool.Utils
case ServerStatus.Running:
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -617,7 +710,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -626,7 +721,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, true, false, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_StartRequested"), profile.ServerName));
@ -637,24 +732,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> UpdateServer(string channelId, string profileId, CancellationToken token)
private static IList<string> UpdateServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
bool performRestart = false;
@ -664,31 +754,48 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordUpdate)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Update, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Update, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Update);
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));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Running:
performRestart = true;
break;
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -707,7 +814,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -716,7 +825,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, performRestart, true, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_UpdateRequested"), profile.ServerName));
@ -727,7 +836,7 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}

View file

@ -46,15 +46,15 @@ namespace ServerManagerTool.Utils
}
}
public static void AddOfficialMods(IEnumerable<string> modIds)
public static void AddOfficialMods(List<string> modIds)
{
if (OfficialMods == null)
OfficialMods = new List<string>();
if (modIds != null)
{
var modIdsToAdd = modIds.Where(m => !string.IsNullOrWhiteSpace(m) && !OfficialMods.Contains(m)).Distinct().ToList();
if (modIdsToAdd != null && modIdsToAdd.Count > 0)
var modIdsToAdd = modIds.Where(m => !string.IsNullOrWhiteSpace(m) && !OfficialMods.Contains(m)).Distinct();
if (modIdsToAdd.Any())
{
OfficialMods.AddRange(modIdsToAdd);
}
@ -170,14 +170,14 @@ namespace ServerManagerTool.Utils
return string.Empty;
// split the map string into parts, using the '/' separator.
var parts = serverMap.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).ToList();
var parts = serverMap.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
long mapModId;
if (parts.Count == 1 && long.TryParse(parts[0], out mapModId))
if (parts.Length == 1 && long.TryParse(parts[0], out mapModId))
return mapModId.ToString();
// check if any parts were returned.
if (parts.Count != 4)
if (parts.Length != 4)
return string.Empty;
// check if the first two parts match what is expected.
@ -194,12 +194,12 @@ namespace ServerManagerTool.Utils
return string.Empty;
// split the map string into parts, using the '/' separator.
var parts = serverMap.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).ToList();
var parts = serverMap.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
// check if any parts were returned.
if (parts.Count == 1)
if (parts.Length == 1)
return serverMap;
if (parts.Count != 4)
if (parts.Length != 4)
return string.Empty;
// check if the first two parts match what is expected.
@ -496,9 +496,9 @@ namespace ServerManagerTool.Utils
return new List<string>();
// remove all null, empty, duplicate and Official mod ids.
var newModIdList = modIdList.Where(m => !string.IsNullOrWhiteSpace(m) && !IsOfficialMod(m)).Distinct().ToList();
var newModIdList = modIdList.Where(m => !string.IsNullOrWhiteSpace(m) && !IsOfficialMod(m)).Distinct();
return newModIdList;
return newModIdList.ToList();
}
public static void WriteModFile(string fileName, string modId, Dictionary<string, string> metaInformation, List<string> mapNames)

View file

@ -5,14 +5,85 @@
<title>Ark Server Manager Version Feed</title>
<subtitle>This is the Ark Server Manager release version feed.</subtitle>
<link href="http://arkservermanager.freeforums.net/" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-17T00:00:00Z</updated>
<entry>
<id>urn:uuid:3E33DCB2-ECFE-4489-B1A4-56F5D386F9DC</id>
<title>1.1.413 (1.1.413.8)</title>
<summary>1.1.413.8</summary>
<link href="" />
<updated>2021-12-17T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Main Window - Added Discord Bot Status and a button to Stop/Start the discord bot.</li>
<li>Global Settings - Discord Bot section - Added a log level droplist.</li>
<li>Global Settings - Discord Bot section - Added a checkbox to allow all bots.</li>
<li>Global Settings - Discord Bot section - Added a whitelist to allow bots to send commands to the server manager.</li>
<li>Server Settings - Discord Bot section - Added an alias that can be used with the discord command instead of the profile id.</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Discord Bot - all commands are now case INsensitive, along with the profile id and the alias.</li>
<li>Discord Bot - removed the mandatory requirement to enter the '!' after the discord prefix. The '!' has been added to the existing prefix so no change to existing functionality, but you can now change it.</li>
<li>Made changes to the code to help improve performance.</li>
<li>pt-BR Translation file updated.</li>
<li>ru-RU Translation file updated.</li>
<li>zh-CN Translation file updated.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:18276A38-2C71-4BB8-9A83-96D5EBFE9C87</id>
<title>1.1.412 (1.1.412.4)</title>
<summary>1.1.412.4</summary>
<link href="" />
<updated>2021-12-15T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed a bug with the Server Shutdown when the CheckForOnlinePlayers option not selected.</li>
<li>Fixed a bug when the backup path was a root directory that caused a 'Invalid URI: A Dos path must be rooted' crash.</li>
<li>Added additional validation when setting directories in the global setting, to ensure they are rooted correctly.</li>
<li>Fixed a bug when starting the server manager and it tries to download steamcmd, but fails as steamcmd is unavailable for download.</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>fr-FR Translation file updated.</li>
<li>zh-CN Translation file updated.</li>
<li>Added LostIsland to official mods in the SurvivalEvolved gamedata file.</li>
<li>Added coloring to the setting grids for the Lost Island DLC engrams, creatures and resources.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:DBAFCE91-2235-4B6C-AE9B-5E4EF9FEC8F5</id>
<title>1.1.411 (1.1.411.6)</title>
<summary>1.1.411.6</summary>
<title>1.1.411 (1.1.411.10)</title>
<summary>1.1.411.10</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-14T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
@ -35,6 +106,7 @@
<ul>
<li>Global Settings - Added reset button to the Data Directory Location.</li>
<li>Server Monitor window now stores it's location.</li>
<li>Removed MOTD and Alternate Save Directory from the Administration section of the Sync.</li>
<li>fr-FR Translation file updated.</li>
<li>pt-BR Translation file updated.</li>
<li>ru-RU Translation file updated.</li>

View file

@ -5,22 +5,45 @@
<title>Ark Server Manager Version Feed</title>
<subtitle>This is the Ark Server Manager beta version feed.</subtitle>
<link href="http://arkservermanager.freeforums.net/" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-16T00:00:00Z</updated>
<entry>
<id>urn:uuid:C02D44F9-E3AA-4CA0-BF2F-110F8C83CC21</id>
<title>1.1.411 (1.1.411.7)</title>
<summary>1.1.411.7</summary>
<id>urn:uuid:8EE5659C-18E6-47D3-941D-C32B129D2E06</id>
<title>1.1.413 (1.1.413.8)</title>
<summary>1.1.413.8</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-17T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Discord Bot - all commands are now case INsensitive, along with the profile id and the alias.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:8EE5659C-18E6-47D3-941D-C32B129D2E06</id>
<title>1.1.413 (1.1.413.7)</title>
<summary>1.1.413.7</summary>
<link href="" />
<updated>2021-12-17T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Added gamedata file for the Lost Island DLC - only contains the map name for the Map droplist - do not use until the DLC is officially released!</li>
<li>Added Lost Island to the language files for translation.</li>
<li>Main Window - Added Discord Bot Status and a button to Stop/Start the discord bot.</li>
<li>Global Settings - Discord Bot section - Added a checkbox to allow all bots.</li>
</ul>
</p>
</div>
@ -32,42 +55,18 @@
</entry>
<entry>
<id>urn:uuid:F75C6AFF-2A27-49BE-917A-7EAAACCCBF17</id>
<title>1.1.411 (1.1.411.6)</title>
<summary>1.1.411.6</summary>
<id>urn:uuid:65A7E6B1-98D1-422D-B42F-B0EBB1D20E41</id>
<title>1.1.413 (1.1.413.6)</title>
<summary>1.1.413.6</summary>
<link href="" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-17T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>fr-FR Translation file updated.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:0BCB8BBA-330F-4063-8B7E-5B144589999A</id>
<title>1.1.411 (1.1.411.5)</title>
<summary>1.1.411.5</summary>
<link href="" />
<updated>2021-12-10T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Server Monitor window now stores it's location.</li>
<li>Reference library updates.</li>
<li>Added additional message logging when log level set to debug.</li>
<li>pt-BR Translation file updated.</li>
<li>ru-RU Translation file updated.</li>
</ul>
@ -81,29 +80,69 @@
</entry>
<entry>
<id>urn:uuid:7697EBD7-DEF6-422B-B9A6-D4B77F31D572</id>
<title>1.1.411 (1.1.411.4)</title>
<summary>1.1.411.4</summary>
<id>urn:uuid:65A7E6B1-98D1-422D-B42F-B0EBB1D20E41</id>
<title>1.1.413 (1.1.413.5)</title>
<summary>1.1.413.5</summary>
<link href="" />
<updated>2021-12-09T00:00:00Z</updated>
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Global Settings - Discord Bot section - Added a log level droplist.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:98FFBFA1-4E99-4801-BF2B-CA68BE300C27</id>
<title>1.1.413 (1.1.413.4)</title>
<summary>1.1.413.4</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed a minor issue when clicking the data directory reset button - fringe case that I found during testing.</li>
<li>Fixed a bug that would prevent a bot on the whitelist processing the message.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:8958A494-DE13-4F6F-ACA2-10026D5FB8A9</id>
<title>1.1.413 (1.1.413.3)</title>
<summary>1.1.413.3</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Server Settings - Dino Section - Added MutagenLevelBoost and MutagenLevelBoostBred settings.</li>
<li>Server Settings - Discord Bot section - Added an alias that can be used with the discord command instead of the profile id.</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>pt-BR Translation file updated.</li>
<li>ru-RU Translation file updated.</li>
<li>Removed the mandatory requirement to enter the '!' after the discord prefix. The '!' has been added to the existing prefix so no change to existing functionality, but you can now change it.</li>
<li>zh-CN Translation file updated.</li>
</ul>
</p>
@ -116,73 +155,41 @@
</entry>
<entry>
<id>urn:uuid:8290F43D-98F4-4F4D-8DD8-0A3EF5A45656</id>
<title>1.1.411 (1.1.411.3)</title>
<summary>1.1.411.3</summary>
<id>urn:uuid:8958A494-DE13-4F6F-ACA2-10026D5FB8A9</id>
<title>1.1.413 (1.1.413.2)</title>
<summary>1.1.413.2</summary>
<link href="" />
<updated>2021-12-08T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed language translation of Data Directory window.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:ADBF3FE0-017C-4E23-8FE8-EFE75E7C8BA1</id>
<title>1.1.411 (1.1.411.2)</title>
<summary>1.1.411.2</summary>
<link href="" />
<updated>2021-12-08T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Global Settings - Added reset button to the Data Directory Location.</li>
<li>pt-BR Translation file updated.</li>
<li>zh-CN Translation file updated.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:DBAFCE91-2235-4B6C-AE9B-5E4EF9FEC8F5</id>
<title>1.1.411 (1.1.411.1)</title>
<summary>1.1.411.1</summary>
<link href="" />
<updated>2021-12-06T00:00:00Z</updated>
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>
A new Discord Bot has been added to the server manager.<br/>
This new discord bot will allow you to send <font color="#0094FF">Start, Stop, Shutdown, Restart, Backup and Update</font> commands to the server manager from within your discord client.<br/>
To setup the new discord bot, open the global settings and scroll down to the Discord section.<br/><br/>
<font color="#e62919">
NOTE: This is long process to get the discord bot working, and I have created a forum post with detailed instructions how to do it.
</font>
</li>
<li>Global Settings - Discord Bot section - Added a whitelist to allow bots to send commands to the server manager.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:3E33DCB2-ECFE-4489-B1A4-56F5D386F9DC</id>
<title>1.1.413 (1.1.413.1)</title>
<summary>1.1.413.1</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Made changes to the code to help improve performance.</li>
</ul>
</p>
</div>

View file

@ -17,6 +17,7 @@
<ProgressBar x:Name="CompletionProgress" Height="10"/>
<Label x:Name="StatusLabel" Content="{DynamicResource AutoUpdater_Status}" HorizontalContentAlignment="Center"/>
<Button Content="{DynamicResource AutoUpdater_CancelButtonLabel}" Width="75" HorizontalAlignment="Center" IsCancel="True" Click="Button_Click"/>
<TextBlock x:Name="ErrorLabel" Text="Error Text" Margin="0,2,0,0" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" Foreground="{DynamicResource WarningMessage}"/>
</StackPanel>
</Grid>
</Window>

View file

@ -2,6 +2,7 @@
using ServerManagerTool.Common.Utils;
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using WPFSharp.Globalizer;
@ -12,15 +13,16 @@ namespace ServerManagerTool
/// </summary>
public partial class AutoUpdateWindow : Window
{
private GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
private SteamCmdUpdater updater = new SteamCmdUpdater();
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
private readonly SteamCmdUpdater updater = new SteamCmdUpdater();
private CancellationTokenSource cancelSource;
public AutoUpdateWindow()
{
InitializeComponent();
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
this.ErrorLabel.Visibility = Visibility.Collapsed;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
@ -32,10 +34,13 @@ namespace ServerManagerTool
this.StatusLabel.Content = message;
this.CompletionProgress.Value = u.CompletionPercent;
if(u.FailureText != null)
if (u.FailureText != null)
{
// TODO: Report error through UI
throw new Exception(u.FailureText);
this.ErrorLabel.Text = u.FailureText;
this.ErrorLabel.Visibility = Visibility.Visible;
await Task.Delay(10000);
Environment.Exit(1);
}
if (u.CompletionPercent >= 100 || u.Cancelled)

View file

@ -9,6 +9,7 @@
xmlns:cvr="clr-namespace:ServerManagerTool.Common.ValidationRules;assembly=ServerManager.Common"
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
xmlns:enum="clr-namespace:ServerManagerTool.Enums"
xmlns:bot="clr-namespace:ServerManagerTool.DiscordBot;assembly=ServerManager.Discord"
MinWidth="900" MinHeight="600" Width="1100" Height="900" Left="50" Top="50" WindowState="Normal"
Loaded="MainWindow_Loaded" SizeChanged="MainWindow_SizeChanged" StateChanged="MainWindow_StateChanged" LocationChanged="MainWindow_LocationChanged"
Name="Main" Icon="../Art/favicon.ico" Title="{DynamicResource MainWindow_Title}">
@ -33,7 +34,7 @@
<Style TargetType="{x:Type DockPanel}">
<Setter Property="Background" Value="#4F4F4F"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Main, Path=BetaVersion}" Value="True">
<DataTrigger Binding="{Binding AppInstance.BetaVersion}" Value="True">
<Setter Property="Background" Value="#378CFB"/>
</DataTrigger>
</Style.Triggers>
@ -52,7 +53,7 @@
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
<Setter Property="Content" Value="{DynamicResource MainWindow_VersionLabel}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Main, Path=BetaVersion}" Value="True">
<DataTrigger Binding="{Binding AppInstance.BetaVersion}" Value="True">
<Setter Property="Content" Value="{DynamicResource MainWindow_BetaVersionLabel}"/>
</DataTrigger>
</Style.Triggers>
@ -60,17 +61,17 @@
</Label.Style>
</Label>
<Label Margin="5,0,0,0" Background="Transparent" Foreground="White" FontSize="12" Content="{Binding Source={x:Static local:App.Instance}, Path=Version}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<Button Margin="5" Click="ASMPatchNotes_Click" ToolTip="{DynamicResource ServerSettings_PatchNotesTooltip}" Style="{StaticResource ButtonStyle1}">
<Button Margin="5" Click="PatchNotes_Click" ToolTip="{DynamicResource ServerSettings_PatchNotesTooltip}" Style="{StaticResource ButtonStyle1}">
<Image Source="{com:Icon Path=/Ark Server Manager;component/Art/ChangeNotes.ico,Size=32}"/>
</Button>
<Button Margin="5,0,0,0" Background="#00AA00" Foreground="White" Padding="1" BorderThickness="1" BorderBrush="White" ContentStringFormat="{DynamicResource MainWindow_UpdateToLabelFormat}" Content="{Binding LatestASMVersion}" Click="Upgrade_Click" VerticalAlignment="Center" >
<Button Margin="5,0,0,0" Background="#00AA00" Foreground="White" Padding="1" BorderThickness="1" BorderBrush="White" ContentStringFormat="{DynamicResource MainWindow_UpdateToLabelFormat}" Content="{Binding LatestServerManagerVersion}" Click="Upgrade_Click" VerticalAlignment="Center" >
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding NewASMAvailable}" Value="True">
<DataTrigger Binding="{Binding NewServerManagerAvailable}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding NewASMAvailable}" Value="False">
<DataTrigger Binding="{Binding NewServerManagerAvailable}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
@ -132,6 +133,7 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Margin="0,-2,0,-3" Background="Transparent" Foreground="White" FontSize="11" Content="{DynamicResource MainWindow_TaskStatusLabel}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
@ -257,6 +259,61 @@
</Button.Style>
</Button>
</StackPanel>
<StackPanel Grid.Row="3" Orientation="Horizontal" VerticalAlignment="Center" Margin="5,0,0,0">
<Label Margin="0" Background="Transparent" Foreground="White" FontSize="10" Content="{DynamicResource MainWindow_DiscordBotStatusLabel}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<Label Margin="0" Background="Transparent" FontSize="10" Content="{Binding DiscordBotStateString}" VerticalAlignment="Center" HorizontalAlignment="Left">
<Label.Style>
<Style BasedOn="{StaticResource {x:Type Label}}" TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="White"/>
<Style.Triggers>
<DataTrigger Binding="{Binding DiscordBotState}" Value="{x:Static bot:Enums.BotState.Disabled}">
<Setter Property="Foreground" Value="DarkRed"/>
</DataTrigger>
<DataTrigger Binding="{Binding DiscordBotState}" Value="{x:Static bot:Enums.BotState.Stopped}">
<Setter Property="Foreground" Value="White"/>
</DataTrigger>
<DataTrigger Binding="{Binding DiscordBotState}" Value="{x:Static bot:Enums.BotState.Running}">
<Setter Property="Foreground" Value="LightGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<Button Margin="5,0,0,0" Padding="1" BorderThickness="1" BorderBrush="White" Click="DiscordBotTaskState_Click" VerticalAlignment="Center">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#00AA00"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Content" Value="{DynamicResource MainWindow_DiscordBotTaskStartLabel}"/>
<Setter Property="ToolTip" Value="{DynamicResource MainWindow_DiscordBotTaskStartTooltip}"/>
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding DiscordBotState}" Value="{x:Static bot:Enums.BotState.Stopped}"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="#00AA00"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Content" Value="{DynamicResource MainWindow_DiscordBotTaskStartLabel}"/>
<Setter Property="ToolTip" Value="{DynamicResource MainWindow_DiscordBotTaskStartTooltip}"/>
<Setter Property="Visibility" Value="Visible"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding DiscordBotState}" Value="{x:Static bot:Enums.BotState.Running}"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="#AA8A00"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Content" Value="{DynamicResource MainWindow_DiscordBotTaskStopLabel}"/>
<Setter Property="ToolTip" Value="{DynamicResource MainWindow_DiscordBotTaskStopTooltip}"/>
<Setter Property="Visibility" Value="Visible"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Grid>
<Grid DockPanel.Dock="Top" VerticalAlignment="Top" Margin="10,0,10,0" HorizontalAlignment="Center">
@ -277,7 +334,7 @@
</ControlTemplate>
</Validation.ErrorTemplate>
<TextBox.Text>
<Binding Path="CurrentConfig.MachinePublicIP" ElementName="Main">
<Binding Path="Config.MachinePublicIP" ElementName="Main">
<Binding.ValidationRules>
<cvr:IpValidationRule ValidatesOnTargetUpdated="true" />
</Binding.ValidationRules>
@ -310,7 +367,7 @@
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}"/>
<Condition Binding="{Binding CurrentConfig.ServerStatus_EnableActions, ElementName=Main}" Value="false"/>
<Condition Binding="{Binding Config.ServerStatus_EnableActions, ElementName=Main}" Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusRunningLabel}"/>
@ -318,7 +375,7 @@
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Running}"/>
<Condition Binding="{Binding CurrentConfig.ServerStatus_EnableActions, ElementName=Main}" Value="true"/>
<Condition Binding="{Binding Config.ServerStatus_EnableActions, ElementName=Main}" Value="true"/>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusRunningLabel}"/>
</MultiDataTrigger>
@ -329,7 +386,7 @@
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}"/>
<Condition Binding="{Binding CurrentConfig.ServerStatus_EnableActions, ElementName=Main}" Value="false"/>
<Condition Binding="{Binding Config.ServerStatus_EnableActions, ElementName=Main}" Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusStoppedLabel}"/>
@ -337,7 +394,7 @@
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Runtime.Status}" Value="{x:Static enum:ServerStatus.Stopped}"/>
<Condition Binding="{Binding CurrentConfig.ServerStatus_EnableActions, ElementName=Main}" Value="true"/>
<Condition Binding="{Binding Config.ServerStatus_EnableActions, ElementName=Main}" Value="true"/>
</MultiDataTrigger.Conditions>
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_RuntimeStatusStoppedLabel}"/>
</MultiDataTrigger>

View file

@ -27,45 +27,80 @@ namespace ServerManagerTool
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public static MainWindow Instance
{
get;
private set;
}
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
private readonly ActionQueue versionChecker;
private readonly ActionQueue scheduledTaskChecker;
private readonly ActionQueue discordBotChecker;
public static readonly DependencyProperty BetaVersionProperty = DependencyProperty.Register(nameof(BetaVersion), typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
public static readonly DependencyProperty IsIpValidProperty = DependencyProperty.Register(nameof(IsIpValid), typeof(bool), typeof(MainWindow));
public static readonly DependencyProperty CurrentConfigProperty = DependencyProperty.Register(nameof(CurrentConfig), typeof(Config), typeof(MainWindow));
private bool discordBotStateClicked = false;
public static readonly DependencyProperty AppInstanceProperty = DependencyProperty.Register(nameof(AppInstance), typeof(App), typeof(MainWindow), new PropertyMetadata(null));
public static readonly DependencyProperty ConfigProperty = DependencyProperty.Register(nameof(Config), typeof(Config), typeof(MainWindow), new PropertyMetadata(null));
public static readonly DependencyProperty ServerManagerProperty = DependencyProperty.Register(nameof(ServerManager), typeof(ServerManager), typeof(MainWindow), new PropertyMetadata(null));
public static readonly DependencyProperty LatestASMVersionProperty = DependencyProperty.Register(nameof(LatestASMVersion), typeof(Version), typeof(MainWindow), new PropertyMetadata(new Version()));
public static readonly DependencyProperty NewASMAvailableProperty = DependencyProperty.Register(nameof(NewASMAvailable), typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
public static readonly DependencyProperty AutoBackupStateProperty = DependencyProperty.Register(nameof(AutoBackupState), typeof(Microsoft.Win32.TaskScheduler.TaskState), typeof(MainWindow), new PropertyMetadata(Microsoft.Win32.TaskScheduler.TaskState.Unknown));
public static readonly DependencyProperty AutoBackupStateStringProperty = DependencyProperty.Register(nameof(AutoBackupStateString), typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty AutoBackupNextRunTimeProperty = DependencyProperty.Register(nameof(AutoBackupNextRunTime), typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty AutoUpdateStateProperty = DependencyProperty.Register(nameof(AutoUpdateState), typeof(Microsoft.Win32.TaskScheduler.TaskState), typeof(MainWindow), new PropertyMetadata(Microsoft.Win32.TaskScheduler.TaskState.Unknown));
public static readonly DependencyProperty AutoUpdateStateStringProperty = DependencyProperty.Register(nameof(AutoUpdateStateString), typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty AutoUpdateNextRunTimeProperty = DependencyProperty.Register(nameof(AutoUpdateNextRunTime), typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty DiscordBotStateProperty = DependencyProperty.Register(nameof(DiscordBotState), typeof(DiscordBot.Enums.BotState), typeof(MainWindow), new PropertyMetadata(DiscordBot.Enums.BotState.Unknown));
public static readonly DependencyProperty DiscordBotStateStringProperty = DependencyProperty.Register(nameof(DiscordBotStateString), typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty IsIpValidProperty = DependencyProperty.Register(nameof(IsIpValid), typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
public static readonly DependencyProperty LatestServerManagerVersionProperty = DependencyProperty.Register(nameof(LatestServerManagerVersion), typeof(Version), typeof(MainWindow), new PropertyMetadata(new Version()));
public static readonly DependencyProperty NewServerManagerAvailableProperty = DependencyProperty.Register(nameof(NewServerManagerAvailable), typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
public bool BetaVersion
public MainWindow()
{
get { return (bool)GetValue(BetaVersionProperty); }
set { SetValue(BetaVersionProperty, value); }
this.AppInstance = App.Instance;
this.Config = Config.Default;
InitializeComponent();
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
this.ServerManager = ServerManager.Instance;
this.DataContext = this;
this.versionChecker = new ActionQueue();
this.scheduledTaskChecker = new ActionQueue();
this.discordBotChecker = new ActionQueue();
IsAdministrator = SecurityUtils.IsAdministrator();
if (!string.IsNullOrWhiteSpace(App.Instance.Title))
{
this.Title = App.Instance.Title;
}
else
{
if (IsAdministrator)
{
this.Title = _globalizer.GetResourceString("MainWindow_TitleWithAdmin");
}
else
{
this.Title = _globalizer.GetResourceString("MainWindow_Title");
}
}
this.Left = Config.Default.MainWindow_Left;
this.Top = Config.Default.MainWindow_Top;
this.Height = Config.Default.MainWindow_Height;
this.Width = Config.Default.MainWindow_Width;
this.WindowState = Config.Default.MainWindow_WindowState;
// hook into the language change event
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
}
public bool IsIpValid
public App AppInstance
{
get { return (bool)GetValue(IsIpValidProperty); }
set { SetValue(IsIpValidProperty, value); }
get { return GetValue(AppInstanceProperty) as App; }
set { SetValue(AppInstanceProperty, value); }
}
public Config CurrentConfig
public Config Config
{
get { return GetValue(CurrentConfigProperty) as Config; }
set { SetValue(CurrentConfigProperty, value); }
get { return GetValue(ConfigProperty) as Config; }
set { SetValue(ConfigProperty, value); }
}
public ServerManager ServerManager
@ -74,18 +109,6 @@ namespace ServerManagerTool
set { SetValue(ServerManagerProperty, value); }
}
public Version LatestASMVersion
{
get { return (Version)GetValue(LatestASMVersionProperty); }
set { SetValue(LatestASMVersionProperty, value); }
}
public bool NewASMAvailable
{
get { return (bool)GetValue(NewASMAvailableProperty); }
set { SetValue(NewASMAvailableProperty, value); }
}
public Microsoft.Win32.TaskScheduler.TaskState AutoBackupState
{
get { return (Microsoft.Win32.TaskScheduler.TaskState)GetValue(AutoBackupStateProperty); }
@ -122,52 +145,40 @@ namespace ServerManagerTool
set { SetValue(AutoUpdateNextRunTimeProperty, value); }
}
public DiscordBot.Enums.BotState DiscordBotState
{
get { return (DiscordBot.Enums.BotState)GetValue(DiscordBotStateProperty); }
set { SetValue(DiscordBotStateProperty, value); }
}
public string DiscordBotStateString
{
get { return (string)GetValue(DiscordBotStateStringProperty); }
set { SetValue(DiscordBotStateStringProperty, value); }
}
public bool IsAdministrator
{
get;
set;
}
public MainWindow()
public bool IsIpValid
{
this.BetaVersion = App.Instance.BetaVersion;
this.CurrentConfig = Config.Default;
get { return (bool)GetValue(IsIpValidProperty); }
set { SetValue(IsIpValidProperty, value); }
}
InitializeComponent();
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
public Version LatestServerManagerVersion
{
get { return (Version)GetValue(LatestServerManagerVersionProperty); }
set { SetValue(LatestServerManagerVersionProperty, value); }
}
MainWindow.Instance = this;
this.ServerManager = ServerManager.Instance;
this.DataContext = this;
this.versionChecker = new ActionQueue();
this.scheduledTaskChecker = new ActionQueue();
IsAdministrator = SecurityUtils.IsAdministrator();
if (!string.IsNullOrWhiteSpace(App.Instance.Title))
{
this.Title = $"{App.Instance.Title}";
}
else
{
if (IsAdministrator)
{
this.Title = _globalizer.GetResourceString("MainWindow_TitleWithAdmin");
}
else
{
this.Title = _globalizer.GetResourceString("MainWindow_Title");
}
}
this.Left = Config.Default.MainWindow_Left;
this.Top = Config.Default.MainWindow_Top;
this.Height = Config.Default.MainWindow_Height;
this.Width = Config.Default.MainWindow_Width;
this.WindowState = Config.Default.MainWindow_WindowState;
// hook into the language change event
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
public bool NewServerManagerAvailable
{
get { return (bool)GetValue(NewServerManagerAvailableProperty); }
set { SetValue(NewServerManagerAvailableProperty, value); }
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
@ -198,6 +209,7 @@ namespace ServerManagerTool
this.versionChecker.PostAction(CheckForUpdates).DoNotWait();
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
this.discordBotChecker.PostAction(CheckForDiscordBot).DoNotWait();
}
private void MainWindow_LocationChanged(object sender, EventArgs e)
@ -261,12 +273,13 @@ namespace ServerManagerTool
this.Title = _globalizer.GetResourceString("MainWindow_Title");
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
this.discordBotChecker.PostAction(CheckForDiscordBot).DoNotWait();
}
private void ASMPatchNotes_Click(object sender, RoutedEventArgs e)
private void PatchNotes_Click(object sender, RoutedEventArgs e)
{
var url = string.Empty;
if (BetaVersion)
if (AppInstance.BetaVersion)
url = Config.Default.ServerManagerVersionBetaFeedUrl;
else
url = Config.Default.ServerManagerVersionFeedUrl;
@ -280,7 +293,7 @@ namespace ServerManagerTool
}
else
{
if (BetaVersion)
if (AppInstance.BetaVersion)
url = Config.Default.LatestASMBetaPatchNotesUrl;
else
url = Config.Default.LatestASMPatchNotesUrl;
@ -424,7 +437,7 @@ namespace ServerManagerTool
private async void Upgrade_Click(object sender, RoutedEventArgs e)
{
var result = MessageBox.Show(String.Format(_globalizer.GetResourceString("MainWindow_Upgrade_Label"), this.LatestASMVersion), _globalizer.GetResourceString("MainWindow_Upgrade_Title"), MessageBoxButton.YesNo, MessageBoxImage.Question);
var result = MessageBox.Show(String.Format(_globalizer.GetResourceString("MainWindow_Upgrade_Label"), this.LatestServerManagerVersion), _globalizer.GetResourceString("MainWindow_Upgrade_Title"), MessageBoxButton.YesNo, MessageBoxImage.Question);
if(result == MessageBoxResult.Yes)
{
try
@ -578,6 +591,36 @@ namespace ServerManagerTool
}
}
private async void DiscordBotTaskState_Click(object sender, RoutedEventArgs e)
{
if (discordBotStateClicked)
return;
discordBotStateClicked = true;
try
{
switch (DiscordBotState)
{
case DiscordBot.Enums.BotState.Stopped:
AppInstance.StartDiscordBot();
break;
case DiscordBot.Enums.BotState.Running:
AppInstance.StopDiscordBot();
break;
}
await Task.Delay(5000);
}
catch (Exception)
{
// Ignore.
}
finally
{
discordBotStateClicked = false;
}
}
public ICommand ShowWindowCommand
{
get
@ -640,8 +683,8 @@ namespace ServerManagerTool
var appVersion = new Version();
Version.TryParse(App.Instance.Version, out appVersion);
this.LatestASMVersion = newVersion;
this.NewASMAvailable = appVersion < newVersion;
this.LatestServerManagerVersion = newVersion;
this.NewServerManagerAvailable = appVersion < newVersion;
Logger.Info($"{nameof(CheckForUpdates)} performed");
}
@ -669,8 +712,8 @@ namespace ServerManagerTool
this.AutoBackupState = backupState;
this.AutoUpdateState = updateState;
this.AutoBackupStateString = GetTaskStateString(AutoBackupState);
this.AutoUpdateStateString = GetTaskStateString(AutoUpdateState);
this.AutoBackupStateString = GetTaskSchedulerStateString(AutoBackupState);
this.AutoUpdateStateString = GetTaskSchedulerStateString(AutoUpdateState);
this.AutoBackupNextRunTime = backupnextRunTime == DateTime.MinValue ? string.Empty : $"{_globalizer.GetResourceString("MainWindow_TaskRunTimeLabel")} {backupnextRunTime:G}";
this.AutoUpdateNextRunTime = updatenextRunTime == DateTime.MinValue ? string.Empty : $"{_globalizer.GetResourceString("MainWindow_TaskRunTimeLabel")} {updatenextRunTime:G}";
@ -687,7 +730,46 @@ namespace ServerManagerTool
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
}
private string GetTaskStateString(Microsoft.Win32.TaskScheduler.TaskState taskState)
private async Task CheckForDiscordBot()
{
TaskUtils.RunOnUIThreadAsync(() =>
{
try
{
var botState = DiscordBot.Enums.BotState.Unknown;
if (AppInstance.DiscordBotStarted)
{
botState = DiscordBot.Enums.BotState.Running;
}
else
{
if (Config.DiscordBotEnabled)
{
botState = DiscordBot.Enums.BotState.Stopped;
}
else
{
botState = DiscordBot.Enums.BotState.Disabled;
}
}
this.DiscordBotState = botState;
this.DiscordBotStateString = GetDiscordBotStateString(botState);
Logger.Info($"{nameof(CheckForDiscordBot)} performed");
}
catch (Exception)
{
// Ignore.
}
}).DoNotWait();
await Task.Delay(Config.Default.DiscordBotStatusCheckTime * 1 * 1000);
this.discordBotChecker.PostAction(CheckForDiscordBot).DoNotWait();
}
private string GetTaskSchedulerStateString(Microsoft.Win32.TaskScheduler.TaskState taskState)
{
switch (taskState)
{
@ -706,6 +788,21 @@ namespace ServerManagerTool
}
}
private string GetDiscordBotStateString(DiscordBot.Enums.BotState botState)
{
switch (botState)
{
case DiscordBot.Enums.BotState.Disabled:
return _globalizer.GetResourceString("MainWindow_TaskStateDisabledLabel");
case DiscordBot.Enums.BotState.Running:
return _globalizer.GetResourceString("MainWindow_TaskStateRunningLabel");
case DiscordBot.Enums.BotState.Stopped:
return _globalizer.GetResourceString("MainWindow_TaskStateStoppedLabel");
default:
return _globalizer.GetResourceString("MainWindow_TaskStateUnknownLabel");
}
}
private async Task StartServerAsync(Server server)
{
if (server == null || server.Profile == null || server.Runtime == null || server.Runtime.Status != ServerStatus.Stopped)

View file

@ -1,4 +1,5 @@
using ServerManagerTool.Common.Lib;
using ServerManagerTool.Common.Extensions;
using ServerManagerTool.Common.Lib;
using ServerManagerTool.Common.Utils;
using ServerManagerTool.Enums;
using ServerManagerTool.Lib;
@ -927,7 +928,7 @@ namespace ServerManagerTool
yield return new RCONOutput_Command($"> {command.rawCommand}");
}
if(!command.suppressOutput && command.lines.Count() > 0)
if(!command.suppressOutput && !command.lines.IsEmpty())
{
yield return new LineBreak();
}

View file

@ -16,6 +16,6 @@
</ResourceDictionary>
</Window.Resources>
<Grid>
<local:GlobalSettingsControl HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch" Background="{StaticResource BeigeGradient}"/>
<local:GlobalSettingsControl x:Name="globalSettingsControl" HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch" Background="{StaticResource BeigeGradient}"/>
</Grid>
</Window>

View file

@ -22,6 +22,8 @@ namespace ServerManagerTool
protected override void OnClosed(EventArgs e)
{
globalSettingsControl.ApplyChangesToConfig();
if (SecurityUtils.IsAdministrator())
{
// check if the Auto Update has been enabled.

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
@ -18,29 +19,35 @@ namespace ArkData
/// <returns>The async task context containing the resulting container.</returns>
public static async Task<DataContainer> CreateAsync(string playerFileFolder, string tribeFileFolder)
{
var playerFiles = new string[0];
var tribeFiles = new string[0];
IEnumerable<string> playerFiles = null;
IEnumerable<string> tribeFiles = null;
if (Directory.Exists(playerFileFolder))
{
playerFiles = Directory.GetFiles(playerFileFolder).Where(f => Path.GetFileNameWithoutExtension(f).StartsWith(DataFileDetails.PlayerFilePrefix)
&& Path.GetFileNameWithoutExtension(f).EndsWith(DataFileDetails.PlayerFileSuffix)
&& Path.GetExtension(f).Equals(DataFileDetails.PlayerFileExtension)).ToArray();
&& Path.GetExtension(f).Equals(DataFileDetails.PlayerFileExtension));
}
if (Directory.Exists(tribeFileFolder))
{
tribeFiles = Directory.GetFiles(tribeFileFolder).Where(f => Path.GetFileNameWithoutExtension(f).StartsWith(DataFileDetails.TribeFilePrefix)
&& Path.GetFileNameWithoutExtension(f).EndsWith(DataFileDetails.TribeFileSuffix)
&& Path.GetExtension(f).Equals(DataFileDetails.TribeFileExtension)).ToArray();
&& Path.GetExtension(f).Equals(DataFileDetails.TribeFileExtension));
}
var container = new DataContainer();
foreach (var file in playerFiles)
container.Players.Add(await Parser.ParsePlayerAsync(file));
if (playerFiles != null)
{
foreach (var file in playerFiles)
container.Players.Add(await Parser.ParsePlayerAsync(file));
}
foreach (var file in tribeFiles)
container.Tribes.Add(await Parser.ParseTribeAsync(file));
if (tribeFiles != null)
{
foreach (var file in tribeFiles)
container.Tribes.Add(await Parser.ParseTribeAsync(file));
}
container.LinkPlayerTribe();
@ -58,14 +65,14 @@ namespace ArkData
// need to make multiple calls of 100 steam id's.
var lastSteamUpdateUtc = DateTime.UtcNow;
var startIndex = 0;
var playerSteamIds = Players.Where(p => p.LastPlatformUpdateUtc.AddMinutes(steamUpdateInterval) < DateTime.UtcNow).Select(p => p.PlayerId).ToArray();
var playerSteamIds = Players.Where(p => p.LastPlatformUpdateUtc.AddMinutes(steamUpdateInterval) < DateTime.UtcNow).Select(p => p.PlayerId);
while (true)
{
// check if the start index has exceeded the Players list count.
if (startIndex >= playerSteamIds.Length) break;
if (startIndex >= playerSteamIds.Count()) break;
// get the number of steam ids to read.
int steamIdsCount = System.Math.Min(MAX_STEAM_IDS, playerSteamIds.Length - startIndex);
int steamIdsCount = Math.Min(MAX_STEAM_IDS, playerSteamIds.Count() - startIndex);
// get a comma delimited list of the steam ids to process
var builder = string.Join(",", playerSteamIds, startIndex, steamIdsCount);

View file

@ -45,7 +45,7 @@ namespace ArkData
{
try
{
var online = Enumerable.OfType<PlayerInfo>(new SSQL().Players(new IPEndPoint(IPAddress.Parse(ipString), port))).ToList();
var online = Enumerable.OfType<PlayerInfo>(new SSQL().Players(new IPEndPoint(IPAddress.Parse(ipString), port)));
for (var i = 0; i < Players.Count; i++)
{

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
@ -16,29 +17,35 @@ namespace ArkData
/// </summary>
public static DataContainer Create(string playerFileFolder, string tribeFileFolder)
{
var playerFiles = new string[0];
var tribeFiles = new string[0];
IEnumerable<string> playerFiles = null;
IEnumerable<string> tribeFiles = null;
if (Directory.Exists(playerFileFolder))
{
playerFiles = Directory.GetFiles(playerFileFolder).Where(f => Path.GetFileNameWithoutExtension(f).StartsWith(DataFileDetails.PlayerFilePrefix)
&& Path.GetFileNameWithoutExtension(f).EndsWith(DataFileDetails.PlayerFileSuffix)
&& Path.GetExtension(f).Equals(DataFileDetails.PlayerFileExtension)).ToArray();
&& Path.GetExtension(f).Equals(DataFileDetails.PlayerFileExtension));
}
if (Directory.Exists(tribeFileFolder))
{
tribeFiles = Directory.GetFiles(tribeFileFolder).Where(f => Path.GetFileNameWithoutExtension(f).StartsWith(DataFileDetails.TribeFilePrefix)
&& Path.GetFileNameWithoutExtension(f).EndsWith(DataFileDetails.TribeFileSuffix)
&& Path.GetExtension(f).Equals(DataFileDetails.TribeFileExtension)).ToArray();
&& Path.GetExtension(f).Equals(DataFileDetails.TribeFileExtension));
}
var container = new DataContainer();
foreach (var file in playerFiles)
container.Players.Add(Parser.ParsePlayer(file));
if (playerFiles != null)
{
foreach (var file in playerFiles)
container.Players.Add(Parser.ParsePlayer(file));
}
foreach (var file in tribeFiles)
container.Tribes.Add(Parser.ParseTribe(file));
if (tribeFiles != null)
{
foreach (var file in tribeFiles)
container.Tribes.Add(Parser.ParseTribe(file));
}
container.LinkPlayerTribe();
@ -56,14 +63,14 @@ namespace ArkData
// need to make multiple calls of 100 steam id's.
var lastSteamUpdateUtc = DateTime.UtcNow;
var startIndex = 0;
var playerSteamIds = Players.Where(p => p.LastPlatformUpdateUtc.AddMinutes(steamUpdateInterval) < DateTime.UtcNow).Select(p => p.PlayerId).ToArray();
var playerSteamIds = Players.Where(p => p.LastPlatformUpdateUtc.AddMinutes(steamUpdateInterval) < DateTime.UtcNow).Select(p => p.PlayerId);
while (true)
{
// check if the start index has exceeded the Players list count.
if (startIndex >= playerSteamIds.Length) break;
if (startIndex >= playerSteamIds.Count()) break;
// get the number of steam ids to read.
int steamIdsCount = System.Math.Min(MAX_STEAM_IDS, playerSteamIds.Length - startIndex);
int steamIdsCount = Math.Min(MAX_STEAM_IDS, playerSteamIds.Count() - startIndex);
// get a comma delimited list of the steam ids to process
var builder = string.Join(",", playerSteamIds, startIndex, steamIdsCount);

View file

@ -18,7 +18,7 @@ namespace ArkData
return -1;
}
public static int[] Locate(this byte[] self, byte[] candidate)
public static IEnumerable<int> Locate(this byte[] self, byte[] candidate)
{
if (IsEmptyLocate(self, candidate, 0))
return Empty;
@ -29,7 +29,7 @@ namespace ArkData
list.Add(position);
if (list.Count != 0)
return list.ToArray();
return list;
return Empty;
}

View file

@ -263,6 +263,9 @@
<setting name="DiscordBotHelpUrl" serializeAs="String">
<value>https://servermanagers.freeforums.net/thread/99/get-own-discord-bot</value>
</setting>
<setting name="DiscordBotStatusCheckTime" serializeAs="String">
<value>10</value>
</setting>
</ServerManagerTool.Config>
<ServerManagerTool.Common.CommonConfig>
<setting name="DefaultSteamAPIKey" serializeAs="String">
@ -580,7 +583,7 @@
<value>False</value>
</setting>
<setting name="DiscordBotPrefix" serializeAs="String">
<value>csm</value>
<value>csm!</value>
</setting>
<setting name="DiscordBotToken" serializeAs="String">
<value />
@ -615,6 +618,20 @@
<setting name="ServerMonitorWindow_Top" serializeAs="String">
<value>50</value>
</setting>
<setting name="DiscordBotWhitelist" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</value>
</setting>
<setting name="DiscordBotPrefixFixed" serializeAs="String">
<value>False</value>
</setting>
<setting name="DiscordBotLogLevel" serializeAs="String">
<value>Info</value>
</setting>
<setting name="DiscordBotAllowAllBots" serializeAs="String">
<value>False</value>
</setting>
</ServerManagerTool.Config>
</userSettings>
</configuration>

View file

@ -10,6 +10,7 @@ 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,7 +38,7 @@ namespace ServerManagerTool
public event PropertyChangedEventHandler PropertyChanged;
private CancellationTokenSource _tokenSource;
private CancellationTokenSource _tokenSourceDiscordBot;
private GlobalizedApplication _globalizer;
private bool _applicationStarted;
private string _args;
@ -48,7 +49,45 @@ namespace ServerManagerTool
public App()
{
if (string.IsNullOrWhiteSpace(Config.Default.ServerManagerUniqueKey))
{
Config.Default.ServerManagerUniqueKey = Guid.NewGuid().ToString();
}
if (!string.IsNullOrWhiteSpace(Config.Default.DataPath))
{
var root = Path.GetPathRoot(Config.Default.DataPath);
if (!root.EndsWith("\\"))
{
Config.Default.DataPath = Config.Default.DataPath.Replace(root, root + "\\");
}
}
if (!string.IsNullOrWhiteSpace(Config.Default.ConfigPath))
{
var root = Path.GetPathRoot(Config.Default.ConfigPath);
if (!root.EndsWith("\\"))
{
Config.Default.ConfigPath = Config.Default.ConfigPath.Replace(root, root + "\\");
}
}
if (!string.IsNullOrWhiteSpace(Config.Default.BackupPath))
{
var root = Path.GetPathRoot(Config.Default.BackupPath);
if (!root.EndsWith("\\"))
{
Config.Default.BackupPath = Config.Default.BackupPath.Replace(root, root + "\\");
}
}
if (!string.IsNullOrWhiteSpace(Config.Default.AutoUpdate_CacheDir))
{
var root = Path.GetPathRoot(Config.Default.AutoUpdate_CacheDir);
if (!root.EndsWith("\\"))
{
Config.Default.AutoUpdate_CacheDir = Config.Default.AutoUpdate_CacheDir.Replace(root, root + "\\");
}
}
App.Instance = this;
ApplicationStarted = false;
@ -111,6 +150,18 @@ namespace ServerManagerTool
}
}
public bool DiscordBotStarted
{
get
{
return _tokenSourceDiscordBot != null;
}
set
{
OnPropertyChanged();
}
}
public string Title
{
get
@ -239,6 +290,14 @@ namespace ServerManagerTool
Config.Default.UpgradeConfig = false;
Config.Default.Save();
}
if (!Config.Default.DiscordBotPrefixFixed)
{
if (!Config.Default.DiscordBotPrefix.EndsWith("!"))
Config.Default.DiscordBotPrefix += "!";
Config.Default.DiscordBotPrefixFixed = true;
Config.Default.Save();
Config.Default.Reload();
}
Config.Default.SteamCmdRedirectOutput = false;
}
@ -432,21 +491,7 @@ namespace ServerManagerTool
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);
StartDiscordBot();
}
}
@ -488,11 +533,7 @@ namespace ServerManagerTool
private void ShutDownApplication()
{
if (!(_tokenSource is null))
{
_tokenSource.Cancel();
_tokenSource.Dispose();
}
StopDiscordBot();
if (this.ApplicationStarted)
{
@ -525,13 +566,68 @@ namespace ServerManagerTool
var installFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var backupFolder = includeBackup
? IOUtils.NormalizePath(string.IsNullOrWhiteSpace(Config.Default.BackupPath)
? string.IsNullOrWhiteSpace(Config.Default.BackupPath)
? Path.Combine(Config.Default.DataPath, Config.Default.BackupRelativePath)
: Path.Combine(Config.Default.BackupPath))
: Path.Combine(Config.Default.BackupPath)
: null;
SettingsUtils.BackupUserConfigSettings(Config.Default, "userconfig.json", installFolder, backupFolder);
SettingsUtils.BackupUserConfigSettings(CommonConfig.Default, "commonconfig.json", installFolder, backupFolder);
}
public void StartDiscordBot()
{
if (_tokenSourceDiscordBot != null)
{
return;
}
_tokenSourceDiscordBot = new CancellationTokenSource();
DiscordBotStarted = true;
Task discordTask = Task.Run(async () =>
{
var discordWhiteList = new List<string>();
if (Config.Default.DiscordBotWhitelist != null)
{
discordWhiteList.AddRange(Config.Default.DiscordBotWhitelist.Cast<string>());
}
await ServerManagerBotFactory.GetServerManagerBot()?.StartAsync(Config.Default.DiscordBotLogLevel, Config.Default.DiscordBotToken, Config.Default.DiscordBotPrefix, Config.Default.DataPath, Config.Default.DiscordBotAllowAllBots, discordWhiteList, DiscordBotHelper.HandleDiscordCommand, DiscordBotHelper.HandleTranslation, _tokenSourceDiscordBot.Token);
if (_tokenSourceDiscordBot != null)
{
// cleanup the token
_tokenSourceDiscordBot.Dispose();
_tokenSourceDiscordBot = null;
}
DiscordBotStarted = false;
}, _tokenSourceDiscordBot.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);
if (_tokenSourceDiscordBot != null)
{
// cleanup the token
_tokenSourceDiscordBot.Dispose();
_tokenSourceDiscordBot = null;
}
DiscordBotStarted = false;
}, TaskContinuationOptions.OnlyOnFaulted);
}
public void StopDiscordBot()
{
if (!(_tokenSourceDiscordBot is null))
{
_tokenSourceDiscordBot.Cancel();
}
}
}
}

View file

@ -147,7 +147,6 @@
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>

View file

@ -1980,7 +1980,7 @@ namespace ServerManagerTool {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("csm")]
[global::System.Configuration.DefaultSettingValueAttribute("csm!")]
public string DiscordBotPrefix {
get {
return ((string)(this["DiscordBotPrefix"]));
@ -2139,5 +2139,63 @@ namespace ServerManagerTool {
this["ServerMonitorWindow_Top"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<ArrayOfString xmlns:xsd=\"http://www.w3." +
"org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" />")]
public global::System.Collections.Specialized.StringCollection DiscordBotWhitelist {
get {
return ((global::System.Collections.Specialized.StringCollection)(this["DiscordBotWhitelist"]));
}
set {
this["DiscordBotWhitelist"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool DiscordBotPrefixFixed {
get {
return ((bool)(this["DiscordBotPrefixFixed"]));
}
set {
this["DiscordBotPrefixFixed"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Info")]
public global::ServerManagerTool.DiscordBot.Enums.LogLevel DiscordBotLogLevel {
get {
return ((global::ServerManagerTool.DiscordBot.Enums.LogLevel)(this["DiscordBotLogLevel"]));
}
set {
this["DiscordBotLogLevel"] = value;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("10")]
public int DiscordBotStatusCheckTime {
get {
return ((int)(this["DiscordBotStatusCheckTime"]));
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool DiscordBotAllowAllBots {
get {
return ((bool)(this["DiscordBotAllowAllBots"]));
}
set {
this["DiscordBotAllowAllBots"] = value;
}
}
}
}

View file

@ -549,7 +549,7 @@
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="DiscordBotPrefix" Type="System.String" Scope="User">
<Value Profile="(Default)">csm</Value>
<Value Profile="(Default)">csm!</Value>
</Setting>
<Setting Name="DiscordBotToken" Type="System.String" Scope="User">
<Value Profile="(Default)" />
@ -590,5 +590,21 @@
<Setting Name="ServerMonitorWindow_Top" Type="System.Double" Scope="User">
<Value Profile="(Default)">50</Value>
</Setting>
<Setting Name="DiscordBotWhitelist" Type="System.Collections.Specialized.StringCollection" Scope="User">
<Value Profile="(Default)">&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /&gt;</Value>
</Setting>
<Setting Name="DiscordBotPrefixFixed" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="DiscordBotLogLevel" Type="ServerManagerTool.DiscordBot.Enums.LogLevel" Scope="User">
<Value Profile="(Default)">Info</Value>
</Setting>
<Setting Name="DiscordBotStatusCheckTime" Type="System.Int32" Scope="Application">
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="DiscordBotAllowAllBots" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>

View file

@ -8,8 +8,9 @@
AutoShutdown1,
AutoShutdown2,
Backup,
Shutdown,
Restart,
Shutdown,
Stop,
Update,
}
}

View file

@ -57,12 +57,21 @@
<sys:String x:Key="ProcessorAffinity_All">All</sys:String>
<!--#endregion-->
<!--#region Processor Window States -->
<!--#region Window States -->
<sys:String x:Key="WindowState_Normal">Normal</sys:String>
<sys:String x:Key="WindowState_Minimized">Minimized</sys:String>
<sys:String x:Key="WindowState_Maximized">Maximized</sys:String>
<!--#endregion-->
<!--#region Discord Bot Log Levels -->
<sys:String x:Key="DiscordBotLogLevel_Critical">Critical</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Error">Error</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Warning">Warning</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Info">Info</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Verbose">Verbose</sys:String>
<sys:String x:Key="DiscordBotLogLevel_Debug">Debug</sys:String>
<!--#endregion-->
<!--#region Unit strings -->
<sys:String x:Key="SliderUnits_Multiplier">x</sys:String>
<sys:String x:Key="SliderUnits_Percentage">%</sys:String>
@ -120,6 +129,7 @@
<sys:String x:Key="AutoUpdater_Status_DownloadNewServerComplete">Server download complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Complete">Complete</sys:String>
<sys:String x:Key="AutoUpdater_Status_Cancelled">Cancelled</sys:String>
<sys:String x:Key="AutoUpdater_Status_Failed">Failed</sys:String>
<sys:String x:Key="AutoUpdater_CancelButtonLabel">Cancel</sys:String>
<!--#endregion-->
@ -605,12 +615,18 @@
<sys:String x:Key="MainWindow_AutoUpdateTaskEnableLabel">Enable</sys:String>
<sys:String x:Key="MainWindow_AutoUpdateTaskEnableTooltip">Enable the auto-update scheduled task</sys:String>
<sys:String x:Key="MainWindow_TaskRunTimeLabel">Next Run Time:</sys:String>
<sys:String x:Key="MainWindow_DiscordBotStatusLabel">Discord Bot:</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStartLabel">Start</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStartTooltip">Start the discord bot</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStopLabel">Stop</sys:String>
<sys:String x:Key="MainWindow_DiscordBotTaskStopTooltip">Stop the discord bot</sys:String>
<sys:String x:Key="MainWindow_TaskStateUnknownLabel">Unknown</sys:String>
<sys:String x:Key="MainWindow_TaskStateDisabledLabel">Disabled</sys:String>
<sys:String x:Key="MainWindow_TaskStateQueuedLabel">Queued</sys:String>
<sys:String x:Key="MainWindow_TaskStateReadyLabel">Ready</sys:String>
<sys:String x:Key="MainWindow_TaskStateRunningLabel">Running</sys:String>
<sys:String x:Key="MainWindow_TaskStateStoppedLabel">Stopped</sys:String>
<sys:String x:Key="MainWindow_ProfileLoad_FailedTitle">Profile failed to load</sys:String>
<sys:String x:Key="MainWindow_ProfileLoad_FailedLabel">The profile at {0} failed to load. The error was: {1}\r\n{2}</sys:String>
@ -779,8 +795,17 @@
<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_DiscordBotLogLevelLabel">Log Level:</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="ServerSettings_DiscordBotAllowAllBotsLabel">Allow All Bots</sys:String>
<sys:String x:Key="ServerSettings_DiscordBotAllowAllBotsTooltip">If enabled, the server manager bot will respond to all other bots, otherwise they will be ignored unless they are in the whitelist.</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistLabel">Bot Whitelist</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdLabel">Bot ID</sys:String>
<sys:String x:Key="GlobalSettings_DiscordBotWhitelistIdTooltip">The id of the bot to whitelist.</sys:String>
<sys:String x:Key="ServerSettings_AddDiscordBotWhitelistTooltip">Add Whitelist</sys:String>
<sys:String x:Key="ServerSettings_ClearDiscordBotWhitelistTooltip">Clear Whitelists</sys:String>
<sys:String x:Key="ServerSettings_RemoveDiscordBotWhitelistTooltip">Delete Whitelist</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>
@ -1147,6 +1172,8 @@
<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_DiscordAliasLabel">Alias:</sys:String>
<sys:String x:Key="ServerSettings_DiscordAliasTooltip">A unique name to identify your server when using the discord commands, can be used instead of the profile id.</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>
@ -1244,8 +1271,9 @@
<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_ProfileMissing">The '{0}' command requires a profile id or alias.</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_ProfileMultiples">Multiple profiles with '{0}' were found in the channel, command aborted.</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>

View file

@ -423,6 +423,16 @@ namespace ServerManagerTool.Lib
LogProfileMessage("Starting shutdown timer...");
var minutesLeft = ShutdownInterval;
if (ServerProcess == ServerProcessType.Stop)
{
LogProfileMessage($"Server shutdown type is {ServerProcess}, shutdown timer cancelled.");
minutesLeft = 0;
}
else if (!CheckForOnlinePlayers)
{
LogProfileMessage("CheckForOnlinePlayers disabled, shutdown timer will not perform online player check.");
}
while (minutesLeft > 0)
{
if (cancellationToken.IsCancellationRequested)
@ -446,8 +456,8 @@ namespace ServerManagerTool.Lib
// 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;
var playerInfo = gameServer?.GetPlayers()?.Where(p => !string.IsNullOrWhiteSpace(p.Name?.Trim()));
var playerCount = playerInfo?.Count() ?? -1;
// check if anyone is logged into the server
if (playerCount <= 0)
@ -466,7 +476,6 @@ namespace ServerManagerTool.Lib
else
{
Debug.WriteLine($"CheckForOnlinePlayers disabled, shutdown timer cancelled.");
break;
}
var message = string.Empty;
@ -1781,7 +1790,7 @@ namespace ServerManagerTool.Lib
comment.AppendLine($"Profile Name: {_profile.ProfileName}");
comment.AppendLine($"Process: {ServerProcess}");
ZipUtils.ZipFiles(backupFile, files.ToArray(), comment.ToString(), false);
ZipUtils.ZipFiles(backupFile, files, comment.ToString(), false);
LogProfileMessage($"Backup file created - {backupFile}");
}
@ -1901,7 +1910,7 @@ namespace ServerManagerTool.Lib
ZipUtils.ZipAFile(backupFile, worldFileName, worldBackupFile, comment.ToString());
if (files.Count > 0)
ZipUtils.UpdateFiles(backupFile, files.ToArray(), null, false, "");
ZipUtils.UpdateFiles(backupFile, files, null, false, "");
LogProfileMessage($"Backed up world files - {saveFolder}");
LogProfileMessage($"Backup file created - {backupFile}");
@ -2842,7 +2851,7 @@ namespace ServerManagerTool.Lib
if (ExitCode == EXITCODE_NORMALEXIT)
{
// get the profile associated with the branch
var profiles = _profiles.Keys.Where(p => p.EnableAutoUpdate && p.BranchName.Equals(branch.BranchName, StringComparison.OrdinalIgnoreCase)).ToArray();
var profiles = _profiles.Keys.Where(p => p.EnableAutoUpdate && p.BranchName.Equals(branch.BranchName, StringComparison.OrdinalIgnoreCase));
var profileExitCodes = new ConcurrentDictionary<ServerProfileSnapshot, int>();
if (Config.Default.AutoUpdate_ParallelUpdate)
@ -3093,7 +3102,7 @@ namespace ServerManagerTool.Lib
if (exitCode == EXITCODE_NORMALEXIT)
{
var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => BranchSnapshot.Create(p)).Distinct(new BranchSnapshotComparer()).ToArray();
var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => BranchSnapshot.Create(p)).Distinct(new BranchSnapshotComparer());
var exitCodes = new ConcurrentDictionary<BranchSnapshot, int>();
// update the server cache for each branch

View file

@ -212,7 +212,7 @@ namespace ServerManagerTool.Lib
return;
// remove any players that do not have a player record.
var droppedPlayers = this._players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null).ToArray();
var droppedPlayers = this._players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null);
foreach (var droppedPlayer in droppedPlayers)
{
_players.TryRemove(droppedPlayer.PlayerId, out PlayerInfo player);

View file

@ -576,6 +576,14 @@ namespace ServerManagerTool.Lib
set { SetValue(DiscordChannelIdProperty, value); }
}
public static readonly DependencyProperty DiscordAliasProperty = DependencyProperty.Register(nameof(DiscordAlias), typeof(string), typeof(ServerProfile), new PropertyMetadata(String.Empty));
[DataMember]
public string DiscordAlias
{
get { return (string)GetValue(DiscordAliasProperty); }
set { SetValue(DiscordAliasProperty, value); }
}
public static readonly DependencyProperty AllowDiscordBackupProperty = DependencyProperty.Register(nameof(AllowDiscordBackup), typeof(bool), typeof(ServerProfile), new PropertyMetadata(true));
[DataMember]
public bool AllowDiscordBackup
@ -688,8 +696,7 @@ namespace ServerManagerTool.Lib
{
InstallDirectory = folder;
LoadServerFileBlacklisted();
LoadServerFileWhitelisted();
LoadServerFiles(true, true);
SetupServerFilesWatcher();
}
@ -759,8 +766,7 @@ namespace ServerManagerTool.Lib
internal static ServerProfile FromDefaults()
{
var settings = new ServerProfile();
settings.LoadServerFileBlacklisted();
settings.LoadServerFileWhitelisted();
settings.LoadServerFiles(true, true);
settings.SetupServerFilesWatcher();
return settings;
}
@ -794,11 +800,9 @@ namespace ServerManagerTool.Lib
}
}
private static Enum[] GetExclusions()
private static IEnumerable<Enum> GetExclusions()
{
var exclusions = new List<Enum>();
return exclusions.ToArray();
return new List<Enum>();
}
public string GetLauncherFile() => Path.Combine(GetProfileServerConfigDir(), Config.Default.LauncherFile);
@ -887,7 +891,7 @@ namespace ServerManagerTool.Lib
return profile;
}
public static ServerProfile LoadFromConfigFiles(string file, ServerProfile profile, Enum[] exclusions = null)
public static ServerProfile LoadFromConfigFiles(string file, ServerProfile profile, IEnumerable<Enum> exclusions = null)
{
if (string.IsNullOrWhiteSpace(file) || !File.Exists(file))
return null;
@ -949,8 +953,7 @@ namespace ServerManagerTool.Lib
profile = LoadFromConfigFiles(serverConfigFile, profile);
}
profile.LoadServerFileBlacklisted();
profile.LoadServerFileWhitelisted();
profile.LoadServerFiles(true, true);
profile.SetupServerFilesWatcher();
profile._lastSaveLocation = file;
@ -1111,7 +1114,7 @@ namespace ServerManagerTool.Lib
SaveConfigFile(serverConfigDir);
}
public void SaveConfigFile(string configDir, Enum[] exclusions = null)
public void SaveConfigFile(string configDir, IEnumerable<Enum> exclusions = null)
{
if (exclusions == null)
exclusions = GetExclusions();
@ -1536,14 +1539,19 @@ namespace ServerManagerTool.Lib
#region Server Files
private void ServerFilesWatcher_Changed(object sender, FileSystemEventArgs e)
{
var blacklistFile = false;
var whitelistFile = false;
if (e.Name.Equals(Config.Default.ServerBlacklistFile, StringComparison.OrdinalIgnoreCase))
{
TaskUtils.RunOnUIThreadAsync(() => LoadServerFileBlacklisted()).DoNotWait();
blacklistFile = true;
}
if (e.Name.Equals(Config.Default.ServerWhitelistFile, StringComparison.OrdinalIgnoreCase))
{
TaskUtils.RunOnUIThreadAsync(() => LoadServerFileWhitelisted()).DoNotWait();
whitelistFile = true;
}
TaskUtils.RunOnUIThreadAsync(() => LoadServerFiles(blacklistFile, whitelistFile)).DoNotWait();
}
private void ServerFilesWatcher_Error(object sender, ErrorEventArgs e)
@ -1589,58 +1597,58 @@ namespace ServerManagerTool.Lib
_serverFilesWatcher.EnableRaisingEvents = true;
}
public void LoadServerFileBlacklisted()
public void LoadServerFiles(bool blacklistFile, bool whitelistFile)
{
try
{
var list = this.ServerFilesBlacklisted ?? new PlayerUserList();
var list1 = this.ServerFilesBlacklisted ?? new PlayerUserList();
var list2 = this.ServerFilesWhitelisted ?? new PlayerUserList();
var file = Path.Combine(InstallDirectory, Config.Default.SavedFilesRelativePath, Config.Default.ServerBlacklistFile);
if (File.Exists(file))
var allSteamIds = new List<string>();
string[] blacklistSteamIds = null;
string[] whitelistSteamIds = null;
if (blacklistFile)
{
var steamIds = File.ReadAllLines(file);
var steamUsers = SteamUtils.GetSteamUserDetails(steamIds.ToList());
list = PlayerUserList.GetList(steamUsers, steamIds);
var file = Path.Combine(InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ServerBlacklistFile);
if (File.Exists(file))
{
blacklistSteamIds = File.ReadAllLines(file);
allSteamIds.AddRange(blacklistSteamIds);
}
}
this.ServerFilesBlacklisted = list;
}
catch (IOException)
{
// do nothing
if (whitelistFile)
{
var file = Path.Combine(InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ServerWhitelistFile);
if (File.Exists(file))
{
whitelistSteamIds = File.ReadAllLines(file);
allSteamIds.AddRange(whitelistSteamIds);
}
}
// remove all duplicates
allSteamIds = allSteamIds.Distinct().ToList();
// fetch the details of all steam users in the list
var steamUsers = SteamUtils.GetSteamUserDetails(allSteamIds);
if (blacklistFile && blacklistSteamIds != null)
{
list1 = PlayerUserList.GetList(steamUsers, blacklistSteamIds);
}
if (whitelistFile && whitelistSteamIds != null)
{
list2 = PlayerUserList.GetList(steamUsers, whitelistSteamIds);
}
this.ServerFilesBlacklisted = list1;
this.ServerFilesWhitelisted = list2;
}
catch (Exception ex)
{
this.ServerFilesBlacklisted = new PlayerUserList();
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_ServerFilesLoadErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public void LoadServerFileWhitelisted()
{
try
{
var list = this.ServerFilesWhitelisted ?? new PlayerUserList();
var file = Path.Combine(InstallDirectory, Config.Default.SavedFilesRelativePath, Config.Default.ServerWhitelistFile);
if (File.Exists(file))
{
var steamIds = File.ReadAllLines(file);
var steamUsers = SteamUtils.GetSteamUserDetails(steamIds.ToList());
list = PlayerUserList.GetList(steamUsers, steamIds);
}
this.ServerFilesWhitelisted = list;
}
catch (IOException)
{
// do nothing
}
catch (Exception ex)
{
this.ServerFilesWhitelisted = new PlayerUserList();
MessageBox.Show(ex.Message, _globalizer.GetResourceString("ServerSettings_ServerFilesLoadErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@ -1654,7 +1662,7 @@ namespace ServerManagerTool.Lib
Directory.CreateDirectory(folder);
var file = Path.Combine(folder, Config.Default.ServerBlacklistFile);
File.WriteAllLines(file, this.ServerFilesBlacklisted.ToArray());
File.WriteAllLines(file, this.ServerFilesBlacklisted.ToEnumerable());
}
catch (Exception ex)
{
@ -1671,7 +1679,7 @@ namespace ServerManagerTool.Lib
Directory.CreateDirectory(folder);
var file = Path.Combine(folder, Config.Default.ServerWhitelistFile);
File.WriteAllLines(file, this.ServerFilesWhitelisted.ToArray());
File.WriteAllLines(file, this.ServerFilesWhitelisted.ToEnumerable());
}
catch (Exception ex)
{

View file

@ -450,7 +450,7 @@ namespace ServerManagerTool.Lib
return new List<string>();
// remove any players that do not have a player record.
var droppedPlayers = this._players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null).ToArray();
var droppedPlayers = this._players.Values.Where(p => dataContainer.Players.FirstOrDefault(pd => pd.PlayerId.Equals(p.PlayerId, StringComparison.OrdinalIgnoreCase)) == null);
foreach (var droppedPlayer in droppedPlayers)
{
_players.TryRemove(droppedPlayer.PlayerId, out PlayerInfo player);

View file

@ -534,11 +534,14 @@
<Grid IsEnabled="{Binding Config.DiscordBotEnabled}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" MinHeight="25"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="Auto" MinHeight="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="60"/>
@ -565,6 +568,8 @@
<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}"/>
<Label Grid.Row="2" Grid.Column="6" Margin="1" Content="{DynamicResource GlobalSettings_DiscordBotLogLevelLabel}" VerticalAlignment="Center"/>
<ComboBox Name="DiscordBotLogLevelComboBox" Grid.Row="2" Grid.Column="7" Margin="1" ItemsSource="{Binding ElementName=GlobalSettings, Path=DiscordBotLogLevels}" SelectedValue="{Binding Config.DiscordBotLogLevel}" SelectedValuePath="ValueMember" DisplayMemberPath="DisplayMember" VerticalContentAlignment="Center" PreviewMouseWheel="ComboBox_PreviewMouseWheel"/>
<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}"/>
@ -573,6 +578,57 @@
<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}"/>
<GroupBox Grid.Row="5" Grid.Column="3" Grid.RowSpan="3" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" MinHeight="200" IsEnabled="{Binding Config.DiscordBotAllowAllBots, Converter={StaticResource InvertBooleanConverter}}">
<GroupBox.Header>
<StackPanel Orientation="Horizontal">
<Label Content="{DynamicResource GlobalSettings_DiscordBotWhitelistLabel}"/>
<Button Click="AddDiscordBotWhitelist_Click" Margin="20,0,0,0" ToolTip="{DynamicResource ServerSettings_AddDiscordBotWhitelistTooltip}" Style="{StaticResource ButtonStyle1}">
<Image Source="../Art/Add.ico"/>
</Button>
<Button Click="ClearDiscordBotWhitelists_Click" Margin="5,0,0,0" ToolTip="{DynamicResource ServerSettings_ClearDiscordBotWhitelistTooltip}" Style="{StaticResource ButtonStyle1}">
<Image Source="../Art/Delete.ico"/>
</Button>
</StackPanel>
</GroupBox.Header>
<DataGrid x:Name="DiscordBotWhitelistGrid" ItemsSource="{Binding DiscordBotWhitelist, ElementName=GlobalSettings}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="true" SelectionMode="Single" CanUserResizeColumns="False" CanUserResizeRows="False" RowHeaderWidth="25" IsReadOnly="False">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="{x:Static SystemColors.HighlightTextColor}"/>
</Style.Resources>
</Style>
</DataGrid.Resources>
<DataGrid.HorizontalGridLinesBrush>
<SolidColorBrush Color="#FFB4B4B4"/>
</DataGrid.HorizontalGridLinesBrush>
<DataGrid.VerticalGridLinesBrush>
<SolidColorBrush Color="#FFB4B4B4"/>
</DataGrid.VerticalGridLinesBrush>
<DataGrid.Columns>
<DataGridTextColumn Width="*" Binding="{Binding BotId}">
<DataGridTextColumn.Header>
<TextBlock Text="{DynamicResource GlobalSettings_DiscordBotWhitelistIdLabel}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTemplateColumn Width="30" CanUserReorder="False" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Width="22" Height="22" Margin="0" IsTabStop="False" HorizontalAlignment="Center" VerticalAlignment="Center" Click="RemoveDiscordBotWhitelist_Click" ToolTip="{DynamicResource ServerSettings_RemoveDiscordBotWhitelistTooltip}">
<Image Source="../Art/Delete.ico"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</GroupBox>
<CheckBox Grid.Row="6" Grid.Column="1" Margin="0,5,0,5" IsChecked="{Binding Config.DiscordBotAllowAllBots}" Content="{DynamicResource ServerSettings_DiscordBotAllowAllBotsLabel}" HorizontalAlignment="Left" ToolTip="{DynamicResource ServerSettings_DiscordBotAllowAllBotsTooltip}"/>
</Grid>
</GroupBox>

View file

@ -5,13 +5,16 @@ using ServerManagerTool.Common.Lib;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Xml;
using WPFSharp.Globalizer;
@ -24,11 +27,13 @@ namespace ServerManagerTool
public partial class GlobalSettingsControl : UserControl
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
public static readonly DependencyProperty AppInstanceProperty = DependencyProperty.Register(nameof(AppInstance), typeof(App), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty IsAdministratorProperty = DependencyProperty.Register(nameof(IsAdministrator), typeof(bool), typeof(GlobalSettingsControl), new PropertyMetadata(false));
public static readonly DependencyProperty WindowStatesProperty = DependencyProperty.Register(nameof(WindowStates), typeof(ComboBoxItemList), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty DiscordBotLogLevelsProperty = DependencyProperty.Register(nameof(DiscordBotLogLevels), typeof(ComboBoxItemList), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public static readonly DependencyProperty DiscordBotWhitelistProperty = DependencyProperty.Register(nameof(DiscordBotWhitelist), typeof(List<DiscordBotWhitelist>), typeof(GlobalSettingsControl), new PropertyMetadata(null));
public GlobalSettingsControl()
{
@ -38,11 +43,21 @@ namespace ServerManagerTool
this.IsAdministrator = SecurityUtils.IsAdministrator();
this.Version = GetDeployedVersion();
PopulateWindowsStatesComboBox();
InitializeComponent();
WindowUtils.RemoveDefaultResourceDictionary(this, Config.Default.DefaultGlobalizationFile);
PopulateWindowsStatesComboBox();
PopulateDiscordBotLogLevelsComboBox();
DiscordBotWhitelist = new List<DiscordBotWhitelist>();
if (Config.DiscordBotWhitelist != null)
{
foreach (var item in Config.DiscordBotWhitelist)
{
DiscordBotWhitelist.Add(new DiscordBotWhitelist() { BotId = item });
}
}
this.DataContext = this;
}
@ -82,6 +97,27 @@ namespace ServerManagerTool
set;
}
public ComboBoxItemList DiscordBotLogLevels
{
get { return (ComboBoxItemList)GetValue(DiscordBotLogLevelsProperty); }
set { SetValue(DiscordBotLogLevelsProperty, value); }
}
public List<DiscordBotWhitelist> DiscordBotWhitelist
{
get { return (List<DiscordBotWhitelist>)GetValue(DiscordBotWhitelistProperty); }
set { SetValue(DiscordBotWhitelistProperty, value); }
}
public void ApplyChangesToConfig()
{
if (Config.DiscordBotWhitelist is null)
Config.DiscordBotWhitelist = new System.Collections.Specialized.StringCollection();
Config.DiscordBotWhitelist.Clear();
Config.DiscordBotWhitelist.AddRange(DiscordBotWhitelist.Select(i => i.BotId).ToArray());
}
private string GetDeployedVersion()
{
XmlDocument xmlDoc = new XmlDocument();
@ -158,14 +194,24 @@ namespace ServerManagerTool
if (result == CommonFileDialogResult.Ok)
{
if (!String.Equals(dialog.FileName, Config.Default.DataPath))
if (!string.Equals(dialog.FileName, Config.Default.DataPath))
{
try
{
var newDataDirectory = dialog.FileName;
if (!string.IsNullOrWhiteSpace(newDataDirectory))
{
var root = Path.GetPathRoot(newDataDirectory);
if (!root.EndsWith("\\"))
{
newDataDirectory = newDataDirectory.Replace(root, root + "\\");
}
}
// Set up the destination directories
string newConfigDirectory = Path.Combine(dialog.FileName, Config.Default.ProfilesRelativePath);
string newConfigDirectory = Path.Combine(newDataDirectory, Config.Default.ProfilesRelativePath);
string oldSteamDirectory = Path.Combine(Config.Default.DataPath, CommonConfig.Default.SteamCmdRelativePath);
string newSteamDirectory = Path.Combine(dialog.FileName, CommonConfig.Default.SteamCmdRelativePath);
string newSteamDirectory = Path.Combine(newDataDirectory, CommonConfig.Default.SteamCmdRelativePath);
Directory.CreateDirectory(newConfigDirectory);
Directory.CreateDirectory(newSteamDirectory);
@ -199,7 +245,7 @@ namespace ServerManagerTool
Directory.Delete(oldSteamDirectory, true);
// Update the config
Config.Default.DataPath = dialog.FileName;
Config.Default.DataPath = newDataDirectory;
Config.Default.ConfigPath = newConfigDirectory;
App.ReconfigureLogging();
}
@ -238,9 +284,18 @@ namespace ServerManagerTool
if (result == CommonFileDialogResult.Ok)
{
if (!String.Equals(dialog.FileName, Config.Default.BackupPath))
if (!string.Equals(dialog.FileName, Config.Default.BackupPath))
{
Config.Default.BackupPath = dialog.FileName;
if (!string.IsNullOrWhiteSpace(Config.Default.BackupPath))
{
var root = Path.GetPathRoot(Config.Default.BackupPath);
if (!root.EndsWith("\\"))
{
Config.Default.BackupPath = Config.Default.BackupPath.Replace(root, root + "\\");
}
}
}
}
}
@ -260,9 +315,18 @@ namespace ServerManagerTool
if (result == CommonFileDialogResult.Ok)
{
if (!String.Equals(dialog.FileName, Config.Default.AutoUpdate_CacheDir))
if (!string.Equals(dialog.FileName, Config.Default.AutoUpdate_CacheDir))
{
Config.Default.AutoUpdate_CacheDir = dialog.FileName;
if (!string.IsNullOrWhiteSpace(Config.Default.AutoUpdate_CacheDir))
{
var root = Path.GetPathRoot(Config.Default.AutoUpdate_CacheDir);
if (!root.EndsWith("\\"))
{
Config.Default.AutoUpdate_CacheDir = Config.Default.AutoUpdate_CacheDir.Replace(root, root + "\\");
}
}
}
}
}
@ -443,5 +507,53 @@ namespace ServerManagerTool
this.WindowStateComboBox.SelectedValue = selectedValue;
}
}
private void PopulateDiscordBotLogLevelsComboBox()
{
var selectedValue = this.DiscordBotLogLevelComboBox?.SelectedValue ?? Config.DiscordBotLogLevel;
var comboBoxList = new ComboBoxItemList();
foreach (DiscordBot.Enums.LogLevel logLevel in Enum.GetValues(typeof(DiscordBot.Enums.LogLevel)))
{
var displayMember = _globalizer.GetResourceString($"DiscordBotLogLevel_{logLevel}") ?? logLevel.ToString();
comboBoxList.Add(new Common.Model.ComboBoxItem(logLevel.ToString(), displayMember));
}
this.DiscordBotLogLevels = comboBoxList;
if (this.DiscordBotLogLevelComboBox != null)
{
this.DiscordBotLogLevelComboBox.SelectedValue = selectedValue;
}
}
#region Discord Bot Whitelist
private void AddDiscordBotWhitelist_Click(object sender, RoutedEventArgs e)
{
DiscordBotWhitelist.Add(new DiscordBotWhitelist());
CollectionViewSource.GetDefaultView(DiscordBotWhitelistGrid.ItemsSource).Refresh();
}
private void ClearDiscordBotWhitelists_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show(_globalizer.GetResourceString("ServerSettings_ClearLabel"), _globalizer.GetResourceString("ServerSettings_ClearTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
return;
DiscordBotWhitelist.Clear();
CollectionViewSource.GetDefaultView(DiscordBotWhitelistGrid.ItemsSource).Refresh();
}
private void RemoveDiscordBotWhitelist_Click(object sender, RoutedEventArgs e)
{
if (MessageBox.Show(_globalizer.GetResourceString("ServerSettings_DeleteLabel"), _globalizer.GetResourceString("ServerSettings_DeleteTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
return;
var item = ((DiscordBotWhitelist)((Button)e.Source).DataContext);
DiscordBotWhitelist.Remove(item);
CollectionViewSource.GetDefaultView(DiscordBotWhitelistGrid.ItemsSource).Refresh();
}
#endregion
}
}

View file

@ -1093,6 +1093,9 @@
<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" />
<Label Grid.Row="0" Grid.Column="2" Content="{DynamicResource ServerSettings_DiscordAliasLabel}" ToolTip="{DynamicResource ServerSettings_DiscordAliasTooltip}" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="3" Margin="1" Text="{Binding DiscordAlias, Mode=TwoWay}" ToolTip="{DynamicResource ServerSettings_DiscordAliasTooltip}" 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}"/>

View file

@ -696,7 +696,7 @@ namespace ServerManagerTool
comment.AppendLine($"ServerUpdate_OnServerStart: {Config.Default.ServerUpdate_OnServerStart}");
comment.AppendLine($"DiscordBotEnabled: {Config.Default.DiscordBotEnabled}");
comment.AppendLine($"HasDiscordBotToken: {string.IsNullOrWhiteSpace(Config.Default.DiscordBotToken)}");
comment.AppendLine($"HasDiscordBotToken: {!string.IsNullOrWhiteSpace(Config.Default.DiscordBotToken)}");
comment.AppendLine($"DiscordBotServerId: {Config.Default.DiscordBotServerId}");
comment.AppendLine($"DiscordBotPrefix: {Config.Default.DiscordBotPrefix}");
comment.AppendLine($"AllowDiscordBackup: {Config.Default.AllowDiscordBackup}");
@ -720,7 +720,7 @@ namespace ServerManagerTool
var zipFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), this.Settings.ProfileID + ".zip");
if (File.Exists(zipFile)) File.Delete(zipFile);
ZipUtils.ZipFiles(zipFile, files.ToArray(), comment.ToString());
ZipUtils.ZipFiles(zipFile, files, comment.ToString());
foreach (var kvp in obfuscateFiles)
{
ZipUtils.ZipAFile(zipFile, kvp.Key, kvp.Value);
@ -1130,7 +1130,7 @@ namespace ServerManagerTool
Application.Current.Dispatcher.Invoke(() => this.Cursor = Cursors.Wait);
await Task.Delay(500);
Settings.LoadServerFileBlacklisted();
Settings.LoadServerFiles(true, false);
}
catch (Exception ex)
{
@ -1151,7 +1151,7 @@ namespace ServerManagerTool
Application.Current.Dispatcher.Invoke(() => this.Cursor = Cursors.Wait);
await Task.Delay(500);
Settings.LoadServerFileWhitelisted();
Settings.LoadServerFiles(false, true);
}
catch (Exception ex)
{

View file

@ -1,11 +1,11 @@
using QueryMaster;
using ServerManagerTool.Common.Extensions;
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;
@ -23,7 +23,7 @@ namespace ServerManagerTool.Utils
public static bool HasRunningCommands => _currentProfileCommands.Count > 0;
public static IList<string> HandleDiscordCommand(CommandType commandType, string serverId, string channelId, string profileId, CancellationToken token)
public static IList<string> HandleDiscordCommand(CommandType commandType, string serverId, string channelId, string profileIdOrAlias, CancellationToken token)
{
// check if incoming values are valid
if (string.IsNullOrWhiteSpace(serverId) || string.IsNullOrWhiteSpace(channelId))
@ -42,35 +42,35 @@ namespace ServerManagerTool.Utils
switch (commandType)
{
case CommandType.Info:
return GetServerInfo(channelId, profileId);
return GetServerInfo(channelId, profileIdOrAlias);
case CommandType.List:
return GetServerList(channelId);
case CommandType.Status:
return GetServerStatus(channelId, profileId);
return GetServerStatus(channelId, profileIdOrAlias);
case CommandType.Backup:
if (Config.Default.AllowDiscordBackup)
return BackupServer(channelId, profileId, token);
return BackupServer(channelId, profileIdOrAlias, 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 RestartServer(channelId, profileIdOrAlias, 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 ShutdownServer(channelId, profileIdOrAlias, 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 StopServer(channelId, profileIdOrAlias, 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 StartServer(channelId, profileIdOrAlias, 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 UpdateServer(channelId, profileIdOrAlias, token);
return new List<string> { string.Format(_globalizer.GetResourceString("DiscordBot_CommandNotEnabled"), commandType) };
default:
@ -93,19 +93,14 @@ namespace ServerManagerTool.Utils
return string.IsNullOrWhiteSpace(translationKey) ? string.Empty : _globalizer.GetResourceString(translationKey) ?? translationKey;
}
private static IList<string> GetServerInfo(string channelId, string profileId)
private static IList<string> GetServerInfo(string channelId, string profileIdOrAlias)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
try
{
@ -115,12 +110,29 @@ namespace ServerManagerTool.Utils
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Info);
switch (server.Runtime.Status)
{
@ -130,7 +142,7 @@ namespace ServerManagerTool.Utils
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
}
serverName = server.Profile.ServerName;
@ -155,7 +167,9 @@ namespace ServerManagerTool.Utils
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}```");
response.Add($"```{info.Name}\n" +
$"{_globalizer.GetResourceString("DiscordBot_MapLabel")} {mapName}\n" +
$"{_globalizer.GetResourceString("ServerSettings_PlayersLabel")} {info.Players} / {info.MaxPlayers}```");
}
}
}
@ -168,7 +182,7 @@ namespace ServerManagerTool.Utils
}
finally
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
@ -178,49 +192,55 @@ namespace ServerManagerTool.Utils
TaskUtils.RunOnUIThreadAsync(() =>
{
var serverList = ServerManager.Instance.Servers.Where(s => Equals(channelId, s.Profile.DiscordChannelId));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase));
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}```");
response.Add($"```{_globalizer.GetResourceString("ServerSettings_ProfileLabel")} {server.Profile.ProfileName}\n" +
$"{_globalizer.GetResourceString("ServerSettings_ProfileIdLabel")} {server.Profile.ProfileID}\n" +
(string.IsNullOrWhiteSpace(server.Profile.DiscordAlias) ? "" : $"{_globalizer.GetResourceString("ServerSettings_DiscordAliasLabel")} {server.Profile.DiscordAlias}\n") +
$"{_globalizer.GetResourceString("ServerSettings_ServerNameLabel")} {server.Profile.ServerName}```");
}
}).Wait();
return response;
}
private static IList<string> GetServerStatus(string channelId, string profileId)
private static IList<string> GetServerStatus(string channelId, string profileIdOrAlias)
{
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)));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.IsNullOrWhiteSpace(profileIdOrAlias)
|| string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
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}")}```");
response.Add($"```{_globalizer.GetResourceString("ServerSettings_ProfileLabel")} {server.Profile.ProfileName}\n" +
$"{_globalizer.GetResourceString("ServerSettings_ProfileIdLabel")} {server.Profile.ProfileID}\n" +
(string.IsNullOrWhiteSpace(server.Profile.DiscordAlias) ? "" : $"{_globalizer.GetResourceString("ServerSettings_DiscordAliasLabel")} {server.Profile.DiscordAlias}\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)
private static IList<string> BackupServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -229,18 +249,35 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordBackup)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Backup, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Backup, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Backup);
switch (server.Runtime.Status)
{
case ServerStatus.Initializing:
@ -248,7 +285,7 @@ namespace ServerManagerTool.Utils
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -267,7 +304,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -276,7 +315,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileBackup(profile, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_BackupRequested"), profile.ServerName));
@ -287,24 +326,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> RestartServer(string channelId, string profileId, CancellationToken token)
private static IList<string> RestartServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -313,28 +347,45 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordRestart)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Restart, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Restart, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Restart);
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));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -354,7 +405,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -363,7 +416,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, true, false, false, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_RestartRequested"), profile.ServerName));
@ -374,24 +427,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> ShutdownServer(string channelId, string profileId, CancellationToken token)
private static IList<string> ShutdownServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -400,18 +448,35 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordShutdown)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Shutdown, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Shutdown, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Shutdown);
switch (server.Runtime.Status)
{
case ServerStatus.Initializing:
@ -419,10 +484,10 @@ namespace ServerManagerTool.Utils
case ServerStatus.Stopped:
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -441,7 +506,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -450,7 +517,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, false, false, false, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_ShutdownRequested"), profile.ServerName));
@ -461,24 +528,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> StopServer(string channelId, string profileId, CancellationToken token)
private static IList<string> StopServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -487,18 +549,35 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordStop)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Stop, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Stop, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Stop);
switch (server.Runtime.Status)
{
case ServerStatus.Initializing:
@ -506,10 +585,10 @@ namespace ServerManagerTool.Utils
case ServerStatus.Stopped:
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -523,13 +602,15 @@ namespace ServerManagerTool.Utils
OutputLogs = false,
SendAlerts = true,
SendEmails = false,
ServerProcess = ServerProcessType.Shutdown,
ServerProcess = ServerProcessType.Stop,
ShutdownInterval = 0,
ServerStatusChangeCallback = (ServerStatus serverStatus) =>
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -538,7 +619,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, false, false, false, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_StopRequested"), profile.ServerName));
@ -549,24 +630,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> StartServer(string channelId, string profileId, CancellationToken token)
private static IList<string> StartServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
Task task = null;
@ -575,18 +651,35 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordStart)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Start, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Start, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Start);
switch (server.Runtime.Status)
{
case ServerStatus.Initializing:
@ -594,10 +687,10 @@ namespace ServerManagerTool.Utils
case ServerStatus.Running:
case ServerStatus.Uninstalled:
case ServerStatus.Unknown:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, server.Runtime.StatusString));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -617,7 +710,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -626,7 +721,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, true, false, false, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_StartRequested"), profile.ServerName));
@ -637,24 +732,19 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}
private static IList<string> UpdateServer(string channelId, string profileId, CancellationToken token)
private static IList<string> UpdateServer(string channelId, string profileIdOrAlias, CancellationToken token)
{
if (string.IsNullOrWhiteSpace(profileId))
if (string.IsNullOrWhiteSpace(profileIdOrAlias))
{
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);
var key = string.Empty;
ServerProfileSnapshot profile = null;
bool performRestart = false;
@ -664,31 +754,48 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var serverList = ServerManager.Instance.Servers.Where(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
if (server is null)
if (serverList.IsEmpty())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileIdOrAlias));
}
if (!serverList.HasOne())
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMultiples"), profileIdOrAlias));
}
var server = serverList.First();
if (!server.Profile.AllowDiscordUpdate)
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Update, profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandDisabledProfile"), CommandType.Update, server.Profile.ProfileName));
}
// check if another command is being run against the profile
if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID))
{
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName));
}
key = server.Profile.ProfileID;
_currentProfileCommands.Add(key, CommandType.Update);
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));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString));
case ServerStatus.Running:
performRestart = true;
break;
case ServerStatus.Updating:
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName));
}
profile = ServerProfileSnapshot.Create(server.Profile);
@ -707,7 +814,9 @@ namespace ServerManagerTool.Utils
{
TaskUtils.RunOnUIThreadAsync(() =>
{
var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
var server = ServerManager.Instance.Servers.First(s => string.Equals(channelId, s.Profile.DiscordChannelId, StringComparison.OrdinalIgnoreCase)
&& (string.Equals(profileIdOrAlias, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(s.Profile.DiscordAlias) && string.Equals(profileIdOrAlias, s.Profile.DiscordAlias, StringComparison.OrdinalIgnoreCase)));
server.Runtime.UpdateServerStatus(serverStatus, true);
}).Wait();
}
@ -716,7 +825,7 @@ namespace ServerManagerTool.Utils
task = Task.Run(() =>
{
app.PerformProfileShutdown(profile, performRestart, true, false, false, token);
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
});
response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_UpdateRequested"), profile.ServerName));
@ -727,7 +836,7 @@ namespace ServerManagerTool.Utils
{
if (task is null)
{
_currentProfileCommands.Remove(profileId);
_currentProfileCommands.Remove(key);
}
}
}

View file

@ -86,7 +86,7 @@ namespace ServerManagerTool.Utils
Directory.CreateDirectory(modRootFolder);
// get the a list of the mod file into include in the mod file
var modFileItems = modIdList.Select(m => $"{m}.pak").ToArray();
var modFileItems = modIdList.Select(m => $"{m}.pak");
// create the mod file.
File.WriteAllLines(modListFile, modFileItems);
}

View file

@ -5,7 +5,67 @@
<title>Conan Server Manager Version Feed</title>
<subtitle>This is the Conan Server Manager release version feed.</subtitle>
<link href="http://servermanagers.freeforums.net/" />
<updated>2021-12-12T00:00:00Z</updated>
<updated>2021-12-16T00:00:00Z</updated>
<entry>
<id>urn:uuid:19B09A66-43F2-4D5F-AF33-5C77D7EA9A6B</id>
<title>1.1.58 (1.1.58.8)</title>
<summary>1.1.58.8</summary>
<link href="" />
<updated>2021-12-16T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">NEW</u>
<br/>
<ul>
<li>Main Window - Added Discord Bot Status and a button to Stop/Start the discord bot.</li>
<li>Global Settings - Discord Bot section - Added a log level droplist.</li>
<li>Global Settings - Discord Bot section - Added a checkbox to allow all bots.</li>
<li>Global Settings - Discord Bot section - Added a whitelist to allow bots to send commands to the server manager.</li>
<li>Server Settings - Discord Bot section - Added an alias that can be used with the discord command instead of the profile id.</li>
</ul>
<u style="font-size: .9em;">CHANGE</u>
<br/>
<ul>
<li>Discord Bot - all commands are now case INsensitive, along with the profile id and the alias.</li>
<li>Discord Bot - removed the mandatory requirement to enter the '!' after the discord prefix. The '!' has been added to the existing prefix so no change to existing functionality, but you can now change it.</li>
<li>Made changes to the code to help improve performance.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:6383E79A-C31F-462B-9730-B26B28DC5EFF</id>
<title>1.1.57 (1.1.57.3)</title>
<summary>1.1.57.3</summary>
<link href="" />
<updated>2021-12-15T00:00:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
<p>
<u style="font-size: .9em;">BUGFIX</u>
<br/>
<ul>
<li>Fixed a bug with the Server Shutdown when the CheckForOnlinePlayers option not selected.</li>
<li>Fixed a bug when the backup path was a root directory that caused a 'Invalid URI: A Dos path must be rooted' crash.</li>
<li>Added additional validation when setting directories in the global setting, to ensure they are rooted correctly.</li>
<li>Fixed a bug when starting the server manager and it tries to download steamcmd, but fails as steamcmd is unavailable for download.</li>
</ul>
</p>
</div>
</content>
<author>
<name>bletch</name>
<email>bletch1971@hotmail.com</email>
</author>
</entry>
<entry>
<id>urn:uuid:F8A08616-749B-48E7-87D5-D97E86AB3926</id>

Some files were not shown because too many files have changed in this diff Show more