source code checkin
557
src/ConanServerManager/App.config
Normal file
|
|
@ -0,0 +1,557 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
|
||||
<configSections>
|
||||
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="ServerManagerTool.Common.CommonConfig" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
|
||||
<section name="ServerManagerTool.Config" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
|
||||
</sectionGroup>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="ServerManagerTool.Config" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
|
||||
</startup>
|
||||
|
||||
<applicationSettings>
|
||||
<ServerManagerTool.Config>
|
||||
<setting name="SteamCmdInstallServerArgsFormat" serializeAs="String">
|
||||
<value>+login {0} +force_install_dir "{1}" "+app_update {2} {3} {4}" +quit</value>
|
||||
</setting>
|
||||
<setting name="ServersInstallPath" serializeAs="String">
|
||||
<value>Servers</value>
|
||||
</setting>
|
||||
<setting name="DefaultServerProfileName" serializeAs="String">
|
||||
<value>Unnamed Profile</value>
|
||||
</setting>
|
||||
<setting name="DefaultServerName" serializeAs="String">
|
||||
<value>Unnamed Server</value>
|
||||
</setting>
|
||||
<setting name="ServerBinaryRelativePath" serializeAs="String">
|
||||
<value>ConanSandbox\Binaries\Win64</value>
|
||||
</setting>
|
||||
<setting name="ServerConfigRelativePath" serializeAs="String">
|
||||
<value>ConanSandbox\Saved\Config\WindowsServer</value>
|
||||
</setting>
|
||||
<setting name="ServerExeFile" serializeAs="String">
|
||||
<value>ConanSandboxServer-Win64-Test.exe</value>
|
||||
</setting>
|
||||
<setting name="ProfilesRelativePath" serializeAs="String">
|
||||
<value>profiles</value>
|
||||
</setting>
|
||||
<setting name="ProfileExtension" serializeAs="String">
|
||||
<value>.profile</value>
|
||||
</setting>
|
||||
<setting name="ServerProcessName" serializeAs="String">
|
||||
<value>ConanSandboxServer-Win64-Test</value>
|
||||
</setting>
|
||||
<setting name="LoadProfileExtensionList" serializeAs="String">
|
||||
<value>*.profile,*.ini</value>
|
||||
</setting>
|
||||
<setting name="LogsRelativePath" serializeAs="String">
|
||||
<value>Logs</value>
|
||||
</setting>
|
||||
<setting name="LatestServerManagerVersionUrl" serializeAs="String">
|
||||
<value>https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/latest.txt</value>
|
||||
</setting>
|
||||
<setting name="UpdateCheckTime" serializeAs="String">
|
||||
<value>1440</value>
|
||||
</setting>
|
||||
<setting name="SavedFilesRelativePath" serializeAs="String">
|
||||
<value>ConanSandbox\Saved</value>
|
||||
</setting>
|
||||
<setting name="HelpUrl" serializeAs="String">
|
||||
<value>http://servermanagers.freeforums.net/thread/43/faq-frequently-asked</value>
|
||||
</setting>
|
||||
<setting name="AppPatchNotesUrl" serializeAs="String">
|
||||
<value>https://forums.funcom.com/c/conan-exiles/Patch-Notes</value>
|
||||
</setting>
|
||||
<setting name="AppUrl" serializeAs="String">
|
||||
<value>http://store.steampowered.com/app/440900/</value>
|
||||
</setting>
|
||||
<setting name="LastUpdatedTimeFile" serializeAs="String">
|
||||
<value>LastUpdatedSM.txt</value>
|
||||
</setting>
|
||||
<setting name="LauncherFile" serializeAs="String">
|
||||
<value>RunServer.cmd</value>
|
||||
</setting>
|
||||
<setting name="SteamCmdInstallModArgsFormat" serializeAs="String">
|
||||
<value>+login {0} +workshop_download_item {1} {2} +quit</value>
|
||||
</setting>
|
||||
<setting name="AppSteamWorkshopFolderRelativePath" serializeAs="String">
|
||||
<value>steamapps\workshop\content\440900\</value>
|
||||
</setting>
|
||||
<setting name="ServerModsRelativePath" serializeAs="String">
|
||||
<value>ConanSandbox\Mods</value>
|
||||
</setting>
|
||||
<setting name="SavedRelativePath" serializeAs="String">
|
||||
<value>Saved</value>
|
||||
</setting>
|
||||
<setting name="WorkshopCacheFile" serializeAs="String">
|
||||
<value>workshopcache_440900.json</value>
|
||||
</setting>
|
||||
<setting name="SteamCmd_AnonymousUsername" serializeAs="String">
|
||||
<value>anonymous</value>
|
||||
</setting>
|
||||
<setting name="SteamWorkshopFolderRelativePath" serializeAs="String">
|
||||
<value>steamapps\workshop</value>
|
||||
</setting>
|
||||
<setting name="AppSteamWorkshopFile" serializeAs="String">
|
||||
<value>appworkshop_440900.acf</value>
|
||||
</setting>
|
||||
<setting name="AppId" serializeAs="String">
|
||||
<value>440900</value>
|
||||
</setting>
|
||||
<setting name="AppIdServer" serializeAs="String">
|
||||
<value>443030</value>
|
||||
</setting>
|
||||
<setting name="ServerAppIdFile" serializeAs="String">
|
||||
<value>steam_appid.txt</value>
|
||||
</setting>
|
||||
<setting name="LatestServerManagerBetaVersionUrl" serializeAs="String">
|
||||
<value>https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/beta/latest.txt</value>
|
||||
</setting>
|
||||
<setting name="LatestServerManagerBetaDownloadUrl" serializeAs="String">
|
||||
<value>https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/beta/latest.zip</value>
|
||||
</setting>
|
||||
<setting name="LatestServerManagerDownloadUrl" serializeAs="String">
|
||||
<value>https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/latest.zip</value>
|
||||
</setting>
|
||||
<setting name="LatestServerManagerPatchNotesUrl" serializeAs="String">
|
||||
<value>http://servermanagers.freeforums.net/thread/36/downloads</value>
|
||||
</setting>
|
||||
<setting name="LatestServerManagerBetaPatchNotesUrl" serializeAs="String">
|
||||
<value>http://servermanagers.freeforums.net/board/44/beta-testers</value>
|
||||
</setting>
|
||||
<setting name="ServerBlacklistFile" serializeAs="String">
|
||||
<value>blacklist.txt</value>
|
||||
</setting>
|
||||
<setting name="DefaultServerRelativePath" serializeAs="String">
|
||||
<value>server</value>
|
||||
</setting>
|
||||
<setting name="ServerStatusUrlFormat" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="BackupRelativePath" serializeAs="String">
|
||||
<value>_backup_</value>
|
||||
</setting>
|
||||
<setting name="ServerGameConfigFile" serializeAs="String">
|
||||
<value>Game.ini</value>
|
||||
</setting>
|
||||
<setting name="SteamWebAPIKeyHelpUrl" serializeAs="String">
|
||||
<value>http://servermanagers.freeforums.net/thread/40/get-own-steam-web-api</value>
|
||||
</setting>
|
||||
<setting name="BackupServerExtension" serializeAs="String">
|
||||
<value>.smbak</value>
|
||||
</setting>
|
||||
<setting name="ScheduledTasksCheckTime" serializeAs="String">
|
||||
<value>1</value>
|
||||
</setting>
|
||||
<setting name="ServerManagerPluginUrl" serializeAs="String">
|
||||
<value>http://servermanagers.freeforums.net/board/36/plugins</value>
|
||||
</setting>
|
||||
<setting name="ServerManagerForumUrl" serializeAs="String">
|
||||
<value>http://servermanagers.freeforums.net/</value>
|
||||
</setting>
|
||||
<setting name="DefaultGlobalizationFile" serializeAs="String">
|
||||
<value>Globalization\en-US\en-US.xaml</value>
|
||||
</setting>
|
||||
<setting name="ScheduledTaskFolder" serializeAs="String">
|
||||
<value>ConanServerManager</value>
|
||||
</setting>
|
||||
<setting name="FirewallRulePrefix" serializeAs="String">
|
||||
<value>ConanServer:</value>
|
||||
</setting>
|
||||
<setting name="DonationUrl" serializeAs="String">
|
||||
<value>https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=bletch1971%40hotmail%2ecom&lc=US&item_name=Server%20Manager&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted</value>
|
||||
</setting>
|
||||
<setting name="ServerManagerCode" serializeAs="String">
|
||||
<value>F2653C3D-BC83-440A-AD99-FD9D9466DE04</value>
|
||||
</setting>
|
||||
<setting name="BackupExtension" serializeAs="String">
|
||||
<value>.zip</value>
|
||||
</setting>
|
||||
<setting name="UpdaterPrefix" serializeAs="String">
|
||||
<value>Conan_</value>
|
||||
</setting>
|
||||
<setting name="UpdaterFile" serializeAs="String">
|
||||
<value>ServerManagerUpdater.exe</value>
|
||||
</setting>
|
||||
<setting name="ServerCommandLineArgsIPMatchFormat" serializeAs="String">
|
||||
<value>-MultiHome={0}</value>
|
||||
</setting>
|
||||
<setting name="ServerCommandLineArgsPortMatchFormat" serializeAs="String">
|
||||
<value>-QueryPort={0}</value>
|
||||
</setting>
|
||||
<setting name="GameDataRelativePath" serializeAs="String">
|
||||
<value>GameData</value>
|
||||
</setting>
|
||||
<setting name="GameDataExtension" serializeAs="String">
|
||||
<value>.gamedata</value>
|
||||
</setting>
|
||||
<setting name="GameDataApplication" serializeAs="String">
|
||||
<value>conan</value>
|
||||
</setting>
|
||||
<setting name="ServerManagerVersionFeedUrl" serializeAs="String">
|
||||
<value>https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/VersionFeed.xml</value>
|
||||
</setting>
|
||||
<setting name="ServerManagerVersionBetaFeedUrl" serializeAs="String">
|
||||
<value>https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/beta/VersionFeed.xml</value>
|
||||
</setting>
|
||||
<setting name="DefaultServerBranchName" serializeAs="String">
|
||||
<value>live</value>
|
||||
</setting>
|
||||
<setting name="SteamCmdInstallServerBetaNameArgsFormat" serializeAs="String">
|
||||
<value>-beta {0}</value>
|
||||
</setting>
|
||||
<setting name="SteamCmdInstallServerBetaPasswordArgsFormat" serializeAs="String">
|
||||
<value>-betapassword {0}</value>
|
||||
</setting>
|
||||
<setting name="ServerBranchFolderPrefix" serializeAs="String">
|
||||
<value>__</value>
|
||||
</setting>
|
||||
<setting name="AppSteamManifestFile" serializeAs="String">
|
||||
<value>appmanifest_443030.acf</value>
|
||||
</setting>
|
||||
<setting name="SteamManifestFolderRelativePath" serializeAs="String">
|
||||
<value>steamapps</value>
|
||||
</setting>
|
||||
<setting name="ServerEngineConfigFile" serializeAs="String">
|
||||
<value>Engine.ini</value>
|
||||
</setting>
|
||||
<setting name="ServerSettingsConfigFile" serializeAs="String">
|
||||
<value>ServerSettings.ini</value>
|
||||
</setting>
|
||||
<setting name="SendMessageDelay" serializeAs="String">
|
||||
<value>5000</value>
|
||||
</setting>
|
||||
<setting name="PlayerImageFileExtension" serializeAs="String">
|
||||
<value>.png</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdownCommand" serializeAs="String">
|
||||
<value>doexit</value>
|
||||
</setting>
|
||||
<setting name="ServerSaveCommand" serializeAs="String">
|
||||
<value>saveworld</value>
|
||||
</setting>
|
||||
<setting name="DefaultStyleFile" serializeAs="String">
|
||||
<value>Styles\Default.xaml</value>
|
||||
</setting>
|
||||
<setting name="ServerWhitelistFile" serializeAs="String">
|
||||
<value>whitelist.txt</value>
|
||||
</setting>
|
||||
<setting name="ServerCommandLineStandardArgs" serializeAs="String">
|
||||
<value>-listen -nosteamclient -game -server -log</value>
|
||||
</setting>
|
||||
<setting name="GameDataUrl" serializeAs="String">
|
||||
<value>https://servermanagers.freeforums.net/</value>
|
||||
</setting>
|
||||
<setting name="ServerStatusWatcher_LocalStatusQueryDelay" serializeAs="String">
|
||||
<value>15000</value>
|
||||
</setting>
|
||||
<setting name="ServerStatusWatcher_RemoteStatusQueryDelay" serializeAs="String">
|
||||
<value>120000</value>
|
||||
</setting>
|
||||
</ServerManagerTool.Config>
|
||||
<ServerManagerTool.Common.CommonConfig>
|
||||
<setting name="DefaultSteamAPIKey" serializeAs="String">
|
||||
<value>2043D84BBC372F2F47D9AF937129D9C2</value>
|
||||
</setting>
|
||||
</ServerManagerTool.Common.CommonConfig>
|
||||
</applicationSettings>
|
||||
|
||||
<userSettings>
|
||||
<ServerManagerTool.Config>
|
||||
<setting name="ConfigPath" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="DataPath" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="MachinePublicIP" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="ManageFirewallAutomatically" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="UpgradeConfig" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="CultureName" serializeAs="String">
|
||||
<value>en-US</value>
|
||||
</setting>
|
||||
<setting name="SectionAdministrationIsExpanded" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="SectionAutomaticManagementIsExpanded" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="RunAsAdministratorPrompt" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_EnableUpdate" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_UpdatePeriod" serializeAs="String">
|
||||
<value>60</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_GracePeriod" serializeAs="String">
|
||||
<value>15</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_GraceMessage1" serializeAs="String">
|
||||
<value>Server shutdown required. Server will shutdown in {minutes} minutes. Please logout before shutdown to prevent character corruption.</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_GraceMessage2" serializeAs="String">
|
||||
<value>Server shutdown required. Server will shutdown in 1 minute. Please logout before shutdown to prevent character corruption.</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_GraceMessage3" serializeAs="String">
|
||||
<value>Server shutdown required. Server is shutting down now.</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_WorldSaveMessage" serializeAs="String">
|
||||
<value>Server shutdown required. Server is about to shutdown, performing a world save.</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_EnableWorldSave" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_CacheDir" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="ServerUpdate_UpdateModsWhenUpdatingServer" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="ServerUpdate_ForceUpdateMods" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="ServerUpdate_ForceCopyMods" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="SteamCmdRedirectOutput" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_UseSmartCopy" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="StyleName" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="Email_Host" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="Email_Port" serializeAs="String">
|
||||
<value>25</value>
|
||||
</setting>
|
||||
<setting name="Email_UseSSL" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="Email_UseDetaultCredentials" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="Email_Username" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="Email_Password" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="Email_From" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="Email_To" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="EmailNotify_AutoUpdate" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="EmailNotify_AutoRestart" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="SteamCmd_Username" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="SteamCmd_UseAnonymousCredentials" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="SteamCmd_Password" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="ValidateProfileOnServerStart" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="ServerUpdate_OnServerStart" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="SectionServerFilesIsExpanded" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="EmailNotify_ShutdownRestart" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="WorkshopCache_ExpiredHours" serializeAs="String">
|
||||
<value>168</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_CancelMessage" serializeAs="String">
|
||||
<value>Server shutdown has been cancelled.</value>
|
||||
</setting>
|
||||
<setting name="ServerUpdate_ForceUpdateModsIfNoSteamInfo" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoBackup_EnableBackup" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="AutoBackup_BackupPeriod" serializeAs="String">
|
||||
<value>60</value>
|
||||
</setting>
|
||||
<setting name="EmailNotify_AutoBackup" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="AutoBackup_DeleteOldFiles" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoBackup_DeleteInterval" serializeAs="String">
|
||||
<value>30</value>
|
||||
</setting>
|
||||
<setting name="ServerBackup_WorldSaveMessage" serializeAs="String">
|
||||
<value>A world save is about to be performed, you may experience some lag during this process. Please be patient.</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_RetryOnFail" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_ShowUpdateReason" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_ValidateServerFiles" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_OverrideServerStartup" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="ServerManagerUniqueKey" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="AutoUpdate_ParallelUpdate" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_UpdateReasonPrefix" serializeAs="String">
|
||||
<value>Server Update Reason:</value>
|
||||
</setting>
|
||||
<setting name="Alert_ServerStopMessage" serializeAs="String">
|
||||
<value>The server is stopping.</value>
|
||||
</setting>
|
||||
<setting name="Alert_ServerShutdownMessage" serializeAs="String">
|
||||
<value>The server is shutting down.</value>
|
||||
</setting>
|
||||
<setting name="Alert_ServerStartedMessage" serializeAs="String">
|
||||
<value>The server is starting.</value>
|
||||
</setting>
|
||||
<setting name="Alert_BackupProcessError" serializeAs="String">
|
||||
<value>The server backup process was performed but an error occurred.</value>
|
||||
</setting>
|
||||
<setting name="Alert_ShutdownProcessError" serializeAs="String">
|
||||
<value>The server shutdown process was performed but an error occurred.</value>
|
||||
</setting>
|
||||
<setting name="Alert_RestartProcessError" serializeAs="String">
|
||||
<value>The server restart process was performed but an error occurred.</value>
|
||||
</setting>
|
||||
<setting name="Alert_UpdateProcessError" serializeAs="String">
|
||||
<value>The server update process was performed but an error occurred.</value>
|
||||
</setting>
|
||||
<setting name="Alert_ModUpdateDetected" serializeAs="String">
|
||||
<value>Mod updates have been detected:</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_WorldSaveDelay" serializeAs="String">
|
||||
<value>10</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_UseShutdownCommand" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="Alert_ServerStatusChange" serializeAs="String">
|
||||
<value>Server Status:</value>
|
||||
</setting>
|
||||
<setting name="Alert_ServerUpdate" serializeAs="String">
|
||||
<value>Game Server Update</value>
|
||||
</setting>
|
||||
<setting name="Alert_UpdateResults" serializeAs="String">
|
||||
<value>Update performed, includes:</value>
|
||||
</setting>
|
||||
<setting name="BackupPath" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="ServerShutdown_AllMessagesShowReason" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CloseShutdownWindowWhenFinished" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="ServerModListFile" serializeAs="String">
|
||||
<value>modlist.txt</value>
|
||||
</setting>
|
||||
<setting name="RCON_PlayerListFilter" serializeAs="String">
|
||||
<value>19</value>
|
||||
</setting>
|
||||
<setting name="RCON_PlayerListSort" serializeAs="String">
|
||||
<value>1</value>
|
||||
</setting>
|
||||
<setting name="PlayerListFilter" serializeAs="String">
|
||||
<value>19</value>
|
||||
</setting>
|
||||
<setting name="PlayerListSort" serializeAs="String">
|
||||
<value>1</value>
|
||||
</setting>
|
||||
<setting name="ServerStatus_EnableActions" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="ServerStatus_ShowActionConfirmation" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_SequencialDelayPeriod" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="BackupWorldFile" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="MainWindow_Width" serializeAs="String">
|
||||
<value>1100</value>
|
||||
</setting>
|
||||
<setting name="MainWindow_Height" serializeAs="String">
|
||||
<value>900</value>
|
||||
</setting>
|
||||
<setting name="ServerMonitorWindow_Width" serializeAs="String">
|
||||
<value>900</value>
|
||||
</setting>
|
||||
<setting name="ServerMonitorWindow_Height" serializeAs="String">
|
||||
<value>500</value>
|
||||
</setting>
|
||||
<setting name="UpdateDirectoryPermissions" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoUpdate_VerifyServerAfterUpdate" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_CheckForOnlinePlayers" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="ServerShutdown_SendShutdownMessages" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoRestart_EnabledGracePeriod" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="AutoRestart_GracePeriod" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="MainWindow_MinimizeToTray" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="ServerMonitorMessageOutput_Height" serializeAs="String">
|
||||
<value>100</value>
|
||||
</setting>
|
||||
<setting name="Alert_ServerStartedMessageIncludeIPandPort" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="ManagePublicIPAutomatically" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
</ServerManagerTool.Config>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
7
src/ConanServerManager/App.xaml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<globalizer:GlobalizedApplication
|
||||
x:Class="ServerManagerTool.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:globalizer="clr-namespace:WPFSharp.Globalizer;assembly=WPFSharp.Globalizer"
|
||||
StartupUri="Windows/AutoUpdateWindow.xaml">
|
||||
</globalizer:GlobalizedApplication>
|
||||
530
src/ConanServerManager/App.xaml.cs
Normal file
|
|
@ -0,0 +1,530 @@
|
|||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using NLog;
|
||||
using NLog.Config;
|
||||
using NLog.Targets;
|
||||
using ServerManagerTool.Common;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib;
|
||||
using ServerManagerTool.Plugin.Common;
|
||||
using ServerManagerTool.Windows;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : GlobalizedApplication, INotifyPropertyChanged
|
||||
{
|
||||
public new static App Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private GlobalizedApplication _globalizer;
|
||||
private bool _applicationStarted;
|
||||
private string _args;
|
||||
private bool _betaVersion;
|
||||
private string _title;
|
||||
private string _version;
|
||||
|
||||
public App()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Config.Default.ServerManagerUniqueKey))
|
||||
Config.Default.ServerManagerUniqueKey = Guid.NewGuid().ToString();
|
||||
|
||||
App.Instance = this;
|
||||
ApplicationStarted = false;
|
||||
Args = string.Empty;
|
||||
BetaVersion = false;
|
||||
Title = string.Empty;
|
||||
Version = AppUtils.GetDeployedVersion(Assembly.GetEntryAssembly());
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += ErrorHandling.CurrentDomain_UnhandledException;
|
||||
|
||||
MigrateSettings();
|
||||
ReconfigureLogging();
|
||||
}
|
||||
|
||||
public bool ApplicationStarted
|
||||
{
|
||||
get
|
||||
{
|
||||
return _applicationStarted;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!Equals(value, _applicationStarted))
|
||||
{
|
||||
_applicationStarted = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Args
|
||||
{
|
||||
get
|
||||
{
|
||||
return _args;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!Equals(value, _args))
|
||||
{
|
||||
_args = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool BetaVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return _betaVersion;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!Equals(value, _betaVersion))
|
||||
{
|
||||
_betaVersion = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!Equals(value, _title))
|
||||
{
|
||||
_title = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return _version;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!Equals(value, _version))
|
||||
{
|
||||
_version = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DiscoverMachinePublicIP(bool forceOverride)
|
||||
{
|
||||
if (forceOverride || string.IsNullOrWhiteSpace(Config.Default.MachinePublicIP))
|
||||
{
|
||||
var publicIP = NetworkUtils.DiscoverPublicIP();
|
||||
if (string.IsNullOrWhiteSpace(publicIP))
|
||||
return;
|
||||
|
||||
if (!Config.Default.MachinePublicIP.Equals(publicIP, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Config.Default.MachinePublicIP = publicIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task DiscoverMachinePublicIPAsync(bool forceOverride)
|
||||
{
|
||||
if (forceOverride || string.IsNullOrWhiteSpace(Config.Default.MachinePublicIP))
|
||||
{
|
||||
var publicIP = await NetworkUtils.DiscoverPublicIPAsync();
|
||||
if (string.IsNullOrWhiteSpace(publicIP))
|
||||
return;
|
||||
|
||||
if (!Config.Default.MachinePublicIP.Equals(publicIP, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await App.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
Config.Default.MachinePublicIP = publicIP;
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IList<Plugin.Common.Lib.Profile> FetchProfiles()
|
||||
{
|
||||
return ServerManager.Instance.Servers.Select(s => new ServerManagerTool.Plugin.Common.Lib.Profile() { ProfileName = s?.Profile?.ProfileName ?? string.Empty, InstallationFolder = s?.Profile?.InstallDirectory ?? string.Empty }).ToList();
|
||||
}
|
||||
|
||||
public static string GetLogFolder() => IOUtils.NormalizePath(Path.Combine(Config.Default.DataPath, Config.Default.LogsRelativePath));
|
||||
|
||||
public static string GetProfileLogFolder(string profileId) => IOUtils.NormalizePath(Path.Combine(Config.Default.DataPath, Config.Default.LogsRelativePath, profileId.ToLower()));
|
||||
|
||||
public static Logger GetProfileLogger(string profileId, string name, LogLevel minLevel, LogLevel maxLevel)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId) || string.IsNullOrWhiteSpace(name))
|
||||
return null;
|
||||
|
||||
var loggerName = $"{profileId.ToLower()}_{name}".Replace(" ", "_");
|
||||
|
||||
if (LogManager.Configuration.FindTargetByName(loggerName) == null)
|
||||
{
|
||||
var logFilePath = GetProfileLogFolder(profileId);
|
||||
if (!System.IO.Directory.Exists(logFilePath))
|
||||
System.IO.Directory.CreateDirectory(logFilePath);
|
||||
|
||||
var logFile = new FileTarget(loggerName)
|
||||
{
|
||||
FileName = Path.Combine(logFilePath, $"{name}.log"),
|
||||
Layout = "${time} ${message}",
|
||||
ArchiveFileName = Path.Combine(logFilePath, $"{name}.{{#}}.log"),
|
||||
ArchiveNumbering = ArchiveNumberingMode.DateAndSequence,
|
||||
ArchiveEvery = FileArchivePeriod.Day,
|
||||
ArchiveDateFormat = "yyyyMMdd"
|
||||
};
|
||||
LogManager.Configuration.AddTarget(loggerName, logFile);
|
||||
|
||||
var rule = new LoggingRule(loggerName, minLevel, maxLevel, logFile);
|
||||
LogManager.Configuration.LoggingRules.Add(rule);
|
||||
LogManager.ReconfigExistingLoggers();
|
||||
}
|
||||
|
||||
return LogManager.GetLogger(loggerName);
|
||||
}
|
||||
|
||||
private static void MigrateSettings()
|
||||
{
|
||||
var installFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
//
|
||||
// Migrate settings when we update.
|
||||
//
|
||||
if (CommonConfig.Default.UpgradeConfig)
|
||||
{
|
||||
var settingsFile = IOUtils.NormalizePath(Path.Combine(installFolder, "commonconfig.json"));
|
||||
|
||||
CommonConfig.Default.Upgrade();
|
||||
CommonConfig.Default.Reload();
|
||||
SettingsUtils.MigrateSettings(CommonConfig.Default, settingsFile);
|
||||
CommonConfig.Default.UpgradeConfig = false;
|
||||
CommonConfig.Default.Save();
|
||||
}
|
||||
if (Config.Default.UpgradeConfig)
|
||||
{
|
||||
var settingsFile = IOUtils.NormalizePath(Path.Combine(installFolder, "userconfig.json"));
|
||||
|
||||
Config.Default.Upgrade();
|
||||
Config.Default.Reload();
|
||||
SettingsUtils.MigrateSettings(Config.Default, settingsFile);
|
||||
Config.Default.UpgradeConfig = false;
|
||||
Config.Default.Save();
|
||||
}
|
||||
|
||||
Config.Default.SteamCmdRedirectOutput = false;
|
||||
}
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
|
||||
|
||||
_globalizer = GlobalizedApplication.Instance;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.CultureName))
|
||||
_globalizer.GlobalizationManager.SwitchLanguage(Config.Default.CultureName, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// just output the exception message, it should default back to the fallback language.
|
||||
Debug.WriteLine(ex.Message);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.StyleName))
|
||||
_globalizer.StyleManager.SwitchStyle(Config.Default.StyleName, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// just output the exception message, it should default back to the fallback style.
|
||||
Debug.WriteLine(ex.Message);
|
||||
}
|
||||
|
||||
TaskSchedulerUtils.TaskFolder = Config.Default.ScheduledTaskFolder;
|
||||
|
||||
this.Args = string.Join(" ", e.Args);
|
||||
|
||||
// check if we are starting server manager in BETA/TEST mode
|
||||
if (e.Args.Any(a => a.Equals(Constants.ARG_BETA, StringComparison.OrdinalIgnoreCase) || a.Equals(Constants.ARG_TEST, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
this.BetaVersion = true;
|
||||
}
|
||||
|
||||
// check if we need to set the title
|
||||
if (e.Args.Any(a => a.Equals(Constants.ARG_TITLE, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
for (int i = 0; i < e.Args.Length - 1; i++)
|
||||
{
|
||||
if (e.Args[i].Equals(Constants.ARG_TITLE, StringComparison.OrdinalIgnoreCase) && i < e.Args.Length - 1 && !e.Args[i + 1].StartsWith("-"))
|
||||
{
|
||||
Title = e.Args[i + 1].Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check and update the public IP address
|
||||
DiscoverMachinePublicIP(Config.Default.ManagePublicIPAutomatically);
|
||||
|
||||
var installPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
PluginHelper.Instance.BetaEnabled = this.BetaVersion;
|
||||
PluginHelper.Instance.LoadPlugins(installPath, true);
|
||||
PluginHelper.Instance.SetFetchProfileCallback(FetchProfiles);
|
||||
|
||||
// check if we are starting server manager for server shutdown
|
||||
if (e.Args.Any(a => a.StartsWith(Constants.ARG_AUTOSHUTDOWN1, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var arg = e.Args.FirstOrDefault(a => a.StartsWith(Constants.ARG_AUTOSHUTDOWN1, StringComparison.OrdinalIgnoreCase));
|
||||
var exitCode = ServerApp.PerformAutoShutdown(arg, ServerProcessType.AutoShutdown1);
|
||||
|
||||
// once we are finished, just exit
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
|
||||
// check if we are starting server manager for server shutdown
|
||||
if (e.Args.Any(a => a.StartsWith(Constants.ARG_AUTOSHUTDOWN2, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var arg = e.Args.FirstOrDefault(a => a.StartsWith(Constants.ARG_AUTOSHUTDOWN2, StringComparison.OrdinalIgnoreCase));
|
||||
var exitCode = ServerApp.PerformAutoShutdown(arg, ServerProcessType.AutoShutdown2);
|
||||
|
||||
// once we are finished, just exit
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
|
||||
// check if we are starting server manager for server updating
|
||||
if (e.Args.Any(a => a.Equals(Constants.ARG_AUTOUPDATE, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var exitCode = ServerApp.PerformAutoUpdate();
|
||||
|
||||
// once we are finished, just exit
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
|
||||
// check if we are starting server manager for server backups
|
||||
if (e.Args.Any(a => a.Equals(Constants.ARG_AUTOBACKUP, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var exitCode = ServerApp.PerformAutoBackup();
|
||||
|
||||
// once we are finished, just exit
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
|
||||
if (Config.Default.RunAsAdministratorPrompt && !SecurityUtils.IsAdministrator())
|
||||
{
|
||||
var result = MessageBox.Show(_globalizer.GetResourceString("Application_RunAsAdministratorLabel"), _globalizer.GetResourceString("Application_RunAsAdministratorTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
var processInfo = new ProcessStartInfo(Assembly.GetEntryAssembly().CodeBase);
|
||||
|
||||
// The following properties run the new process as administrator
|
||||
processInfo.UseShellExecute = true;
|
||||
processInfo.Verb = "runas";
|
||||
processInfo.Arguments = string.Join(" ", e.Args);
|
||||
|
||||
// Start the new process
|
||||
try
|
||||
{
|
||||
Process.Start(processInfo);
|
||||
|
||||
// Shut down the current process
|
||||
Application.Current.Shutdown(0);
|
||||
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// The user did not allow the application to run as administrator
|
||||
MessageBox.Show(_globalizer.GetResourceString("Application_RunAsAdministrator_FailedLabel"), _globalizer.GetResourceString("Application_RunAsAdministrator_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if application is already running
|
||||
if (ProcessUtils.IsAlreadyRunning())
|
||||
{
|
||||
var result = MessageBox.Show(_globalizer.GetResourceString("Application_SingleInstanceLabel"), _globalizer.GetResourceString("Application_SingleInstanceTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
if (ProcessUtils.SwitchToCurrentInstance())
|
||||
{
|
||||
// Shut down the current process
|
||||
Application.Current.Shutdown(0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MessageBox.Show(_globalizer.GetResourceString("Application_SingleInstance_FailedLabel"), _globalizer.GetResourceString("Application_SingleInstance_FailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
this.ApplicationStarted = true;
|
||||
|
||||
// Initial configuration setting
|
||||
if (String.IsNullOrWhiteSpace(Config.Default.DataPath))
|
||||
{
|
||||
MessageBox.Show(_globalizer.GetResourceString("Application_DataDirectoryLabel"), _globalizer.GetResourceString("Application_DataDirectoryTitle"), MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
|
||||
var installationFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
if (!installationFolder.EndsWith(@"\"))
|
||||
installationFolder += @"\";
|
||||
|
||||
while (String.IsNullOrWhiteSpace(Config.Default.DataPath))
|
||||
{
|
||||
var dialog = new CommonOpenFileDialog
|
||||
{
|
||||
EnsureFileExists = true,
|
||||
IsFolderPicker = true,
|
||||
Multiselect = false,
|
||||
Title = _globalizer.GetResourceString("Application_DataDirectory_DialogTitle"),
|
||||
InitialDirectory = installationFolder
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog() != CommonFileDialogResult.Ok)
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
MessageBoxResult confirm = MessageBoxResult.Cancel;
|
||||
|
||||
// check if the folder is under the installation folder
|
||||
var newDataFolder = dialog.FileName;
|
||||
if (!newDataFolder.EndsWith(@"\"))
|
||||
newDataFolder += @"\";
|
||||
|
||||
if (newDataFolder.StartsWith(installationFolder))
|
||||
{
|
||||
confirm = MessageBoxResult.No;
|
||||
MessageBox.Show(_globalizer.GetResourceString("Application_DataDirectory_WithinInstallFolderErrorLabel"), _globalizer.GetResourceString("Application_DataDirectory_WithinInstallFolderErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
confirm = MessageBox.Show(String.Format(_globalizer.GetResourceString("Application_DataDirectory_ConfirmLabel"), Path.Combine(newDataFolder, Config.Default.ProfilesRelativePath), Path.Combine(newDataFolder, CommonConfig.Default.SteamCmdRelativePath)), _globalizer.GetResourceString("Application_DataDirectory_ConfirmTitle"), MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
|
||||
}
|
||||
|
||||
if (confirm == MessageBoxResult.Cancel)
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
else if (confirm == MessageBoxResult.Yes)
|
||||
{
|
||||
if (newDataFolder.EndsWith(@"\"))
|
||||
newDataFolder = newDataFolder.Substring(0, newDataFolder.Length - 1);
|
||||
|
||||
Config.Default.DataPath = newDataFolder;
|
||||
ReconfigureLogging();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Config.Default.ConfigPath = Path.Combine(Config.Default.DataPath, Config.Default.ProfilesRelativePath);
|
||||
System.IO.Directory.CreateDirectory(Config.Default.ConfigPath);
|
||||
Config.Default.Save();
|
||||
CommonConfig.Default.Save();
|
||||
|
||||
if (e.Args.Any(a => a.StartsWith(Constants.ARG_SERVERMONITOR, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
ServerRuntime.EnableUpdateModStatus = false;
|
||||
ServerProfile.EnableServerFilesWatcher = false;
|
||||
|
||||
StartupUri = new Uri("Windows/ServerMonitorWindow.xaml", UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
else
|
||||
{
|
||||
// initialize all the game data
|
||||
GameData.Initialize();
|
||||
|
||||
StartupUri = new Uri("Windows/AutoUpdateWindow.xaml", UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
ShutDownApplication();
|
||||
|
||||
base.OnExit(e);
|
||||
}
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public static void ReconfigureLogging()
|
||||
{
|
||||
string logDir = Path.Combine(Config.Default.DataPath, Config.Default.LogsRelativePath);
|
||||
if (!System.IO.Directory.Exists(logDir))
|
||||
System.IO.Directory.CreateDirectory(logDir);
|
||||
|
||||
LogManager.Configuration.Variables["logDir"] = logDir;
|
||||
|
||||
var fileTargets = LogManager.Configuration.AllTargets.OfType<FileTarget>();
|
||||
foreach (var fileTarget in fileTargets)
|
||||
{
|
||||
var fileName = Path.GetFileNameWithoutExtension(fileTarget.FileName.ToString());
|
||||
fileTarget.FileName = Path.Combine(logDir, $"{fileName}.log");
|
||||
fileTarget.ArchiveFileName = Path.Combine(logDir, $"{fileName}.{{#}}.log");
|
||||
}
|
||||
|
||||
LogManager.ReconfigExistingLoggers();
|
||||
}
|
||||
|
||||
private void ShutDownApplication()
|
||||
{
|
||||
if (this.ApplicationStarted)
|
||||
{
|
||||
foreach (var server in ServerManager.Instance.Servers)
|
||||
{
|
||||
try
|
||||
{
|
||||
server.Profile.Save(false, false, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(String.Format(_globalizer.GetResourceString("Application_Profile_SaveFailedLabel"), server.Profile.ProfileName, ex.Message, ex.StackTrace), _globalizer.GetResourceString("Application_Profile_SaveFailedTitle"), MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
Config.Default.Save();
|
||||
CommonConfig.Default.Save();
|
||||
}
|
||||
|
||||
PluginHelper.Instance?.Dispose();
|
||||
|
||||
this.ApplicationStarted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
src/ConanServerManager/Art/Add.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Cancel.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/ChangeNotes.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Checked.ico
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
src/ConanServerManager/Art/Command.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Copy.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Delete.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Document.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Donate.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
src/ConanServerManager/Art/Down.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Download.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Drag.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/DropArrow.ico
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
src/ConanServerManager/Art/Edit.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Filter.ico
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
src/ConanServerManager/Art/Find.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/FolderDelete.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/FolderExport.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/FolderImport.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/FolderOpen.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Help.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Logs.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/NoAvatar.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src/ConanServerManager/Art/Paste.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Players.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Plugin.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Refresh.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Reload.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Save.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Servers.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Settings.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Shortcut.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Start.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/StatusOff.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/StatusOn.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/StatusStarting.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/StatusUnknown.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Steam.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Stop.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Unchecked.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Up.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Validate.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Website.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/Zip.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/ConanServerManager/Art/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
593
src/ConanServerManager/ConanServerManager.csproj
Normal file
|
|
@ -0,0 +1,593 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{F7A82C6A-32CD-4847-AD16-D79ADC72746E}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>ServerManagerTool</RootNamespace>
|
||||
<AssemblyName>ConanServerManager</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>false</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>false</MapFileExtensions>
|
||||
<SupportUrl>https://servermanagers.freeforums.net/thread/43/faq-frequently-asked</SupportUrl>
|
||||
<ErrorReportUrl>https://servermanagers.freeforums.net/board/39/tech-support-bug-reports</ErrorReportUrl>
|
||||
<ProductName>Conan Exiles™ Server Manager</ProductName>
|
||||
<PublisherName>Bletch1971</PublisherName>
|
||||
<SuiteName>Server Managers</SuiteName>
|
||||
<OpenBrowserOnPublish>false</OpenBrowserOnPublish>
|
||||
<ApplicationRevision>1</ApplicationRevision>
|
||||
<ApplicationVersion>1.1.51.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<PublishWizardCompleted>true</PublishWizardCompleted>
|
||||
<BootstrapperEnabled>false</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject>ServerManagerTool.App</StartupObject>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetZone>LocalIntranet</TargetZone>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<GenerateManifests>true</GenerateManifests>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Art\favicon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ManifestCertificateThumbprint>C1A6DBBCC8495EE1062FD4FB1B05D0F1D7E2E392</ManifestCertificateThumbprint>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ManifestKeyFile>ConanServerManager_TemporaryKey.pfx</ManifestKeyFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignManifests>false</SignManifests>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="DotNetZip, Version=1.13.8.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DotNetZip.1.13.8\lib\net40\DotNetZip.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="EO.Wpf, Version=4.0.12.0, Culture=neutral, PublicKeyToken=e92353a6bf73fffc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\EO.Wpf.4.0.12\lib\EO.Wpf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Hardcodet.Wpf.TaskbarNotification, Version=1.0.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Win32.TaskScheduler, Version=2.8.19.0, Culture=neutral, PublicKeyToken=c416bc1b32d97233, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\TaskScheduler.2.8.19\lib\net452\Microsoft.Win32.TaskScheduler.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WindowsAPICodePack-Core.1.1.2\lib\Microsoft.WindowsAPICodePack.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WindowsAPICodePack-Shell.1.1.1\lib\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.7.2\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Data.SQLite, Version=1.0.112.1, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Data.SQLite.Core.1.0.112.1\lib\net40\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Threading.Tasks.Dataflow, Version=4.5.24.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Tpl.Dataflow.4.5.24\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Expression.Blend.Sdk.1.0.2\lib\net45\System.Windows.Interactivity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<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>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Lib\Model\PlayerListParameters.cs" />
|
||||
<Compile Include="Lib\Model\RconParameters.cs" />
|
||||
<Compile Include="Lib\Serialization\IniFileEntryAttribute.cs" />
|
||||
<Compile Include="Lib\Serialization\IniFiles.cs" />
|
||||
<Compile Include="Lib\Serialization\IniSections.cs" />
|
||||
<Compile Include="Lib\Serialization\SystemIniFile.cs" />
|
||||
<Compile Include="Lib\ServerPlayers.cs" />
|
||||
<Compile Include="Lib\ServerRcon.cs" />
|
||||
<Compile Include="Lib\ViewConverters\EnumDescriptionTypeConverter.cs" />
|
||||
<Compile Include="Lib\ViewConverters\MapNameValueConverter.cs" />
|
||||
<Compile Include="Lib\ViewModel\PlayerInfo.cs" />
|
||||
<Compile Include="Windows\AddUserWindow.xaml.cs">
|
||||
<DependentUpon>AddUserWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\AutoUpdateWindow.xaml.cs">
|
||||
<DependentUpon>AutoUpdateWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\CommandLineWindow.xaml.cs">
|
||||
<DependentUpon>CommandLineWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\GameDataWindow.xaml.cs">
|
||||
<DependentUpon>GameDataWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\GlobalSettingsControl.xaml.cs">
|
||||
<DependentUpon>GlobalSettingsControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ModDetailsWindow.xaml.cs">
|
||||
<DependentUpon>ModDetailsWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\PlayerListWindow.xaml.cs">
|
||||
<DependentUpon>PlayerListWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\PlayerProfileWindow.xaml.cs">
|
||||
<DependentUpon>PlayerProfileWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\PluginsWindow.xaml.cs">
|
||||
<DependentUpon>PluginsWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ProcessorAffinityWindow.xaml.cs">
|
||||
<DependentUpon>ProcessorAffinityWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ProfileSyncWindow.xaml.cs">
|
||||
<DependentUpon>ProfileSyncWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ProgressWindow.xaml.cs">
|
||||
<DependentUpon>ProgressWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\RconWindow.xaml.cs">
|
||||
<DependentUpon>RconWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ServerMonitorWindow.xaml.cs">
|
||||
<DependentUpon>ServerMonitorWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ServerSettingsControl.xaml.cs">
|
||||
<DependentUpon>ServerSettingsControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\SettingsWindow.xaml.cs">
|
||||
<DependentUpon>SettingsWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\ShutdownWindow.xaml.cs">
|
||||
<DependentUpon>ShutdownWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\GuildProfileWindow.xaml.cs">
|
||||
<DependentUpon>GuildProfileWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\VersionFeedWindow.xaml.cs">
|
||||
<DependentUpon>VersionFeedWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\WorkshopFilesWindow.xaml.cs">
|
||||
<DependentUpon>WorkshopFilesWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\WorldSaveRestoreWindow.xaml.cs">
|
||||
<DependentUpon>WorldSaveRestoreWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Resource Include="Art\StatusOff.ico" />
|
||||
<Resource Include="Art\StatusOn.ico" />
|
||||
<Resource Include="Art\StatusStarting.ico" />
|
||||
<Resource Include="Art\StatusUnknown.ico" />
|
||||
<Resource Include="Art\Document.ico" />
|
||||
<Resource Include="Art\Servers.ico" />
|
||||
<Resource Include="Art\Shortcut.ico" />
|
||||
<Content Include="..\packages\System.Data.SQLite.Core.1.0.112.1\build\net40\x64\SQLite.Interop.dll">
|
||||
<Link>x64\SQLite.Interop.dll</Link>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\packages\System.Data.SQLite.Core.1.0.112.1\build\net40\x86\SQLite.Interop.dll">
|
||||
<Link>x86\SQLite.Interop.dll</Link>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Resource Include="Art\Filter.ico" />
|
||||
<Resource Include="Art\DropArrow.ico" />
|
||||
<Content Include="Globalization\en-US\en-US.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Config.Designer.cs">
|
||||
<DependentUpon>Config.settings</DependentUpon>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="Enums\LogEventType.cs" />
|
||||
<Compile Include="Enums\PlayerFilterType.cs" />
|
||||
<Compile Include="Enums\PlayerSortType.cs" />
|
||||
<Compile Include="Enums\ServerProcessStatus.cs" />
|
||||
<Compile Include="Enums\ServerProcessType.cs" />
|
||||
<Compile Include="Enums\ServerProfileCategory.cs" />
|
||||
<Compile Include="Enums\ServerStatus.cs" />
|
||||
<Compile Include="Enums\AvailabilityStatus.cs" />
|
||||
<Compile Include="Enums\WatcherServerStatus.cs" />
|
||||
<Compile Include="ErrorHandling.cs" />
|
||||
<None Include="Installer.iss" />
|
||||
<Content Include="Styles\Default.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Globalization\fr-FR\fr-FR.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Globalization\pt-BR\pt-BR.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Globalization\en-AU\en-AU.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Page Include="Windows\AddUserWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\AutoUpdateWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\CommandLineWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\GameDataWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\GlobalSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\ModDetailsWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\PlayerListWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\PlayerProfileWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\PluginsWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\ProcessorAffinityWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\ProfileSyncWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\ProgressWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\RconWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\ServerMonitorWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\ServerSettingsControl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\SettingsWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\ShutdownWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\GuildProfileWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\VersionFeedWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\WorkshopFilesWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Windows\WorldSaveRestoreWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Lib\BranchSnapshot.cs" />
|
||||
<Compile Include="Lib\Events\ProfileEventArgs.cs" />
|
||||
<Compile Include="Lib\GameData.cs" />
|
||||
<Compile Include="Lib\Model\ModDetail.cs" />
|
||||
<Compile Include="Lib\Model\ModDetailExtended.cs" />
|
||||
<Compile Include="Lib\Model\ModDetailList.cs" />
|
||||
<Compile Include="Lib\ServerProfileSnapshot.cs" />
|
||||
<Compile Include="Lib\Server.cs" />
|
||||
<Compile Include="Lib\ServerApp.cs" />
|
||||
<Compile Include="Lib\ServerManager.cs" />
|
||||
<Compile Include="Lib\ServerProfile.cs" />
|
||||
<Compile Include="Lib\ServerRuntime.cs" />
|
||||
<Compile Include="Lib\ServerStatusUpdate.cs" />
|
||||
<Compile Include="Lib\ServerStatusUpdateRegistration.cs" />
|
||||
<Compile Include="Lib\ServerStatusWatcher.cs" />
|
||||
<Compile Include="Utils\ModUtils.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Content Include="GameData\Conan.gamedata">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="VersionFeed.xml" />
|
||||
<None Include="VersionFeedBeta.xml" />
|
||||
<None Include="Config.settings">
|
||||
<Generator>PublicSettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Config.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Content Include="NLog.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="DeployBetaToGithub.cmd" />
|
||||
<None Include="DeployToGithub.cmd" />
|
||||
<None Include="MakeLatestBetaVersionGithub.ps1" />
|
||||
<None Include="MakeLatestVersionGithub.ps1" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\app.manifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<COMReference Include="IWshRuntimeLibrary">
|
||||
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.6.2">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft .NET Framework 4.6.2 %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Add.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Cancel.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\ChangeNotes.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Checked.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Command.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Copy.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Delete.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Donate.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Down.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Download.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Drag.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Edit.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\favicon.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Find.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\FolderDelete.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\FolderExport.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\FolderImport.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\FolderOpen.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Help.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Logs.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\NoAvatar.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Paste.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Players.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Plugin.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Refresh.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Reload.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Save.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Settings.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Start.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Steam.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Stop.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Unchecked.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Up.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Validate.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Website.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Art\Zip.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ConanData\ConanData.csproj">
|
||||
<Project>{96832688-29bd-464f-9dce-482e37bfc751}</Project>
|
||||
<Name>ConanData</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ConanServerManager.Common\ConanServerManager.Common.csproj">
|
||||
<Project>{630422ca-4bcc-4d1d-9701-87d8eaf0b209}</Project>
|
||||
<Name>ConanServerManager.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\NeXtVdf\NeXt.Vdf.csproj">
|
||||
<Project>{e4eda8b8-006c-4d41-822f-f64b6db0021f}</Project>
|
||||
<Name>NeXt.Vdf</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Plugin.Common\Plugin.Common.csproj">
|
||||
<Project>{679fe859-9a82-4ffb-a758-c1e8df915f58}</Project>
|
||||
<Name>Plugin.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\QueryMaster\QueryMaster.csproj">
|
||||
<Project>{4ca9c894-518f-42d7-bbe2-cfdfe7a03f8a}</Project>
|
||||
<Name>QueryMaster</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ServerManager.Common\ServerManager.Common.csproj">
|
||||
<Project>{7c99d9f7-0c65-4116-927a-94eb018c88fd}</Project>
|
||||
<Name>ServerManager.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ServerManager.Updater\ServerManager.Updater.csproj">
|
||||
<Project>{3e0c9ee6-780f-4fef-ba03-e38062a5fdb6}</Project>
|
||||
<Name>ServerManager.Updater</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\WPFSharp.Globalizer\WPFSharp.Globalizer.csproj">
|
||||
<Project>{715461e8-4e54-4993-80a8-8e72892135e0}</Project>
|
||||
<Name>WPFSharp.Globalizer</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\System.Data.SQLite.Core.1.0.112.1\build\net40\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.112.1\build\net40\System.Data.SQLite.Core.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\System.Data.SQLite.Core.1.0.112.1\build\net40\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Data.SQLite.Core.1.0.112.1\build\net40\System.Data.SQLite.Core.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
1900
src/ConanServerManager/Config.Designer.cs
generated
Normal file
531
src/ConanServerManager/Config.settings
Normal file
|
|
@ -0,0 +1,531 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="ServerManagerTool" GeneratedClassName="Config">
|
||||
<Profiles />
|
||||
<Settings>
|
||||
<Setting Name="ConfigPath" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="SteamCmdInstallServerArgsFormat" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">+login {0} +force_install_dir "{1}" "+app_update {2} {3} {4}" +quit</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServersInstallPath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Servers</Value>
|
||||
</Setting>
|
||||
<Setting Name="DefaultServerProfileName" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Unnamed Profile</Value>
|
||||
</Setting>
|
||||
<Setting Name="DefaultServerName" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Unnamed Server</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerBinaryRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ConanSandbox\Binaries\Win64</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerConfigRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ConanSandbox\Saved\Config\WindowsServer</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerExeFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ConanSandboxServer-Win64-Test.exe</Value>
|
||||
</Setting>
|
||||
<Setting Name="ProfilesRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">profiles</Value>
|
||||
</Setting>
|
||||
<Setting Name="ProfileExtension" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">.profile</Value>
|
||||
</Setting>
|
||||
<Setting Name="DataPath" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="ServerProcessName" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ConanSandboxServer-Win64-Test</Value>
|
||||
</Setting>
|
||||
<Setting Name="LoadProfileExtensionList" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">*.profile,*.ini</Value>
|
||||
</Setting>
|
||||
<Setting Name="MachinePublicIP" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="ManageFirewallAutomatically" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="LogsRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Logs</Value>
|
||||
</Setting>
|
||||
<Setting Name="LatestServerManagerVersionUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/latest.txt</Value>
|
||||
</Setting>
|
||||
<Setting Name="UpdateCheckTime" Type="System.Int32" Scope="Application">
|
||||
<Value Profile="(Default)">1440</Value>
|
||||
</Setting>
|
||||
<Setting Name="SavedFilesRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ConanSandbox\Saved</Value>
|
||||
</Setting>
|
||||
<Setting Name="UpgradeConfig" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="HelpUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">http://servermanagers.freeforums.net/thread/43/faq-frequently-asked</Value>
|
||||
</Setting>
|
||||
<Setting Name="CultureName" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">en-US</Value>
|
||||
</Setting>
|
||||
<Setting Name="SectionAdministrationIsExpanded" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="SectionAutomaticManagementIsExpanded" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="AppPatchNotesUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://forums.funcom.com/c/conan-exiles/Patch-Notes</Value>
|
||||
</Setting>
|
||||
<Setting Name="AppUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">http://store.steampowered.com/app/440900/</Value>
|
||||
</Setting>
|
||||
<Setting Name="RunAsAdministratorPrompt" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_EnableUpdate" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_UpdatePeriod" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">60</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_GracePeriod" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">15</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_GraceMessage1" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Server shutdown required. Server will shutdown in {minutes} minutes. Please logout before shutdown to prevent character corruption.</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_GraceMessage2" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Server shutdown required. Server will shutdown in 1 minute. Please logout before shutdown to prevent character corruption.</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_GraceMessage3" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Server shutdown required. Server is shutting down now.</Value>
|
||||
</Setting>
|
||||
<Setting Name="LastUpdatedTimeFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">LastUpdatedSM.txt</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_WorldSaveMessage" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Server shutdown required. Server is about to shutdown, performing a world save.</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_EnableWorldSave" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="LauncherFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">RunServer.cmd</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamCmdInstallModArgsFormat" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">+login {0} +workshop_download_item {1} {2} +quit</Value>
|
||||
</Setting>
|
||||
<Setting Name="AppSteamWorkshopFolderRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">steamapps\workshop\content\440900\</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerModsRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ConanSandbox\Mods</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_CacheDir" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="ServerUpdate_UpdateModsWhenUpdatingServer" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerUpdate_ForceUpdateMods" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerUpdate_ForceCopyMods" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="SavedRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Saved</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamCmdRedirectOutput" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_UseSmartCopy" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="StyleName" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="WorkshopCacheFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">workshopcache_440900.json</Value>
|
||||
</Setting>
|
||||
<Setting Name="Email_Host" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="Email_Port" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">25</Value>
|
||||
</Setting>
|
||||
<Setting Name="Email_UseSSL" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="Email_UseDetaultCredentials" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="Email_Username" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="Email_Password" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="Email_From" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="Email_To" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="EmailNotify_AutoUpdate" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="EmailNotify_AutoRestart" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamCmd_Username" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="SteamCmd_AnonymousUsername" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">anonymous</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamCmd_UseAnonymousCredentials" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamWorkshopFolderRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">steamapps\workshop</Value>
|
||||
</Setting>
|
||||
<Setting Name="AppSteamWorkshopFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">appworkshop_440900.acf</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamCmd_Password" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="ValidateProfileOnServerStart" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerUpdate_OnServerStart" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="AppId" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">440900</Value>
|
||||
</Setting>
|
||||
<Setting Name="AppIdServer" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">443030</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerAppIdFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">steam_appid.txt</Value>
|
||||
</Setting>
|
||||
<Setting Name="LatestServerManagerBetaVersionUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/beta/latest.txt</Value>
|
||||
</Setting>
|
||||
<Setting Name="LatestServerManagerBetaDownloadUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/beta/latest.zip</Value>
|
||||
</Setting>
|
||||
<Setting Name="LatestServerManagerDownloadUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/latest.zip</Value>
|
||||
</Setting>
|
||||
<Setting Name="LatestServerManagerPatchNotesUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">http://servermanagers.freeforums.net/thread/36/downloads</Value>
|
||||
</Setting>
|
||||
<Setting Name="LatestServerManagerBetaPatchNotesUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">http://servermanagers.freeforums.net/board/44/beta-testers</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerBlacklistFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">blacklist.txt</Value>
|
||||
</Setting>
|
||||
<Setting Name="SectionServerFilesIsExpanded" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="EmailNotify_ShutdownRestart" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="WorkshopCache_ExpiredHours" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">168</Value>
|
||||
</Setting>
|
||||
<Setting Name="DefaultServerRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">server</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerStatusUrlFormat" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="BackupRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">_backup_</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerGameConfigFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Game.ini</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_CancelMessage" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Server shutdown has been cancelled.</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerUpdate_ForceUpdateModsIfNoSteamInfo" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoBackup_EnableBackup" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoBackup_BackupPeriod" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">60</Value>
|
||||
</Setting>
|
||||
<Setting Name="EmailNotify_AutoBackup" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoBackup_DeleteOldFiles" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoBackup_DeleteInterval" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">30</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerBackup_WorldSaveMessage" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">A world save is about to be performed, you may experience some lag during this process. Please be patient.</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_RetryOnFail" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamWebAPIKeyHelpUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">http://servermanagers.freeforums.net/thread/40/get-own-steam-web-api</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_ShowUpdateReason" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="BackupServerExtension" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">.smbak</Value>
|
||||
</Setting>
|
||||
<Setting Name="ScheduledTasksCheckTime" Type="System.Int32" Scope="Application">
|
||||
<Value Profile="(Default)">1</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_ValidateServerFiles" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_OverrideServerStartup" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerManagerUniqueKey" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_ParallelUpdate" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_UpdateReasonPrefix" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Server Update Reason:</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_ServerStopMessage" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">The server is stopping.</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_ServerShutdownMessage" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">The server is shutting down.</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_ServerStartedMessage" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">The server is starting.</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_BackupProcessError" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">The server backup process was performed but an error occurred.</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_ShutdownProcessError" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">The server shutdown process was performed but an error occurred.</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_RestartProcessError" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">The server restart process was performed but an error occurred.</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_UpdateProcessError" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">The server update process was performed but an error occurred.</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_ModUpdateDetected" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Mod updates have been detected:</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerManagerPluginUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">http://servermanagers.freeforums.net/board/36/plugins</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerManagerForumUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">http://servermanagers.freeforums.net/</Value>
|
||||
</Setting>
|
||||
<Setting Name="DefaultGlobalizationFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Globalization\en-US\en-US.xaml</Value>
|
||||
</Setting>
|
||||
<Setting Name="ScheduledTaskFolder" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ConanServerManager</Value>
|
||||
</Setting>
|
||||
<Setting Name="FirewallRulePrefix" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ConanServer:</Value>
|
||||
</Setting>
|
||||
<Setting Name="DonationUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=bletch1971%40hotmail%2ecom&lc=US&item_name=Server%20Manager&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerManagerCode" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">F2653C3D-BC83-440A-AD99-FD9D9466DE04</Value>
|
||||
</Setting>
|
||||
<Setting Name="BackupExtension" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">.zip</Value>
|
||||
</Setting>
|
||||
<Setting Name="UpdaterPrefix" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Conan_</Value>
|
||||
</Setting>
|
||||
<Setting Name="UpdaterFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ServerManagerUpdater.exe</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_WorldSaveDelay" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">10</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_UseShutdownCommand" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_ServerStatusChange" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Server Status:</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_ServerUpdate" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Game Server Update</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_UpdateResults" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Update performed, includes:</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerCommandLineArgsIPMatchFormat" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">-MultiHome={0}</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerCommandLineArgsPortMatchFormat" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">-QueryPort={0}</Value>
|
||||
</Setting>
|
||||
<Setting Name="BackupPath" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_AllMessagesShowReason" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="GameDataRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">GameData</Value>
|
||||
</Setting>
|
||||
<Setting Name="GameDataExtension" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">.gamedata</Value>
|
||||
</Setting>
|
||||
<Setting Name="GameDataApplication" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">conan</Value>
|
||||
</Setting>
|
||||
<Setting Name="CloseShutdownWindowWhenFinished" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerManagerVersionFeedUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/VersionFeed.xml</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerManagerVersionBetaFeedUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://raw.githubusercontent.com/Bletch1971/ServerManagers/master/CSM/beta/VersionFeed.xml</Value>
|
||||
</Setting>
|
||||
<Setting Name="DefaultServerBranchName" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">live</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamCmdInstallServerBetaNameArgsFormat" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">-beta {0}</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamCmdInstallServerBetaPasswordArgsFormat" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">-betapassword {0}</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerBranchFolderPrefix" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">__</Value>
|
||||
</Setting>
|
||||
<Setting Name="AppSteamManifestFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">appmanifest_443030.acf</Value>
|
||||
</Setting>
|
||||
<Setting Name="SteamManifestFolderRelativePath" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">steamapps</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerEngineConfigFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Engine.ini</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerSettingsConfigFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">ServerSettings.ini</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerModListFile" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">modlist.txt</Value>
|
||||
</Setting>
|
||||
<Setting Name="RCON_PlayerListFilter" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">19</Value>
|
||||
</Setting>
|
||||
<Setting Name="RCON_PlayerListSort" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">1</Value>
|
||||
</Setting>
|
||||
<Setting Name="SendMessageDelay" Type="System.Int32" Scope="Application">
|
||||
<Value Profile="(Default)">5000</Value>
|
||||
</Setting>
|
||||
<Setting Name="PlayerImageFileExtension" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">.png</Value>
|
||||
</Setting>
|
||||
<Setting Name="PlayerListFilter" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">19</Value>
|
||||
</Setting>
|
||||
<Setting Name="PlayerListSort" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">1</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdownCommand" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">doexit</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerSaveCommand" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">saveworld</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerStatus_EnableActions" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerStatus_ShowActionConfirmation" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="DefaultStyleFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">Styles\Default.xaml</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerWhitelistFile" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">whitelist.txt</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerCommandLineStandardArgs" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">-listen -nosteamclient -game -server -log</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_SequencialDelayPeriod" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="BackupWorldFile" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="GameDataUrl" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">https://servermanagers.freeforums.net/</Value>
|
||||
</Setting>
|
||||
<Setting Name="MainWindow_Width" Type="System.Double" Scope="User">
|
||||
<Value Profile="(Default)">1100</Value>
|
||||
</Setting>
|
||||
<Setting Name="MainWindow_Height" Type="System.Double" Scope="User">
|
||||
<Value Profile="(Default)">900</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerMonitorWindow_Width" Type="System.Double" Scope="User">
|
||||
<Value Profile="(Default)">900</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerMonitorWindow_Height" Type="System.Double" Scope="User">
|
||||
<Value Profile="(Default)">500</Value>
|
||||
</Setting>
|
||||
<Setting Name="UpdateDirectoryPermissions" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoUpdate_VerifyServerAfterUpdate" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_CheckForOnlinePlayers" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerShutdown_SendShutdownMessages" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoRestart_EnabledGracePeriod" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoRestart_GracePeriod" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerStatusWatcher_LocalStatusQueryDelay" Type="System.Int32" Scope="Application">
|
||||
<Value Profile="(Default)">15000</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerStatusWatcher_RemoteStatusQueryDelay" Type="System.Int32" Scope="Application">
|
||||
<Value Profile="(Default)">120000</Value>
|
||||
</Setting>
|
||||
<Setting Name="MainWindow_MinimizeToTray" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerMonitorMessageOutput_Height" Type="System.Double" Scope="User">
|
||||
<Value Profile="(Default)">100</Value>
|
||||
</Setting>
|
||||
<Setting Name="Alert_ServerStartedMessageIncludeIPandPort" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="ManagePublicIPAutomatically" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
11
src/ConanServerManager/Enums/AvailabilityStatus.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
namespace ServerManagerTool.Enums
|
||||
{
|
||||
public enum AvailabilityStatus
|
||||
{
|
||||
Unknown,
|
||||
NeedPublicIP,
|
||||
Unavailable,
|
||||
WaitingForPublication,
|
||||
Available
|
||||
}
|
||||
}
|
||||
9
src/ConanServerManager/Enums/LogEventType.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
namespace ServerManagerTool.Enums
|
||||
{
|
||||
public enum LogEventType
|
||||
{
|
||||
All,
|
||||
Chat,
|
||||
Event
|
||||
}
|
||||
}
|
||||
15
src/ConanServerManager/Enums/PlayerFilterType.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace ServerManagerTool.Enums
|
||||
{
|
||||
[Flags]
|
||||
public enum PlayerFilterType
|
||||
{
|
||||
None = 0,
|
||||
Offline = 0x1,
|
||||
Online = 0x2,
|
||||
Admin = 0x4,
|
||||
Invalid = 0x10,
|
||||
Whitelisted = 0x20,
|
||||
}
|
||||
}
|
||||
10
src/ConanServerManager/Enums/PlayerSortType.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
namespace ServerManagerTool.Enums
|
||||
{
|
||||
public enum PlayerSortType
|
||||
{
|
||||
Online = 0,
|
||||
Name = 1,
|
||||
Tribe = 2,
|
||||
LastOnline = 3,
|
||||
}
|
||||
}
|
||||
25
src/ConanServerManager/Enums/ServerProcessStatus.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
namespace ServerManagerTool.Enums
|
||||
{
|
||||
public enum ServerProcessStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// The server binary could not be found
|
||||
/// </summary>
|
||||
NotInstalled,
|
||||
|
||||
/// <summary>
|
||||
/// The server binary was found, but the process was not.
|
||||
/// </summary>
|
||||
Stopped,
|
||||
|
||||
/// <summary>
|
||||
/// The server binary was found, the process was found, but no permissions to access the process.
|
||||
/// </summary>
|
||||
Unknown,
|
||||
|
||||
/// <summary>
|
||||
/// The server process was found
|
||||
/// </summary>
|
||||
Running,
|
||||
}
|
||||
}
|
||||
14
src/ConanServerManager/Enums/ServerProcessType.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace ServerManagerTool.Enums
|
||||
{
|
||||
public enum ServerProcessType
|
||||
{
|
||||
Unknown = 0,
|
||||
AutoBackup,
|
||||
AutoUpdate,
|
||||
AutoShutdown1,
|
||||
AutoShutdown2,
|
||||
Backup,
|
||||
Shutdown,
|
||||
Restart,
|
||||
}
|
||||
}
|
||||
9
src/ConanServerManager/Enums/ServerProfileCategory.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
namespace ServerManagerTool.Enums
|
||||
{
|
||||
public enum ServerProfileCategory
|
||||
{
|
||||
Administration,
|
||||
AutomaticManagement,
|
||||
ServerFiles,
|
||||
}
|
||||
}
|
||||
13
src/ConanServerManager/Enums/ServerStatus.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
namespace ServerManagerTool.Enums
|
||||
{
|
||||
public enum ServerStatus
|
||||
{
|
||||
Unknown,
|
||||
Stopping,
|
||||
Stopped,
|
||||
Initializing,
|
||||
Running,
|
||||
Updating,
|
||||
Uninstalled
|
||||
}
|
||||
}
|
||||
40
src/ConanServerManager/Enums/WatcherServerStatus.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
namespace ServerManagerTool.Enums
|
||||
{
|
||||
public enum WatcherServerStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// The server binary couldnot be found.
|
||||
/// </summary>
|
||||
NotInstalled,
|
||||
|
||||
/// <summary>
|
||||
/// The server binary was found, but the process was not
|
||||
/// </summary>
|
||||
Stopped,
|
||||
|
||||
/// <summary>
|
||||
/// The server binary was found, the process was found, but no permissions to access the process.
|
||||
/// </summary>
|
||||
Unknown,
|
||||
|
||||
/// <summary>
|
||||
/// The server process was found, but the server is not responding on its port
|
||||
/// </summary>
|
||||
Initializing,
|
||||
|
||||
/// <summary>
|
||||
/// The server is responding locally on its port, a local check was made
|
||||
/// </summary>
|
||||
RunningLocalCheck,
|
||||
|
||||
/// <summary>
|
||||
/// The server is responding locally on its port, a public check was made
|
||||
/// </summary>
|
||||
RunningExternalCheck,
|
||||
|
||||
/// <summary>
|
||||
/// The server is responding externally on its port
|
||||
/// </summary>
|
||||
Published,
|
||||
}
|
||||
}
|
||||
117
src/ConanServerManager/ErrorHandling.cs
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
using ServerManagerTool.Common.Utils;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace ServerManagerTool
|
||||
{
|
||||
public static class ErrorHandling
|
||||
{
|
||||
public static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
// Oops! Bad news everyone - the app is going down!
|
||||
// Write out a log file with all the details so users can send us the info...
|
||||
|
||||
var file = Path.GetTempFileName();
|
||||
var crashFile = file + ".dmp";
|
||||
|
||||
try
|
||||
{
|
||||
MiniDumpToFile(crashFile);
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
var details = new StringBuilder();
|
||||
details.AppendLine("Server Manager Crash Report");
|
||||
details.AppendLine($"Please report this crash to the Server Manager forums - {Config.Default.ServerManagerForumUrl}");
|
||||
details.AppendLine();
|
||||
|
||||
details.AppendLine($"Assembly: {Assembly.GetEntryAssembly()}");
|
||||
details.AppendLine($"Version: {App.Instance.Version}");
|
||||
details.AppendLine($"Code: {Config.Default.ServerManagerCode}");
|
||||
details.AppendLine($"IsAdministrator: {SecurityUtils.IsAdministrator()}");
|
||||
details.AppendLine();
|
||||
|
||||
details.AppendLine($"Windows Platform: {Environment.OSVersion.Platform}");
|
||||
details.AppendLine($"Windows Version: {Environment.OSVersion.VersionString}");
|
||||
details.AppendLine();
|
||||
|
||||
details.AppendLine($"Crash Dump: {crashFile}");
|
||||
details.AppendLine();
|
||||
|
||||
var exception = e.ExceptionObject as Exception;
|
||||
if (exception != null)
|
||||
{
|
||||
details.AppendLine("Exception Message:");
|
||||
details.AppendLine(exception.Message);
|
||||
details.AppendLine();
|
||||
|
||||
details.AppendLine("Stack Trace:");
|
||||
details.AppendLine(exception.StackTrace);
|
||||
}
|
||||
|
||||
File.WriteAllText(file, details.ToString());
|
||||
|
||||
var message = new StringBuilder();
|
||||
message.AppendLine("OOPS! The Server Manager has suffered from an internal error and must shut down, this is probably a bug and should be reported. The error files are:");
|
||||
message.AppendLine($"Error File: {file}");
|
||||
message.AppendLine($"Crash Dump: {crashFile}");
|
||||
details.AppendLine();
|
||||
details.AppendLine();
|
||||
message.AppendLine($"Please report this crash to the Server Manager forums - {Config.Default.ServerManagerForumUrl}");
|
||||
message.AppendLine("The crash log will now be opened in notepad.");
|
||||
|
||||
var result = MessageBox.Show(message.ToString(), "Server Manager crashed", MessageBoxButton.OK, MessageBoxImage.Exclamation);
|
||||
if (result == MessageBoxResult.OK)
|
||||
{
|
||||
Process.Start("notepad.exe", file);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(file, $"Exception trying to write exception: {ex.Message}\r\nStacktrace: {ex.StackTrace}");
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
internal enum MinidumpType
|
||||
{
|
||||
MiniDumpNormal = 0x00000000,
|
||||
MiniDumpWithDataSegs = 0x00000001,
|
||||
MiniDumpWithFullMemory = 0x00000002,
|
||||
MiniDumpWithHandleData = 0x00000004,
|
||||
MiniDumpFilterMemory = 0x00000008,
|
||||
MiniDumpScanMemory = 0x00000010,
|
||||
MiniDumpWithUnloadedModules = 0x00000020,
|
||||
MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
|
||||
MiniDumpFilterModulePaths = 0x00000080,
|
||||
MiniDumpWithProcessThreadData = 0x00000100,
|
||||
MiniDumpWithPrivateReadWriteMemory = 0x00000200,
|
||||
MiniDumpWithoutOptionalData = 0x00000400,
|
||||
MiniDumpWithFullMemoryInfo = 0x00000800,
|
||||
MiniDumpWithThreadInfo = 0x00001000,
|
||||
MiniDumpWithCodeSegs = 0x00002000
|
||||
}
|
||||
|
||||
[DllImport("dbghelp.dll")]
|
||||
static extern bool MiniDumpWriteDump(IntPtr hProcess, Int32 ProcessId, IntPtr hFile, MinidumpType DumpType, IntPtr ExceptionParam, IntPtr UserStreamParam, IntPtr CallackParam);
|
||||
|
||||
public static void MiniDumpToFile(String fileToDump)
|
||||
{
|
||||
var fsToDump = File.Create(fileToDump);
|
||||
|
||||
Process thisProcess = Process.GetCurrentProcess();
|
||||
MiniDumpWriteDump(thisProcess.Handle, thisProcess.Id, fsToDump.SafeFileHandle.DangerousGetHandle(), MinidumpType.MiniDumpWithFullMemory, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
fsToDump.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
51
src/ConanServerManager/GameData/Conan.gamedata
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"Application": "conan",
|
||||
"Version": "1.1.0",
|
||||
"Created": "2020-09-20T00:00:00.0000000Z",
|
||||
"GameMaps": [
|
||||
{
|
||||
"ClassName": "ConanSandbox",
|
||||
"Description": "The Exiled Lands",
|
||||
"SaveFileName": "game.db",
|
||||
"Mod": "Conan"
|
||||
},
|
||||
{
|
||||
"ClassName": "/Game/DLC_EXT/DLC_Siptah/Maps/DLC_Isle_of_Siptah",
|
||||
"Description": "Isle of Siptah",
|
||||
"SaveFileName": "DLC_Siptah.db",
|
||||
"Mod": "Conan"
|
||||
}
|
||||
],
|
||||
"Branches": [
|
||||
{
|
||||
"BranchName": "testlive",
|
||||
"Description": "TestLive"
|
||||
}
|
||||
],
|
||||
"ServerRegions": [
|
||||
{
|
||||
"RegionNumber": "0",
|
||||
"Description": "Europe"
|
||||
},
|
||||
{
|
||||
"RegionNumber": "1",
|
||||
"Description": "North America"
|
||||
},
|
||||
{
|
||||
"RegionNumber": "2",
|
||||
"Description": "Asia"
|
||||
},
|
||||
{
|
||||
"RegionNumber": "3",
|
||||
"Description": "Australia"
|
||||
},
|
||||
{
|
||||
"RegionNumber": "4",
|
||||
"Description": "South America"
|
||||
},
|
||||
{
|
||||
"RegionNumber": "5",
|
||||
"Description": "Japan"
|
||||
}
|
||||
]
|
||||
}
|
||||
12
src/ConanServerManager/Globalization/en-AU/en-AU.xaml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<Globalization:GlobalizationResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:Globalization="clr-namespace:WPFSharp.Globalizer;assembly=WPFSharp.Globalizer"
|
||||
Name="en-AU"
|
||||
LinkedStyle="en-AU-style"
|
||||
>
|
||||
|
||||
<sys:String x:Key="Generic_TranslatedBy">Bletch</sys:String>
|
||||
|
||||
</Globalization:GlobalizationResourceDictionary>
|
||||
1163
src/ConanServerManager/Globalization/en-US/en-US.xaml
Normal file
1000
src/ConanServerManager/Globalization/fr-FR/fr-FR.xaml
Normal file
1044
src/ConanServerManager/Globalization/pt-BR/pt-BR.xaml
Normal file
36
src/ConanServerManager/Lib/BranchSnapshot.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class BranchSnapshot
|
||||
{
|
||||
public string BranchName = string.Empty;
|
||||
public string BranchPassword = string.Empty;
|
||||
}
|
||||
|
||||
public class BranchSnapshotComparer : IEqualityComparer<BranchSnapshot>
|
||||
{
|
||||
public bool Equals(BranchSnapshot x, BranchSnapshot y)
|
||||
{
|
||||
//Check whether the compared objects reference the same data.
|
||||
if (Object.ReferenceEquals(x, y)) return true;
|
||||
|
||||
//Check whether any of the compared objects is null.
|
||||
if (x is null || y is null)
|
||||
return false;
|
||||
|
||||
//Check whether the snapshot' properties are equal.
|
||||
return x.BranchName == y.BranchName;
|
||||
}
|
||||
|
||||
public int GetHashCode(BranchSnapshot snapshot)
|
||||
{
|
||||
//Check whether the object is null
|
||||
if (snapshot is null) return 0;
|
||||
|
||||
//Get hash code for the Name field if it is not null.
|
||||
return snapshot.BranchName == null ? 0 : snapshot.BranchName.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/ConanServerManager/Lib/Events/ProfileEventArgs.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ProfileEventArgs : EventArgs
|
||||
{
|
||||
public ProfileEventArgs(ServerProfile profile)
|
||||
{
|
||||
Profile = profile;
|
||||
}
|
||||
|
||||
public ServerProfile Profile;
|
||||
}
|
||||
}
|
||||
98
src/ConanServerManager/Lib/GameData.cs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public static class GameData
|
||||
{
|
||||
public static string MainDataFolder = Path.Combine(Environment.CurrentDirectory, Config.Default.GameDataRelativePath);
|
||||
public static string UserDataFolder = Path.Combine(Config.Default.DataPath, Config.Default.GameDataRelativePath);
|
||||
|
||||
private static MainGameData gameData = null;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
// read static game data
|
||||
GameDataUtils.ReadAllData(out gameData, MainDataFolder, Config.Default.GameDataExtension, Config.Default.GameDataApplication);
|
||||
|
||||
// read user game data
|
||||
MainGameData userGameData = new MainGameData();
|
||||
if (!UserDataFolder.Equals(MainDataFolder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
GameDataUtils.ReadAllData(out userGameData, UserDataFolder, Config.Default.GameDataExtension, Config.Default.GameDataApplication, true);
|
||||
}
|
||||
|
||||
// game maps
|
||||
gameData.GameMaps.AddRange(userGameData.GameMaps);
|
||||
|
||||
if (gameData.GameMaps.Count > 0)
|
||||
{
|
||||
var maps = gameMaps.ToList();
|
||||
maps.AddRange(gameData.GameMaps.ConvertAll(item => new ComboBoxItem { ValueMember = item.ClassName, DisplayMember = item.Description }));
|
||||
|
||||
gameMaps = maps.ToArray();
|
||||
}
|
||||
|
||||
// branches
|
||||
gameData.Branches.AddRange(userGameData.Branches);
|
||||
|
||||
if (gameData.Branches.Count > 0)
|
||||
{
|
||||
var allBranches = branches.ToList();
|
||||
allBranches.AddRange(gameData.Branches.ConvertAll(item => new ComboBoxItem { ValueMember = item.BranchName, DisplayMember = item.Description }));
|
||||
|
||||
branches = allBranches.ToArray();
|
||||
}
|
||||
|
||||
// server regions
|
||||
gameData.ServerRegions.AddRange(userGameData.ServerRegions);
|
||||
|
||||
if (gameData.ServerRegions.Count > 0)
|
||||
{
|
||||
var allServerRegions = serverRegions.ToList();
|
||||
allServerRegions.AddRange(gameData.ServerRegions.ConvertAll(item => new ComboBoxItem { ValueMember = item.RegionNumber, DisplayMember = item.Description }));
|
||||
|
||||
serverRegions = allServerRegions.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static string FriendlyNameForClass(string className, bool returnNullIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? (returnNullIfNotFound ? null : string.Empty) : GlobalizedApplication.Instance.GetResourceString(className) ?? (returnNullIfNotFound ? null : className);
|
||||
|
||||
#region Game Maps
|
||||
private static ComboBoxItem[] gameMaps = new ComboBoxItem[]
|
||||
{
|
||||
new ComboBoxItem { ValueMember="", DisplayMember="" },
|
||||
};
|
||||
|
||||
public static IEnumerable<ComboBoxItem> GetGameMaps() => gameMaps.Select(m => m.Duplicate());
|
||||
|
||||
public static string FriendlyMapNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(className) ?? gameData?.GameMaps?.FirstOrDefault(i => i.ClassName.Equals(className))?.Description ?? (returnEmptyIfNotFound ? string.Empty : className);
|
||||
|
||||
public static string MapSaveNameForClass(string className, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(className) ? string.Empty : gameData?.GameMaps?.FirstOrDefault(i => i.ClassName.Equals(className))?.SaveFileName ?? (returnEmptyIfNotFound ? string.Empty : className);
|
||||
#endregion
|
||||
|
||||
#region Branches
|
||||
private static ComboBoxItem[] branches = new[]
|
||||
{
|
||||
new ComboBoxItem { ValueMember="", DisplayMember=FriendlyNameForClass(Config.Default.DefaultServerBranchName) },
|
||||
};
|
||||
|
||||
public static IEnumerable<ComboBoxItem> GetBranches() => branches.Select(d => d.Duplicate());
|
||||
|
||||
public static string FriendlyBranchName(string branchName, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(branchName) ? string.Empty : GlobalizedApplication.Instance.GetResourceString(branchName) ?? gameData?.Branches?.FirstOrDefault(i => i.BranchName.Equals(branchName))?.Description ?? (returnEmptyIfNotFound ? string.Empty : branchName);
|
||||
#endregion
|
||||
|
||||
#region Server Regions
|
||||
private static ComboBoxItem[] serverRegions = new ComboBoxItem[0];
|
||||
|
||||
public static IEnumerable<ComboBoxItem> GetServerRegions() => serverRegions.Select(d => d.Duplicate());
|
||||
|
||||
public static string FriendlyServerRegionName(string regionNumber, bool returnEmptyIfNotFound = false) => string.IsNullOrWhiteSpace(regionNumber) ? string.Empty : GlobalizedApplication.Instance.GetResourceString($"ServerRegion_{regionNumber}") ?? gameData?.ServerRegions?.FirstOrDefault(i => i.RegionNumber.Equals(regionNumber))?.Description ?? (returnEmptyIfNotFound ? string.Empty : regionNumber);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
242
src/ConanServerManager/Lib/Model/ModDetail.cs
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Utils;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ModDetail : DependencyObject
|
||||
{
|
||||
private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
|
||||
|
||||
public static readonly DependencyProperty AppIdProperty = DependencyProperty.Register(nameof(AppId), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty IndexProperty = DependencyProperty.Register(nameof(Index), typeof(int), typeof(ModDetail), new PropertyMetadata(0));
|
||||
public static readonly DependencyProperty IsFirstProperty = DependencyProperty.Register(nameof(IsFirst), typeof(bool), typeof(ModDetail), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty IsLastProperty = DependencyProperty.Register(nameof(IsLast), typeof(bool), typeof(ModDetail), new PropertyMetadata(false));
|
||||
public static readonly DependencyProperty LastWriteTimeProperty = DependencyProperty.Register(nameof(LastWriteTime), typeof(DateTime), typeof(ModDetail), new PropertyMetadata(DateTime.MinValue));
|
||||
public static readonly DependencyProperty LastTimeUpdatedProperty = DependencyProperty.Register(nameof(LastTimeUpdated), typeof(int), typeof(ModDetail), new PropertyMetadata(0));
|
||||
public static readonly DependencyProperty ModIdProperty = DependencyProperty.Register(nameof(ModId), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty ModTypeProperty = DependencyProperty.Register(nameof(ModType), typeof(string), typeof(ModDetail), new PropertyMetadata(ModUtils.MODTYPE_UNKNOWN));
|
||||
public static readonly DependencyProperty ModTypeStringProperty = DependencyProperty.Register(nameof(ModTypeString), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty ModUrlProperty = DependencyProperty.Register(nameof(ModUrl), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty TimeUpdatedProperty = DependencyProperty.Register(nameof(TimeUpdated), typeof(int), typeof(ModDetail), new PropertyMetadata(0));
|
||||
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(ModDetail), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty IsValidProperty = DependencyProperty.Register(nameof(IsValid), typeof(bool), typeof(ModDetail), new PropertyMetadata(false));
|
||||
|
||||
public string AppId
|
||||
{
|
||||
get { return (string)GetValue(AppIdProperty); }
|
||||
set { SetValue(AppIdProperty, value); }
|
||||
}
|
||||
|
||||
public int Index
|
||||
{
|
||||
get { return (int)GetValue(IndexProperty); }
|
||||
set { SetValue(IndexProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsFirst
|
||||
{
|
||||
get { return (bool)GetValue(IsFirstProperty); }
|
||||
set { SetValue(IsFirstProperty, value); }
|
||||
}
|
||||
|
||||
public bool IsLast
|
||||
{
|
||||
get { return (bool)GetValue(IsLastProperty); }
|
||||
set { SetValue(IsLastProperty, value); }
|
||||
}
|
||||
|
||||
public DateTime LastWriteTime
|
||||
{
|
||||
get { return (DateTime)GetValue(LastWriteTimeProperty); }
|
||||
set { SetValue(LastWriteTimeProperty, value); }
|
||||
}
|
||||
|
||||
public int LastTimeUpdated
|
||||
{
|
||||
get { return (int)GetValue(LastTimeUpdatedProperty); }
|
||||
set { SetValue(LastTimeUpdatedProperty, value); }
|
||||
}
|
||||
|
||||
public string ModId
|
||||
{
|
||||
get { return (string)GetValue(ModIdProperty); }
|
||||
set { SetValue(ModIdProperty, value); }
|
||||
}
|
||||
|
||||
public string ModType
|
||||
{
|
||||
get { return (string)GetValue(ModTypeProperty); }
|
||||
set
|
||||
{
|
||||
SetValue(ModTypeProperty, value);
|
||||
SetModTypeString();
|
||||
}
|
||||
}
|
||||
|
||||
public string ModTypeString
|
||||
{
|
||||
get { return (string)GetValue(ModTypeStringProperty); }
|
||||
set { SetValue(ModTypeStringProperty, value); }
|
||||
}
|
||||
|
||||
public int TimeUpdated
|
||||
{
|
||||
get { return (int)GetValue(TimeUpdatedProperty); }
|
||||
set { SetValue(TimeUpdatedProperty, value); }
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return (string)GetValue(TitleProperty); }
|
||||
set
|
||||
{
|
||||
SetValue(TitleProperty, value);
|
||||
|
||||
TitleFilterString = value?.ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get { return (bool)GetValue(IsValidProperty); }
|
||||
set { SetValue(IsValidProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
public bool IsValidModType => !string.IsNullOrWhiteSpace(ModType) && (ModType.Equals(ModUtils.MODTYPE_MAP) || ModType.Equals(ModUtils.MODTYPE_MOD));
|
||||
|
||||
public string LastWriteTimeString => LastWriteTime == DateTime.MinValue ? string.Empty : LastWriteTime.ToString();
|
||||
|
||||
public string LastWriteTimeSortString => LastWriteTime == DateTime.MinValue ? string.Empty : LastWriteTime.ToString("yyyyMMdd_HHmmss");
|
||||
|
||||
public string MapName { get; set; }
|
||||
|
||||
public string ModUrl => $"http://steamcommunity.com/sharedfiles/filedetails/?id={ModId}";
|
||||
|
||||
public string TimeUpdatedString => TimeUpdated <= 0 ? string.Empty : DateTimeUtils.UnixTimeStampToDateTime(TimeUpdated).ToString();
|
||||
|
||||
public string TimeUpdatedSortString => TimeUpdated <= 0 ? string.Empty : DateTimeUtils.UnixTimeStampToDateTime(TimeUpdated).ToString("yyyyMMdd_HHmmss");
|
||||
|
||||
public string TitleFilterString
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool UpToDate => !IsValid && TimeUpdated == -1 || LastTimeUpdated > 0 && LastTimeUpdated == TimeUpdated;
|
||||
|
||||
public long FolderSize { get; set; }
|
||||
|
||||
public string FolderSizeString
|
||||
{
|
||||
get
|
||||
{
|
||||
// GB
|
||||
var divisor = Math.Pow(1024, 3);
|
||||
if (FolderSize > divisor)
|
||||
return $"{FolderSize / divisor:N2} GB";
|
||||
|
||||
// MB
|
||||
divisor = Math.Pow(1024, 2);
|
||||
if (FolderSize > divisor)
|
||||
return $"{FolderSize / divisor:N2} MB";
|
||||
|
||||
// KB
|
||||
divisor = Math.Pow(1024, 1);
|
||||
if (FolderSize > divisor)
|
||||
return $"{FolderSize / divisor:N2} KB";
|
||||
|
||||
return $"{FolderSize} B";
|
||||
}
|
||||
}
|
||||
|
||||
public void PopulateExtended(string modsRootFolder)
|
||||
{
|
||||
var modExtended = new ModDetailExtended(ModId);
|
||||
modExtended.PopulateExtended(modsRootFolder);
|
||||
PopulateExtended(modExtended);
|
||||
}
|
||||
|
||||
public void PopulateExtended(ModDetailExtended extended)
|
||||
{
|
||||
LastTimeUpdated = extended.LastTimeUpdated;
|
||||
LastWriteTime = extended.LastWriteTime;
|
||||
MapName = extended.MapName;
|
||||
ModType = extended.ModType;
|
||||
FolderSize = extended.FolderSize;
|
||||
}
|
||||
|
||||
public void SetModTypeString()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ModType))
|
||||
ModTypeString = _globalizer.GetResourceString("ModType_Unknown");
|
||||
|
||||
switch (ModType)
|
||||
{
|
||||
case ModUtils.MODTYPE_MAP:
|
||||
ModTypeString = _globalizer.GetResourceString("ModType_Map");
|
||||
break;
|
||||
|
||||
case ModUtils.MODTYPE_MOD:
|
||||
ModTypeString = _globalizer.GetResourceString("ModType_Mod");
|
||||
break;
|
||||
|
||||
default:
|
||||
if (string.IsNullOrWhiteSpace(AppId))
|
||||
ModTypeString = _globalizer.GetResourceString("ModType_Unknown");
|
||||
else
|
||||
ModTypeString = _globalizer.GetResourceString("ModType_NotDownloaded");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static ModDetail GetModDetail(PublishedFileDetail detail)
|
||||
{
|
||||
var result = new ModDetail()
|
||||
{
|
||||
AppId = detail.creator_app_id,
|
||||
ModId = detail.publishedfileid,
|
||||
TimeUpdated = detail.time_updated,
|
||||
Title = detail.title,
|
||||
IsValid = true,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ModDetail GetModDetail(WorkshopFileDetail detail)
|
||||
{
|
||||
var result = new ModDetail()
|
||||
{
|
||||
AppId = detail.creator_appid,
|
||||
ModId = detail.publishedfileid,
|
||||
TimeUpdated = detail.time_updated,
|
||||
Title = detail.title,
|
||||
IsValid = true,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ModDetail GetModDetail(WorkshopFileItem detail)
|
||||
{
|
||||
var result = new ModDetail()
|
||||
{
|
||||
AppId = detail.AppId,
|
||||
ModId = detail.WorkshopId,
|
||||
TimeUpdated = detail.TimeUpdated,
|
||||
Title = detail.Title,
|
||||
IsValid = true,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ModId} - {Title}";
|
||||
}
|
||||
}
|
||||
}
|
||||
61
src/ConanServerManager/Lib/Model/ModDetailExtended.cs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
using ServerManagerTool.Utils;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ModDetailExtended
|
||||
{
|
||||
public ModDetailExtended(string modId)
|
||||
{
|
||||
ModId = modId;
|
||||
}
|
||||
|
||||
public string MapName { get; set; }
|
||||
|
||||
private string ModId { get; set; }
|
||||
|
||||
public string ModType { get; set; }
|
||||
|
||||
public DateTime LastWriteTime { get; set; }
|
||||
|
||||
public int LastTimeUpdated { get; set; }
|
||||
|
||||
public long FolderSize { get; set; }
|
||||
|
||||
public void PopulateExtended(string modsRootFolder)
|
||||
{
|
||||
try
|
||||
{
|
||||
FolderSize = 0;
|
||||
LastWriteTime = DateTime.MinValue;
|
||||
ModType = ModUtils.MODTYPE_UNKNOWN;
|
||||
MapName = string.Empty;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(modsRootFolder) || !Directory.Exists(modsRootFolder))
|
||||
return;
|
||||
|
||||
var modFileName = $"{ModId}.pak";
|
||||
var modFile = Path.Combine(modsRootFolder, modFileName);
|
||||
if (!string.IsNullOrWhiteSpace(modFile) && File.Exists(modFile))
|
||||
{
|
||||
var file = new FileInfo(modFile);
|
||||
LastWriteTime = file.LastWriteTime;
|
||||
FolderSize += file.Length;
|
||||
ModType = ModUtils.MODTYPE_MOD;
|
||||
}
|
||||
|
||||
var timeFileName = $"{ModId}.txt";
|
||||
var modTimeFile = Path.Combine(modsRootFolder, timeFileName);
|
||||
if (!string.IsNullOrWhiteSpace(modTimeFile) && File.Exists(modTimeFile))
|
||||
{
|
||||
LastTimeUpdated = ModUtils.GetModLatestTime(modTimeFile);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
200
src/ConanServerManager/Lib/Model/ModDetailList.cs
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ModDetailList : ObservableCollection<ModDetail>
|
||||
{
|
||||
public bool AnyUnknownModTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Any(m => !m.IsValidModType);
|
||||
}
|
||||
}
|
||||
|
||||
public new void Add(ModDetail mod)
|
||||
{
|
||||
if (mod == null || this.Any(m => m.ModId.Equals(mod.ModId)))
|
||||
return;
|
||||
|
||||
base.Add(mod);
|
||||
SetPublishedFileIndex();
|
||||
}
|
||||
|
||||
public void AddRange(ModDetail[] mods)
|
||||
{
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
if (mod == null || this.Any(m => m.ModId.Equals(mod.ModId)))
|
||||
continue;
|
||||
base.Add(mod);
|
||||
}
|
||||
SetPublishedFileIndex();
|
||||
}
|
||||
|
||||
public new void Insert(int index, ModDetail mod)
|
||||
{
|
||||
if (mod == null || this.Any(m => m.ModId.Equals(mod.ModId)))
|
||||
return;
|
||||
|
||||
base.Insert(index, mod);
|
||||
SetPublishedFileIndex();
|
||||
}
|
||||
|
||||
public void Move(ModDetail mod, int newIndex)
|
||||
{
|
||||
if (mod == null)
|
||||
return;
|
||||
|
||||
var index = base.IndexOf(mod);
|
||||
if (index <= 0)
|
||||
return;
|
||||
|
||||
base.Move(index, newIndex);
|
||||
SetPublishedFileIndex();
|
||||
}
|
||||
|
||||
public void MoveDown(ModDetail mod)
|
||||
{
|
||||
if (mod == null)
|
||||
return;
|
||||
|
||||
var index = base.IndexOf(mod);
|
||||
if (index >= base.Count - 1)
|
||||
return;
|
||||
|
||||
base.Move(index, index + 1);
|
||||
SetPublishedFileIndex();
|
||||
}
|
||||
|
||||
public void MoveUp(ModDetail mod)
|
||||
{
|
||||
if (mod == null)
|
||||
return;
|
||||
|
||||
var index = base.IndexOf(mod);
|
||||
if (index <= 0)
|
||||
return;
|
||||
|
||||
base.Move(index, index - 1);
|
||||
SetPublishedFileIndex();
|
||||
}
|
||||
|
||||
public void PopulateExtended(string modsRootFolder)
|
||||
{
|
||||
var results = new Dictionary<ModDetail, ModDetailExtended>();
|
||||
foreach (var mod in this)
|
||||
{
|
||||
results.Add(mod, new ModDetailExtended(mod.ModId));
|
||||
}
|
||||
|
||||
Parallel.ForEach(results, kvp => kvp.Value.PopulateExtended(modsRootFolder));
|
||||
|
||||
foreach (var kvp in results)
|
||||
{
|
||||
kvp.Key.PopulateExtended(kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public new bool Remove(ModDetail mod)
|
||||
{
|
||||
if (mod == null)
|
||||
return false;
|
||||
|
||||
var removed = base.Remove(mod);
|
||||
|
||||
SetPublishedFileIndex();
|
||||
return removed;
|
||||
}
|
||||
|
||||
public void SetPublishedFileIndex()
|
||||
{
|
||||
foreach (var mod in this)
|
||||
{
|
||||
mod.Index = base.IndexOf(mod) + 1;
|
||||
mod.IsFirst = false;
|
||||
mod.IsLast = false;
|
||||
}
|
||||
|
||||
if (this.Count == 0)
|
||||
return;
|
||||
|
||||
this[0].IsFirst = true;
|
||||
this[base.Count - 1].IsLast = true;
|
||||
}
|
||||
|
||||
public bool GetModStrings(out string mapString, out string modIdString)
|
||||
{
|
||||
mapString = null;
|
||||
modIdString = string.Empty;
|
||||
|
||||
var delimiter = "";
|
||||
foreach (var mod in this)
|
||||
{
|
||||
switch (mod.ModType)
|
||||
{
|
||||
case ModUtils.MODTYPE_MOD:
|
||||
default:
|
||||
modIdString += $"{delimiter}{mod.ModId}";
|
||||
delimiter = ",";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ModDetailList GetModDetails(List<string> modIdList, string modsRootFolder, WorkshopFileList workshopFiles, PublishedFileDetailsResponse response)
|
||||
{
|
||||
var result = new ModDetailList();
|
||||
|
||||
if (modIdList != null)
|
||||
{
|
||||
foreach (var modId in modIdList)
|
||||
{
|
||||
var temp = workshopFiles?.FirstOrDefault(w => w.WorkshopId.Equals(modId));
|
||||
|
||||
result.Add(new ModDetail()
|
||||
{
|
||||
AppId = temp?.AppId ?? string.Empty,
|
||||
ModId = modId,
|
||||
TimeUpdated = -1,
|
||||
Title = temp?.Title ?? "Mod name not available",
|
||||
IsValid = false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (response?.publishedfiledetails != null)
|
||||
{
|
||||
foreach (var item in result)
|
||||
{
|
||||
var temp = response.publishedfiledetails.FirstOrDefault(w => w.publishedfileid.Equals(item.ModId));
|
||||
|
||||
if (temp != null)
|
||||
{
|
||||
item.AppId = temp?.creator_app_id ?? string.Empty;
|
||||
item.ModId = temp?.publishedfileid ?? item.ModId;
|
||||
item.TimeUpdated = temp?.time_updated ?? item.TimeUpdated;
|
||||
item.Title = temp?.title ?? item.Title;
|
||||
item.IsValid = temp?.creator_app_id != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.SetPublishedFileIndex();
|
||||
result.PopulateExtended(modsRootFolder);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(ModDetailList)} - {Count}";
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/ConanServerManager/Lib/Model/PlayerListParameters.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using System.Windows;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class PlayerListParameters : DependencyObject
|
||||
{
|
||||
public static readonly DependencyProperty ProfileNameProperty = DependencyProperty.Register(nameof(ProfileName), typeof(string), typeof(PlayerListParameters), new PropertyMetadata(string.Empty));
|
||||
public static readonly DependencyProperty MaxPlayersProperty = DependencyProperty.Register(nameof(MaxPlayers), typeof(int), typeof(PlayerListParameters), new PropertyMetadata(0));
|
||||
|
||||
public string ProfileName
|
||||
{
|
||||
get { return (string)GetValue(ProfileNameProperty); }
|
||||
set { SetValue(ProfileNameProperty, value); }
|
||||
}
|
||||
|
||||
public string ProfileId { get; set; }
|
||||
|
||||
public string InstallDirectory { get; set; }
|
||||
|
||||
public string GameFile { get; set; }
|
||||
|
||||
public Server Server { get; set; }
|
||||
|
||||
public Rect WindowExtents { get; set; }
|
||||
|
||||
public string WindowTitle { get; set; }
|
||||
|
||||
public int MaxPlayers
|
||||
{
|
||||
get { return (int)GetValue(MaxPlayersProperty); }
|
||||
set { SetValue(MaxPlayersProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/ConanServerManager/Lib/Model/RconParameters.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using System.Net;
|
||||
using System.Windows;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class RconParameters : PlayerListParameters
|
||||
{
|
||||
public string RconHost { get; set; }
|
||||
|
||||
public IPAddress RconHostIP
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var ipAddresses = Dns.GetHostAddresses(RconHost);
|
||||
if (ipAddresses.Length > 0)
|
||||
return ipAddresses[0].MapToIPv4();
|
||||
}
|
||||
catch {}
|
||||
|
||||
return IPAddress.None;
|
||||
}
|
||||
}
|
||||
|
||||
public int RconPort { get; set; }
|
||||
|
||||
public string RconPassword { get; set; }
|
||||
|
||||
public double PlayerListWidth { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using ServerManagerTool.Common.Attibutes;
|
||||
using ServerManagerTool.Enums;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class IniFileEntryAttribute : BaseIniFileEntryAttribute
|
||||
{
|
||||
public IniFileEntryAttribute(IniFiles file, IniSections section, ServerProfileCategory category, string key = "")
|
||||
: base(file, section, category, key)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/ConanServerManager/Lib/Serialization/IniFiles.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public enum IniFiles
|
||||
{
|
||||
Engine,
|
||||
Game,
|
||||
ServerSettings,
|
||||
}
|
||||
}
|
||||
20
src/ConanServerManager/Lib/Serialization/IniSections.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public enum IniSections
|
||||
{
|
||||
// Engine.ini
|
||||
Engine_OnlineSubsystem,
|
||||
Engine_OnlineSubsystemSteam,
|
||||
Engine_URL,
|
||||
|
||||
// Game.ini
|
||||
Game_GameSession,
|
||||
Game_RconPlugin,
|
||||
|
||||
// ServerSettings.ini
|
||||
ServerSettings_ServerSettings,
|
||||
|
||||
// Misc
|
||||
Custom,
|
||||
}
|
||||
}
|
||||
46
src/ConanServerManager/Lib/Serialization/SystemIniFile.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
using ServerManagerTool.Common.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class SystemIniFile : BaseSystemIniFile
|
||||
{
|
||||
public static readonly Dictionary<Enum, string> IniFileNames = new Dictionary<Enum, string>
|
||||
{
|
||||
{ IniFiles.Engine, Config.Default.ServerEngineConfigFile },
|
||||
{ IniFiles.Game, Config.Default.ServerGameConfigFile },
|
||||
{ IniFiles.ServerSettings, Config.Default.ServerSettingsConfigFile },
|
||||
};
|
||||
|
||||
public static readonly Dictionary<Enum, string> IniSectionNames = new Dictionary<Enum, string>
|
||||
{
|
||||
// Engine sections, used by the server manager
|
||||
{ IniSections.Engine_OnlineSubsystem, "OnlineSubsystem" },
|
||||
{ IniSections.Engine_OnlineSubsystemSteam, "OnlineSubsystemSteam" },
|
||||
{ IniSections.Engine_URL, "URL" },
|
||||
|
||||
// Engine sections, not used by server manager
|
||||
|
||||
// Game sections, used by the server manager
|
||||
{ IniSections.Game_GameSession, "/Script/Engine.GameSession" },
|
||||
{ IniSections.Game_RconPlugin, "RconPlugin" },
|
||||
|
||||
// Game sections, not used by server manager
|
||||
|
||||
// Server Settings sections, used by the server manager
|
||||
{ IniSections.ServerSettings_ServerSettings, "ServerSettings" },
|
||||
|
||||
// Server Settings sections, not used by server manager
|
||||
};
|
||||
|
||||
public override Dictionary<Enum, string> FileNames => IniFileNames;
|
||||
|
||||
public override Dictionary<Enum, string> SectionNames => IniSectionNames;
|
||||
|
||||
public SystemIniFile(string iniPath)
|
||||
: base(iniPath)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
105
src/ConanServerManager/Lib/Server.cs
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
using ServerManagerTool.Common.Lib;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class Server : DependencyObject, IDisposable
|
||||
{
|
||||
public static readonly DependencyProperty ProfileProperty = DependencyProperty.Register(nameof(Profile), typeof(ServerProfile), typeof(Server), new PropertyMetadata((ServerProfile)null));
|
||||
public static readonly DependencyProperty RuntimeProperty = DependencyProperty.Register(nameof(Runtime), typeof(ServerRuntime), typeof(Server), new PropertyMetadata((ServerRuntime)null));
|
||||
public static readonly DependencyProperty SelectedProperty = DependencyProperty.Register(nameof(Selected), typeof(bool), typeof(Server), new PropertyMetadata(false));
|
||||
|
||||
public ServerProfile Profile
|
||||
{
|
||||
get { return (ServerProfile)GetValue(ProfileProperty); }
|
||||
protected set { SetValue(ProfileProperty, value); }
|
||||
}
|
||||
|
||||
public ServerRuntime Runtime
|
||||
{
|
||||
get { return (ServerRuntime)GetValue(RuntimeProperty); }
|
||||
protected set { SetValue(RuntimeProperty, value); }
|
||||
}
|
||||
|
||||
public bool Selected
|
||||
{
|
||||
get { return (bool)GetValue(SelectedProperty); }
|
||||
set { SetValue(SelectedProperty, value); }
|
||||
}
|
||||
|
||||
private Server(ServerProfile profile)
|
||||
{
|
||||
InitializeFromProfile(profile);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Profile.DestroyServerFilesWatcher();
|
||||
|
||||
this.Runtime.StatusUpdate -= Runtime_StatusUpdate;
|
||||
this.Runtime.Dispose();
|
||||
}
|
||||
|
||||
private void Runtime_StatusUpdate(object sender, EventArgs eventArgs)
|
||||
{
|
||||
this.Profile.LastInstalledVersion = this.Runtime.Version.ToString();
|
||||
}
|
||||
|
||||
public void ImportFromPath(string path, ServerProfile profile = null)
|
||||
{
|
||||
var loadedProfile = ServerProfile.LoadFrom(path, profile);
|
||||
if (loadedProfile != null)
|
||||
InitializeFromProfile(loadedProfile);
|
||||
}
|
||||
|
||||
private void InitializeFromProfile(ServerProfile profile)
|
||||
{
|
||||
if (profile == null)
|
||||
return;
|
||||
|
||||
this.Profile = profile;
|
||||
this.Runtime = new ServerRuntime();
|
||||
this.Runtime.AttachToProfile(this.Profile).Wait();
|
||||
|
||||
this.Runtime.StatusUpdate += Runtime_StatusUpdate;
|
||||
}
|
||||
|
||||
public static Server FromPath(string path)
|
||||
{
|
||||
var loadedProfile = ServerProfile.LoadFrom(path);
|
||||
if (loadedProfile == null)
|
||||
return null;
|
||||
return new Server(loadedProfile);
|
||||
}
|
||||
|
||||
public static Server FromDefaults()
|
||||
{
|
||||
var loadedProfile = ServerProfile.FromDefaults();
|
||||
if (loadedProfile == null)
|
||||
return null;
|
||||
return new Server(loadedProfile);
|
||||
}
|
||||
|
||||
public async Task StartAsync()
|
||||
{
|
||||
await this.Runtime.AttachToProfile(this.Profile);
|
||||
await this.Runtime.StartAsync();
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
{
|
||||
await this.Runtime.StopAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, BranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
|
||||
{
|
||||
await this.Runtime.AttachToProfile(this.Profile);
|
||||
var success = await this.Runtime.UpgradeAsync(cancellationToken, updateServer, branch, validate, updateMods, progressCallback);
|
||||
this.Profile.LastInstalledVersion = this.Runtime.Version.ToString();
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
3147
src/ConanServerManager/Lib/ServerApp.cs
Normal file
135
src/ConanServerManager/Lib/ServerManager.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is responsible for managing all of the servers the tool knows about.
|
||||
/// </summary>
|
||||
public class ServerManager : DependencyObject
|
||||
{
|
||||
static ServerManager()
|
||||
{
|
||||
ServerManager.Instance = new ServerManager();
|
||||
}
|
||||
|
||||
public static ServerManager Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ServersProperty = DependencyProperty.Register(nameof(Servers), typeof(SortableObservableCollection<Server>), typeof(ServerManager), new PropertyMetadata(new SortableObservableCollection<Server>()));
|
||||
|
||||
public SortableObservableCollection<Server> Servers
|
||||
{
|
||||
get { return (SortableObservableCollection<Server>)GetValue(ServersProperty); }
|
||||
set { SetValue(ServersProperty, value); }
|
||||
}
|
||||
|
||||
public ServerManager()
|
||||
{
|
||||
this.Servers.CollectionChanged += Servers_CollectionChanged;
|
||||
}
|
||||
|
||||
void Servers_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if(e.Action == NotifyCollectionChangedAction.Remove)
|
||||
{
|
||||
foreach(Server server in e.OldItems)
|
||||
{
|
||||
server.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int AddFromPath(string path)
|
||||
{
|
||||
var server = Server.FromPath(path);
|
||||
if (server == null)
|
||||
return this.Servers.Count - 1;
|
||||
|
||||
this.Servers.Add(server);
|
||||
return this.Servers.Count - 1;
|
||||
}
|
||||
|
||||
public int AddNew()
|
||||
{
|
||||
var server = Server.FromDefaults();
|
||||
if (server == null)
|
||||
return this.Servers.Count - 1;
|
||||
|
||||
this.Servers.Add(server);
|
||||
return this.Servers.Count - 1;
|
||||
}
|
||||
|
||||
public void Remove(Server server, bool deleteProfile)
|
||||
{
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
// save the profile before deleting, just in case something needed has changed
|
||||
if (server.Profile != null)
|
||||
server.Profile.Save(false, false, null);
|
||||
|
||||
if (deleteProfile)
|
||||
{
|
||||
var profileFile = server.Profile?.GetProfileFile();
|
||||
if (!string.IsNullOrWhiteSpace(profileFile) && File.Exists(profileFile))
|
||||
{
|
||||
// set the file permissions
|
||||
SecurityUtils.SetFileOwnershipForAllUsers(profileFile);
|
||||
try
|
||||
{
|
||||
File.Delete(profileFile);
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
var profileIniDir = server.Profile?.GetProfileConfigDir_Old();
|
||||
if (!string.IsNullOrWhiteSpace(profileIniDir) && Directory.Exists(profileIniDir))
|
||||
{
|
||||
// set the folder permissions
|
||||
SecurityUtils.SetDirectoryOwnershipForAllUsers(profileIniDir);
|
||||
try
|
||||
{
|
||||
Directory.Delete(profileIniDir, true);
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
}
|
||||
|
||||
server.Runtime?.DeleteFirewallRules();
|
||||
server.Dispose();
|
||||
|
||||
this.Servers.Remove(server);
|
||||
}
|
||||
|
||||
public void CheckProfiles()
|
||||
{
|
||||
var serverIds = new Dictionary<string, bool>();
|
||||
foreach (var server in Servers)
|
||||
{
|
||||
if (server == null || server.Profile == null)
|
||||
continue;
|
||||
|
||||
while (serverIds.ContainsKey(server.Profile.ProfileID))
|
||||
{
|
||||
server.Profile.ResetProfileId();
|
||||
}
|
||||
|
||||
serverIds.Add(server.Profile.ProfileID, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void SortServers()
|
||||
{
|
||||
Servers.Sort(s => s.Profile?.SortKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
235
src/ConanServerManager/Lib/ServerPlayers.cs
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
using ConanData;
|
||||
using NLog;
|
||||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ServerPlayers : DependencyObject
|
||||
{
|
||||
private const int PLAYER_LIST_INTERVAL = 5000;
|
||||
|
||||
public event EventHandler PlayersCollectionUpdated;
|
||||
|
||||
public static readonly DependencyProperty PlayersProperty = DependencyProperty.Register(nameof(Players), typeof(SortableObservableCollection<PlayerInfo>), typeof(ServerPlayers), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty CountPlayersProperty = DependencyProperty.Register(nameof(CountPlayers), typeof(int), typeof(ServerPlayers), new PropertyMetadata(0));
|
||||
public static readonly DependencyProperty CountInvalidPlayersProperty = DependencyProperty.Register(nameof(CountInvalidPlayers), typeof(int), typeof(ServerPlayers), new PropertyMetadata(0));
|
||||
public static readonly DependencyProperty CountOnlinePlayersProperty = DependencyProperty.Register(nameof(CountOnlinePlayers), typeof(int), typeof(ServerPlayers), new PropertyMetadata(0));
|
||||
|
||||
private readonly ConcurrentDictionary<string, PlayerInfo> _players = new ConcurrentDictionary<string, PlayerInfo>();
|
||||
private readonly object _updatePlayerCollectionLock = new object();
|
||||
private CancellationTokenSource _cancellationTokenSource = null;
|
||||
private PlayerListParameters _playerListParameters;
|
||||
|
||||
private Logger _allLogger;
|
||||
private Logger _eventLogger;
|
||||
private Logger _debugLogger;
|
||||
private Logger _errorLogger;
|
||||
private bool _disposed = false;
|
||||
|
||||
public ServerPlayers(PlayerListParameters parameters)
|
||||
{
|
||||
this.Players = new SortableObservableCollection<PlayerInfo>();
|
||||
|
||||
_playerListParameters = parameters;
|
||||
|
||||
_allLogger = App.GetProfileLogger(_playerListParameters.ProfileId, "PlayerList_All", LogLevel.Info, LogLevel.Info);
|
||||
_eventLogger = App.GetProfileLogger(_playerListParameters.ProfileId, "PlayerList_Event", LogLevel.Info, LogLevel.Info);
|
||||
_debugLogger = App.GetProfileLogger(_playerListParameters.ProfileId, "PlayerList_Debug", LogLevel.Trace, LogLevel.Debug);
|
||||
_errorLogger = App.GetProfileLogger(_playerListParameters.ProfileId, "PlayerList_Error", LogLevel.Error, LogLevel.Fatal);
|
||||
|
||||
UpdatePlayersAsync().DoNotWait();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_cancellationTokenSource != null)
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
public SortableObservableCollection<PlayerInfo> Players
|
||||
{
|
||||
get { return (SortableObservableCollection<PlayerInfo>)GetValue(PlayersProperty); }
|
||||
set { SetValue(PlayersProperty, value); }
|
||||
}
|
||||
|
||||
public int CountPlayers
|
||||
{
|
||||
get { return (int)GetValue(CountPlayersProperty); }
|
||||
set { SetValue(CountPlayersProperty, value); }
|
||||
}
|
||||
|
||||
public int CountInvalidPlayers
|
||||
{
|
||||
get { return (int)GetValue(CountInvalidPlayersProperty); }
|
||||
set { SetValue(CountInvalidPlayersProperty, value); }
|
||||
}
|
||||
|
||||
public int CountOnlinePlayers
|
||||
{
|
||||
get { return (int)GetValue(CountOnlinePlayersProperty); }
|
||||
set { SetValue(CountOnlinePlayersProperty, value); }
|
||||
}
|
||||
|
||||
private void LogEvent(LogEventType eventType, string message)
|
||||
{
|
||||
switch (eventType)
|
||||
{
|
||||
case LogEventType.All:
|
||||
_allLogger?.Info(message);
|
||||
return;
|
||||
|
||||
case LogEventType.Event:
|
||||
_eventLogger?.Info(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnPlayerCollectionUpdated()
|
||||
{
|
||||
PlayersCollectionUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private async Task UpdatePlayersAsync()
|
||||
{
|
||||
if (this._disposed)
|
||||
return;
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
var token = _cancellationTokenSource.Token;
|
||||
|
||||
await UpdatePlayerDetailsAsync(_cancellationTokenSource.Token);
|
||||
var cancelled = _cancellationTokenSource.IsCancellationRequested;
|
||||
|
||||
if (!cancelled)
|
||||
{
|
||||
await TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
UpdatePlayerCollection();
|
||||
});
|
||||
}
|
||||
|
||||
_cancellationTokenSource.Dispose();
|
||||
_cancellationTokenSource = null;
|
||||
|
||||
if (!cancelled)
|
||||
{
|
||||
await Task.Delay(PLAYER_LIST_INTERVAL).ContinueWith(t => UpdatePlayersAsync());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdatePlayerDetailsAsync(CancellationToken token)
|
||||
{
|
||||
if (this._disposed)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_playerListParameters.GameFile) || !File.Exists(_playerListParameters.GameFile))
|
||||
return;
|
||||
|
||||
var savedPath = ServerProfile.GetProfileSavePath(_playerListParameters.InstallDirectory);
|
||||
DataContainer dataContainer = null;
|
||||
|
||||
try
|
||||
{
|
||||
// load the player data from the files.
|
||||
dataContainer = await DataContainer.CreateAsync(_playerListParameters.GameFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_errorLogger?.Error($"{nameof(UpdatePlayerDetailsAsync)} - Error: CreateAsync. {ex.Message}\r\n{ex.StackTrace}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
// update the player data with the latest update value from the players collection
|
||||
foreach (var playerData in dataContainer.Players)
|
||||
{
|
||||
var id = playerData.PlayerId;
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
continue;
|
||||
|
||||
this._players.TryGetValue(id, out PlayerInfo player);
|
||||
player?.UpdatePlatformData(playerData);
|
||||
}
|
||||
}, token);
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
var totalPlayers = dataContainer.Players.Count;
|
||||
|
||||
foreach (var playerData in dataContainer.Players)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var id = playerData.PlayerId;
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
var validPlayer = new PlayerInfo()
|
||||
{
|
||||
PlayerId = id,
|
||||
PlayerName = playerData.PlayerName,
|
||||
IsValid = true,
|
||||
};
|
||||
|
||||
this._players.AddOrUpdate(id, validPlayer, (k, v) => { v.PlayerName = playerData.PlayerName; v.IsValid = true; return v; });
|
||||
}
|
||||
else
|
||||
{
|
||||
_debugLogger?.Debug($"{nameof(UpdatePlayerDetailsAsync)} - Error: corrupted profile.\r\n{playerData.CharacterId}.");
|
||||
}
|
||||
|
||||
if (this._players.TryGetValue(id, out PlayerInfo player) && player != null)
|
||||
{
|
||||
player.UpdateData(playerData);
|
||||
|
||||
await TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
player.IsWhitelisted = _playerListParameters?.Server?.Profile?.ServerFilesWhitelisted?.Any(u => u.PlayerId.Equals(player.PlayerId, StringComparison.OrdinalIgnoreCase)) ?? false;
|
||||
});
|
||||
}
|
||||
}, token);
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
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();
|
||||
foreach (var droppedPlayer in droppedPlayers)
|
||||
{
|
||||
_players.TryRemove(droppedPlayer.PlayerId, out PlayerInfo player);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlayerCollection()
|
||||
{
|
||||
lock (_updatePlayerCollectionLock)
|
||||
{
|
||||
this.Players = new SortableObservableCollection<PlayerInfo>(_players.Values);
|
||||
this.CountPlayers = this.Players.Count;
|
||||
this.CountInvalidPlayers = this.Players.Count(p => !p.IsValid);
|
||||
this.CountOnlinePlayers = this.Players.Count(p => p.IsOnline);
|
||||
|
||||
OnPlayerCollectionUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1633
src/ConanServerManager/Lib/ServerProfile.cs
Normal file
100
src/ConanServerManager/Lib/ServerProfileSnapshot.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using ServerManagerTool.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ServerProfileSnapshot
|
||||
{
|
||||
public string ProfileId;
|
||||
public string ProfileName;
|
||||
public string ServerName;
|
||||
public string InstallDirectory;
|
||||
public string GameFile;
|
||||
public string AdminPassword;
|
||||
public string ServerIP;
|
||||
public int ServerPort;
|
||||
public int ServerPeerPort;
|
||||
public int QueryPort;
|
||||
public string ServerMap;
|
||||
public List<string> ServerModIds;
|
||||
public bool RconEnabled;
|
||||
public int RconPort;
|
||||
public string RconPassword;
|
||||
public int MaxPlayerCount;
|
||||
|
||||
public string MOTD;
|
||||
public bool MOTDIntervalEnabled;
|
||||
public int MOTDInterval;
|
||||
|
||||
public string BranchName;
|
||||
public string BranchPassword;
|
||||
|
||||
public string SchedulerKey;
|
||||
public bool EnableAutoBackup;
|
||||
public bool EnableAutoUpdate;
|
||||
public bool EnableAutoShutdown1;
|
||||
public bool RestartAfterShutdown1;
|
||||
public bool UpdateAfterShutdown1;
|
||||
public bool EnableAutoShutdown2;
|
||||
public bool RestartAfterShutdown2;
|
||||
public bool UpdateAfterShutdown2;
|
||||
public bool AutoRestartIfShutdown;
|
||||
|
||||
public bool ServerUpdated;
|
||||
public string LastInstalledVersion;
|
||||
public DateTime LastStarted;
|
||||
|
||||
public static ServerProfileSnapshot Create(ServerProfile profile)
|
||||
{
|
||||
return new ServerProfileSnapshot
|
||||
{
|
||||
ProfileId = profile.ProfileID,
|
||||
ProfileName = profile.ProfileName,
|
||||
ServerName = profile.ServerName,
|
||||
InstallDirectory = profile.InstallDirectory,
|
||||
GameFile = profile.GetServerWorldFile(),
|
||||
AdminPassword = profile.AdminPassword,
|
||||
ServerIP = string.IsNullOrWhiteSpace(profile.ServerIP) ? IPAddress.Loopback.ToString() : profile.ServerIP.Trim(),
|
||||
ServerPort = profile.ServerPort,
|
||||
ServerPeerPort = profile.ServerPeerPort,
|
||||
QueryPort = profile.QueryPort,
|
||||
ServerMap = ServerProfile.GetProfileMapName(profile),
|
||||
ServerModIds = ModUtils.GetModIdList(profile.ServerModIds),
|
||||
RconEnabled = profile.RconEnabled,
|
||||
RconPort = profile.RconPort,
|
||||
RconPassword = profile.RconPassword,
|
||||
MaxPlayerCount = profile.MaxPlayers,
|
||||
|
||||
MOTD = profile.MOTD,
|
||||
MOTDIntervalEnabled = profile.MOTDIntervalEnabled && !string.IsNullOrWhiteSpace(profile.MOTD),
|
||||
MOTDInterval = Math.Max(1, Math.Min(int.MaxValue, profile.MOTDInterval)),
|
||||
|
||||
BranchName = profile.BranchName,
|
||||
BranchPassword = profile.BranchPassword,
|
||||
|
||||
SchedulerKey = profile.GetProfileKey(),
|
||||
EnableAutoBackup = profile.EnableAutoBackup,
|
||||
EnableAutoUpdate = profile.EnableAutoUpdate,
|
||||
EnableAutoShutdown1 = profile.EnableAutoShutdown1,
|
||||
RestartAfterShutdown1 = profile.RestartAfterShutdown1,
|
||||
UpdateAfterShutdown1 = profile.UpdateAfterShutdown1,
|
||||
EnableAutoShutdown2 = profile.EnableAutoShutdown2,
|
||||
RestartAfterShutdown2 = profile.RestartAfterShutdown2,
|
||||
UpdateAfterShutdown2 = profile.UpdateAfterShutdown2,
|
||||
AutoRestartIfShutdown = profile.AutoRestartIfShutdown,
|
||||
|
||||
ServerUpdated = false,
|
||||
LastInstalledVersion = profile.LastInstalledVersion ?? new Version(0, 0).ToString(),
|
||||
LastStarted = profile.LastStarted,
|
||||
};
|
||||
}
|
||||
|
||||
public void Update(ServerProfile profile)
|
||||
{
|
||||
profile.LastInstalledVersion = LastInstalledVersion;
|
||||
profile.LastStarted = LastStarted;
|
||||
}
|
||||
}
|
||||
}
|
||||
475
src/ConanServerManager/Lib/ServerRcon.cs
Normal file
|
|
@ -0,0 +1,475 @@
|
|||
using ConanData;
|
||||
using NLog;
|
||||
using ServerManagerTool.Common.Enums;
|
||||
using ServerManagerTool.Common.Interfaces;
|
||||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Model;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using ServerManagerTool.Lib.ViewModel;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ServerRcon : DependencyObject, IAsyncDisposable
|
||||
{
|
||||
private const int PLAYER_LIST_INTERVAL = 5000;
|
||||
private const string NoResponseMatch = "Server received, But no response!!";
|
||||
public const string NoResponseOutput = "NO_RESPONSE";
|
||||
|
||||
public const string RCON_COMMAND_BROADCAST = "broadcast";
|
||||
public const string RCON_COMMAND_LISTPLAYERS = "#managerplayerlist#";
|
||||
|
||||
public event EventHandler PlayersCollectionUpdated;
|
||||
|
||||
public static readonly DependencyProperty PlayersProperty = DependencyProperty.Register(nameof(Players), typeof(SortableObservableCollection<PlayerInfo>), typeof(ServerRcon), new PropertyMetadata(null));
|
||||
public static readonly DependencyProperty CountPlayersProperty = DependencyProperty.Register(nameof(CountPlayers), typeof(int), typeof(ServerRcon), new PropertyMetadata(0));
|
||||
public static readonly DependencyProperty CountInvalidPlayersProperty = DependencyProperty.Register(nameof(CountInvalidPlayers), typeof(int), typeof(ServerRcon), new PropertyMetadata(0));
|
||||
public static readonly DependencyProperty CountOnlinePlayersProperty = DependencyProperty.Register(nameof(CountOnlinePlayers), typeof(int), typeof(ServerRcon), new PropertyMetadata(0));
|
||||
|
||||
private static readonly ConcurrentDictionary<string, bool> locks = new ConcurrentDictionary<string, bool>();
|
||||
private static readonly char[] lineSplitChars = new char[] { '\n' };
|
||||
private static readonly char[] argsSplitChars = new char[] { ' ' };
|
||||
|
||||
private readonly ActionQueue _commandProcessor = new ActionQueue(TaskScheduler.Default);
|
||||
private readonly ActionQueue _outputProcessor = new ActionQueue(TaskScheduler.FromCurrentSynchronizationContext());
|
||||
private readonly List<CommandListener> _commandListeners = new List<CommandListener>();
|
||||
|
||||
private RconParameters _rconParameters;
|
||||
private QueryMaster.Rcon _console;
|
||||
private int maxCommandRetries = 3;
|
||||
|
||||
private readonly ConcurrentDictionary<string, PlayerInfo> _players = new ConcurrentDictionary<string, PlayerInfo>();
|
||||
private readonly object _updatePlayerCollectionLock = new object();
|
||||
private CancellationTokenSource _cancellationTokenSource = null;
|
||||
|
||||
private Logger _chatLogger;
|
||||
private Logger _allLogger;
|
||||
private Logger _eventLogger;
|
||||
private Logger _debugLogger;
|
||||
private Logger _errorLogger;
|
||||
private bool _disposed = false;
|
||||
|
||||
public ServerRcon(RconParameters parameters)
|
||||
{
|
||||
this._rconParameters = parameters;
|
||||
this.Players = new SortableObservableCollection<PlayerInfo>();
|
||||
|
||||
_allLogger = App.GetProfileLogger(this._rconParameters.ProfileId, "Rcon_All", LogLevel.Info, LogLevel.Info);
|
||||
_chatLogger = App.GetProfileLogger(this._rconParameters.ProfileId, "Rcon_Chat", LogLevel.Info, LogLevel.Info);
|
||||
_eventLogger = App.GetProfileLogger(this._rconParameters.ProfileId, "Rcon_Event", LogLevel.Info, LogLevel.Info);
|
||||
_debugLogger = App.GetProfileLogger(this._rconParameters.ProfileId, "Rcon_Debug", LogLevel.Trace, LogLevel.Debug);
|
||||
_errorLogger = App.GetProfileLogger(this._rconParameters.ProfileId, "Rcon_Error", LogLevel.Error, LogLevel.Fatal);
|
||||
|
||||
UpdatePlayersAsync().DoNotWait();
|
||||
}
|
||||
|
||||
public async Task DisposeAsync()
|
||||
{
|
||||
if (_cancellationTokenSource != null)
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
await this._commandProcessor.DisposeAsync();
|
||||
await this._outputProcessor.DisposeAsync();
|
||||
|
||||
for (int index = this._commandListeners.Count - 1; index >= 0; index--)
|
||||
{
|
||||
this._commandListeners[index].Dispose();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
public SortableObservableCollection<PlayerInfo> Players
|
||||
{
|
||||
get { return (SortableObservableCollection<PlayerInfo>)GetValue(PlayersProperty); }
|
||||
set { SetValue(PlayersProperty, value); }
|
||||
}
|
||||
|
||||
public int CountPlayers
|
||||
{
|
||||
get { return (int)GetValue(CountPlayersProperty); }
|
||||
set { SetValue(CountPlayersProperty, value); }
|
||||
}
|
||||
|
||||
public int CountInvalidPlayers
|
||||
{
|
||||
get { return (int)GetValue(CountInvalidPlayersProperty); }
|
||||
set { SetValue(CountInvalidPlayersProperty, value); }
|
||||
}
|
||||
|
||||
public int CountOnlinePlayers
|
||||
{
|
||||
get { return (int)GetValue(CountOnlinePlayersProperty); }
|
||||
set { SetValue(CountOnlinePlayersProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
private void LogEvent(LogEventType eventType, string message)
|
||||
{
|
||||
switch (eventType)
|
||||
{
|
||||
case LogEventType.All:
|
||||
_allLogger?.Info(message);
|
||||
return;
|
||||
|
||||
case LogEventType.Chat:
|
||||
_chatLogger?.Info(message);
|
||||
return;
|
||||
|
||||
case LogEventType.Event:
|
||||
_eventLogger?.Info(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnPlayerCollectionUpdated()
|
||||
{
|
||||
PlayersCollectionUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private bool Reconnect()
|
||||
{
|
||||
if (this._console != null)
|
||||
{
|
||||
this._console.Dispose();
|
||||
this._console = null;
|
||||
}
|
||||
|
||||
var endpoint = new IPEndPoint(this._rconParameters.RconHostIP, this._rconParameters.RconPort);
|
||||
var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint, sendTimeOut: 10000, receiveTimeOut: 10000);
|
||||
this._console = server.GetControl(this._rconParameters.RconPassword);
|
||||
return this._console != null;
|
||||
}
|
||||
|
||||
public IDisposable RegisterCommandListener(Action<ConsoleCommand> callback)
|
||||
{
|
||||
var listener = new CommandListener { Callback = callback, DisposeAction = UnregisterCommandListener };
|
||||
this._commandListeners.Add(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
private void UnregisterCommandListener(CommandListener listener)
|
||||
{
|
||||
this._commandListeners.Remove(listener);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Process Methods
|
||||
private bool ProcessInput(ConsoleCommand command)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!command.suppressCommand)
|
||||
{
|
||||
LogEvent(LogEventType.All, command.rawCommand);
|
||||
}
|
||||
|
||||
var args = command.rawCommand.Split(argsSplitChars, 2);
|
||||
command.command = args[0];
|
||||
if (args.Length > 1)
|
||||
{
|
||||
command.args = args[1];
|
||||
}
|
||||
|
||||
var result = SendCommand(command.rawCommand);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
_debugLogger?.Debug($"SendCommand '{command.rawCommand}' do not return any results.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var lines = result.Split(lineSplitChars, StringSplitOptions.RemoveEmptyEntries).Select(l => l.Trim()).ToArray();
|
||||
|
||||
if (!command.suppressOutput)
|
||||
{
|
||||
foreach (var line in lines)
|
||||
{
|
||||
LogEvent(LogEventType.All, line);
|
||||
}
|
||||
}
|
||||
|
||||
if (lines.Length == 1 && lines[0].StartsWith(NoResponseMatch))
|
||||
{
|
||||
lines[0] = NoResponseOutput;
|
||||
}
|
||||
|
||||
command.lines = lines;
|
||||
}
|
||||
|
||||
command.status = ConsoleStatus.Connected;
|
||||
|
||||
this._outputProcessor.PostAction(() => ProcessOutput(command));
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_errorLogger?.Error($"Failed to send command '{command.rawCommand}'. {ex.Message}");
|
||||
command.status = ConsoleStatus.Disconnected;
|
||||
this._outputProcessor.PostAction(() => ProcessOutput(command));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This is bound to the UI thread
|
||||
private void ProcessOutput(ConsoleCommand command)
|
||||
{
|
||||
//
|
||||
// Handle results
|
||||
//
|
||||
HandleCommand(command);
|
||||
NotifyCommand(command);
|
||||
}
|
||||
|
||||
public Task<bool> IssueCommand(string userCommand)
|
||||
{
|
||||
return this._commandProcessor.PostAction(() => ProcessInput(new ConsoleCommand() { rawCommand = userCommand }));
|
||||
}
|
||||
|
||||
// This is bound to the UI thread
|
||||
private void HandleCommand(ConsoleCommand command)
|
||||
{
|
||||
//
|
||||
// Perform per-command special processing to extract data
|
||||
//
|
||||
if (command?.command?.Equals(RCON_COMMAND_BROADCAST, StringComparison.OrdinalIgnoreCase) ?? false)
|
||||
{
|
||||
LogEvent(LogEventType.Chat, command.rawCommand);
|
||||
command.suppressOutput = true;
|
||||
}
|
||||
|
||||
if (command?.command?.Equals(RCON_COMMAND_LISTPLAYERS, StringComparison.OrdinalIgnoreCase) ?? false)
|
||||
{
|
||||
command.suppressCommand = true;
|
||||
command.suppressOutput = false;
|
||||
}
|
||||
}
|
||||
|
||||
// This is bound to the UI thread
|
||||
private void NotifyCommand(ConsoleCommand command)
|
||||
{
|
||||
foreach (var listener in _commandListeners)
|
||||
{
|
||||
try
|
||||
{
|
||||
listener.Callback(command);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_errorLogger?.Error("Exception in command listener: {0}\n{1}", ex.Message, ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string SendCommand(string command)
|
||||
{
|
||||
const int RETRY_DELAY = 100;
|
||||
|
||||
Exception lastException = null;
|
||||
int retries = 0;
|
||||
|
||||
while (retries < maxCommandRetries)
|
||||
{
|
||||
if (this._console != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return this._console.SendCommand(command);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// we will simply retry
|
||||
lastException = ex;
|
||||
}
|
||||
|
||||
Task.Delay(RETRY_DELAY).Wait();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Reconnect();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lastException = ex;
|
||||
}
|
||||
|
||||
retries++;
|
||||
}
|
||||
|
||||
this.maxCommandRetries = 10;
|
||||
_errorLogger?.Error($"Failed to connect to Rcon at {this._rconParameters.RconHostIP}:{this._rconParameters.RconPort} with {this._rconParameters.RconPassword}. {lastException.Message}");
|
||||
throw new Exception($"Command failed to send after {maxCommandRetries} attempts. Last exception: {lastException.Message}", lastException);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private async Task UpdatePlayersAsync()
|
||||
{
|
||||
if (this._disposed)
|
||||
return;
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
var token = _cancellationTokenSource.Token;
|
||||
|
||||
var output = await UpdatePlayerDetailsAsync(_cancellationTokenSource.Token);
|
||||
var cancelled = _cancellationTokenSource.IsCancellationRequested;
|
||||
|
||||
if (!cancelled)
|
||||
{
|
||||
await TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
UpdatePlayerCollection();
|
||||
|
||||
var command = new ConsoleCommand() { rawCommand = RCON_COMMAND_LISTPLAYERS, command = RCON_COMMAND_LISTPLAYERS, lines = output };
|
||||
ProcessOutput(command);
|
||||
});
|
||||
}
|
||||
|
||||
_cancellationTokenSource.Dispose();
|
||||
_cancellationTokenSource = null;
|
||||
|
||||
if (!cancelled)
|
||||
{
|
||||
await Task.Delay(PLAYER_LIST_INTERVAL).ContinueWith(t => UpdatePlayersAsync());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<string>> UpdatePlayerDetailsAsync(CancellationToken token)
|
||||
{
|
||||
if (this._disposed)
|
||||
return new List<string>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_rconParameters.GameFile) || !File.Exists(_rconParameters.GameFile))
|
||||
return new List<string>();
|
||||
|
||||
var savedPath = ServerProfile.GetProfileSavePath(_rconParameters.InstallDirectory);
|
||||
DataContainer dataContainer = null;
|
||||
|
||||
try
|
||||
{
|
||||
// load the player data from the files.
|
||||
dataContainer = await DataContainer.CreateAsync(_rconParameters.GameFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_errorLogger?.Error($"{nameof(UpdatePlayerDetailsAsync)} - Error: CreateAsync. {ex.Message}\r\n{ex.StackTrace}");
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return new List<string>();
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
// update the player data with the latest update value from the players collection
|
||||
foreach (var playerData in dataContainer.Players)
|
||||
{
|
||||
var id = playerData.PlayerId;
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
continue;
|
||||
|
||||
this._players.TryGetValue(id, out PlayerInfo player);
|
||||
player?.UpdatePlatformData(playerData);
|
||||
}
|
||||
}, token);
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return new List<string>();
|
||||
|
||||
var totalPlayers = dataContainer.Players.Count;
|
||||
var output = new List<string>();
|
||||
|
||||
foreach (var playerData in dataContainer.Players)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var id = playerData.PlayerId;
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
var validPlayer = new PlayerInfo()
|
||||
{
|
||||
PlayerId = id,
|
||||
PlayerName = playerData.PlayerName,
|
||||
IsValid = true,
|
||||
};
|
||||
|
||||
this._players.AddOrUpdate(id, validPlayer, (k, v) => { v.PlayerName = playerData.PlayerName; v.IsValid = true; return v; });
|
||||
}
|
||||
else
|
||||
{
|
||||
_debugLogger?.Debug($"{nameof(UpdatePlayerDetailsAsync)} - Error: corrupted profile.\r\n{playerData.CharacterId}.");
|
||||
}
|
||||
|
||||
if (this._players.TryGetValue(id, out PlayerInfo player) && player != null)
|
||||
{
|
||||
if (player.IsOnline != playerData.Online)
|
||||
{
|
||||
if (playerData.Online)
|
||||
{
|
||||
var messageFormat = GlobalizedApplication.Instance.GetResourceString("Player_Join") ?? "Player '{0}' joined the game.";
|
||||
var message = string.Format(messageFormat, playerData.CharacterName);
|
||||
output.Add(message);
|
||||
LogEvent(LogEventType.Event, message);
|
||||
LogEvent(LogEventType.All, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
var messageFormat = GlobalizedApplication.Instance.GetResourceString("Player_Leave") ?? "Player '{0}' left the game.";
|
||||
var message = string.Format(messageFormat, playerData.CharacterName);
|
||||
output.Add(message);
|
||||
LogEvent(LogEventType.Event, message);
|
||||
LogEvent(LogEventType.All, message);
|
||||
}
|
||||
}
|
||||
|
||||
player.UpdateData(playerData);
|
||||
|
||||
await TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
player.IsWhitelisted = _rconParameters?.Server?.Profile?.ServerFilesWhitelisted?.Any(u => u.PlayerId.Equals(player.PlayerId, StringComparison.OrdinalIgnoreCase)) ?? false;
|
||||
});
|
||||
}
|
||||
}, token);
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
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();
|
||||
foreach (var droppedPlayer in droppedPlayers)
|
||||
{
|
||||
_players.TryRemove(droppedPlayer.PlayerId, out PlayerInfo player);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private void UpdatePlayerCollection()
|
||||
{
|
||||
lock (_updatePlayerCollectionLock)
|
||||
{
|
||||
this.Players = new SortableObservableCollection<PlayerInfo>(_players.Values);
|
||||
this.CountPlayers = this.Players.Count;
|
||||
this.CountInvalidPlayers = this.Players.Count(p => !p.IsValid);
|
||||
this.CountOnlinePlayers = this.Players.Count(p => p.IsOnline);
|
||||
|
||||
OnPlayerCollectionUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1138
src/ConanServerManager/Lib/ServerRuntime.cs
Normal file
14
src/ConanServerManager/Lib/ServerStatusUpdate.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using ServerManagerTool.Enums;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public struct ServerStatusUpdate
|
||||
{
|
||||
public Process Process;
|
||||
public WatcherServerStatus Status;
|
||||
public QueryMaster.ServerInfo ServerInfo;
|
||||
public int OnlinePlayerCount;
|
||||
}
|
||||
}
|
||||
24
src/ConanServerManager/Lib/ServerStatusUpdateRegistration.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using ServerManagerTool.Common.Interfaces;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ServerStatusUpdateRegistration : IAsyncDisposable
|
||||
{
|
||||
public string InstallDirectory;
|
||||
public IPEndPoint LocalEndpoint;
|
||||
public IPEndPoint SteamEndpoint;
|
||||
public Action<IAsyncDisposable, ServerStatusUpdate> UpdateCallback;
|
||||
public Func<Task> UnregisterAction;
|
||||
|
||||
public string ProfileId;
|
||||
public string GameFile;
|
||||
|
||||
public async Task DisposeAsync()
|
||||
{
|
||||
await UnregisterAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
353
src/ConanServerManager/Lib/ServerStatusWatcher.cs
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
using ConanData;
|
||||
using NLog;
|
||||
using ServerManagerTool.Common.Interfaces;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks.Dataflow;
|
||||
|
||||
namespace ServerManagerTool.Lib
|
||||
{
|
||||
public class ServerStatusWatcher
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly List<ServerStatusUpdateRegistration> _serverRegistrations = new List<ServerStatusUpdateRegistration>();
|
||||
private readonly ActionBlock<Func<Task>> _eventQueue;
|
||||
private readonly Dictionary<string, DateTime> _nextExternalStatusQuery = new Dictionary<string, DateTime>();
|
||||
|
||||
static ServerStatusWatcher()
|
||||
{
|
||||
Instance = new ServerStatusWatcher();
|
||||
}
|
||||
|
||||
private ServerStatusWatcher()
|
||||
{
|
||||
_eventQueue = new ActionBlock<Func<Task>>(async f => await f.Invoke(), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 });
|
||||
_eventQueue.Post(DoLocalUpdate);
|
||||
}
|
||||
|
||||
public static ServerStatusWatcher Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public IAsyncDisposable RegisterForUpdates(string installDirectory, string profileId, string gameFile, IPEndPoint localEndpoint, IPEndPoint steamEndpoint, Action<IAsyncDisposable, ServerStatusUpdate> updateCallback)
|
||||
{
|
||||
var registration = new ServerStatusUpdateRegistration
|
||||
{
|
||||
InstallDirectory = installDirectory,
|
||||
ProfileId = profileId,
|
||||
GameFile = gameFile,
|
||||
LocalEndpoint = localEndpoint,
|
||||
SteamEndpoint = steamEndpoint,
|
||||
UpdateCallback = updateCallback,
|
||||
};
|
||||
|
||||
registration.UnregisterAction = async () =>
|
||||
{
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
_eventQueue.Post(() =>
|
||||
{
|
||||
if(_serverRegistrations.Contains(registration))
|
||||
{
|
||||
Logger.Debug($"{nameof(RegisterForUpdates)} Removing registration for L:{registration.LocalEndpoint} S:{registration.SteamEndpoint}");
|
||||
_serverRegistrations.Remove(registration);
|
||||
}
|
||||
tcs.TrySetResult(true);
|
||||
return Task.FromResult(true);
|
||||
});
|
||||
|
||||
await tcs.Task;
|
||||
};
|
||||
|
||||
_eventQueue.Post(() =>
|
||||
{
|
||||
if (!_serverRegistrations.Contains(registration))
|
||||
{
|
||||
Logger.Debug($"{nameof(RegisterForUpdates)} Adding registration for L:{registration.LocalEndpoint} S:{registration.SteamEndpoint}");
|
||||
_serverRegistrations.Add(registration);
|
||||
|
||||
var registrationKey = registration.SteamEndpoint.ToString();
|
||||
_nextExternalStatusQuery[registrationKey] = DateTime.MinValue;
|
||||
}
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
);
|
||||
|
||||
return registration;
|
||||
}
|
||||
|
||||
private static ServerProcessStatus GetServerProcessStatus(ServerStatusUpdateRegistration updateContext, out Process serverProcess)
|
||||
{
|
||||
serverProcess = null;
|
||||
if (String.IsNullOrWhiteSpace(updateContext.InstallDirectory))
|
||||
{
|
||||
return ServerProcessStatus.NotInstalled;
|
||||
}
|
||||
|
||||
var serverExePath = Path.Combine(updateContext.InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ServerExeFile);
|
||||
if(!File.Exists(serverExePath))
|
||||
{
|
||||
return ServerProcessStatus.NotInstalled;
|
||||
}
|
||||
|
||||
//
|
||||
// The server appears to be installed, now determine if it is running or stopped.
|
||||
//
|
||||
try
|
||||
{
|
||||
foreach (var process in Process.GetProcessesByName(Config.Default.ServerProcessName))
|
||||
{
|
||||
var commandLine = ProcessUtils.GetCommandLineForProcess(process.Id)?.ToLower();
|
||||
|
||||
if (commandLine != null && commandLine.Contains(updateContext.InstallDirectory.ToLower()) && commandLine.Contains(Config.Default.ServerExeFile.ToLower()))
|
||||
{
|
||||
// Does this match our server exe and port?
|
||||
var serverArgMatch = String.Format(Config.Default.ServerCommandLineArgsPortMatchFormat, updateContext.LocalEndpoint.Port).ToLower();
|
||||
if (commandLine.Contains(serverArgMatch))
|
||||
{
|
||||
// Was an IP set on it?
|
||||
var anyIpArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, String.Empty).ToLower();
|
||||
if (commandLine.Contains(anyIpArgMatch))
|
||||
{
|
||||
// If we have a specific IP, check for it.
|
||||
var ipArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, updateContext.LocalEndpoint.Address.ToString()).ToLower();
|
||||
if (!commandLine.Contains(ipArgMatch))
|
||||
{
|
||||
// Specific IP set didn't match
|
||||
continue;
|
||||
}
|
||||
|
||||
// Specific IP matched
|
||||
}
|
||||
|
||||
// Either specific IP matched or no specific IP was set and we will claim this is ours.
|
||||
|
||||
process.EnableRaisingEvents = true;
|
||||
if (process.HasExited)
|
||||
{
|
||||
return ServerProcessStatus.Stopped;
|
||||
}
|
||||
|
||||
serverProcess = process;
|
||||
return ServerProcessStatus.Running;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger.Error($"{nameof(GetServerProcessStatus)}. {ex.Message}\r\n{ex.StackTrace}");
|
||||
}
|
||||
|
||||
return ServerProcessStatus.Stopped;
|
||||
}
|
||||
|
||||
private async Task DoLocalUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var registration in this._serverRegistrations)
|
||||
{
|
||||
ServerStatusUpdate statusUpdate = new ServerStatusUpdate();
|
||||
try
|
||||
{
|
||||
Logger.Info($"{nameof(DoLocalUpdate)} Start: {registration.LocalEndpoint}");
|
||||
statusUpdate = await GenerateServerStatusUpdateAsync(registration);
|
||||
|
||||
PostServerStatusUpdate(registration, registration.UpdateCallback, statusUpdate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// We don't want to stop other registration queries or break the ActionBlock
|
||||
Logger.Error($"{nameof(DoLocalUpdate)} - Exception in local update. {ex.Message}\r\n{ex.StackTrace}");
|
||||
Debugger.Break();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Logger.Info($"{nameof(DoLocalUpdate)} End: {registration.LocalEndpoint}: {statusUpdate.Status}");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Task.Delay(Config.Default.ServerStatusWatcher_LocalStatusQueryDelay).ContinueWith(_ => _eventQueue.Post(DoLocalUpdate)).DoNotWait();
|
||||
}
|
||||
}
|
||||
|
||||
private void PostServerStatusUpdate(ServerStatusUpdateRegistration registration, Action<IAsyncDisposable, ServerStatusUpdate> callback, ServerStatusUpdate statusUpdate)
|
||||
{
|
||||
_eventQueue.Post(() =>
|
||||
{
|
||||
if (this._serverRegistrations.Contains(registration))
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(registration, statusUpdate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugUtils.WriteFormatThreadSafeAsync("Exception during local status update callback: {0}\n{1}", ex.Message, ex.StackTrace).DoNotWait();
|
||||
}
|
||||
}
|
||||
return TaskUtils.FinishedTask;
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<ServerStatusUpdate> GenerateServerStatusUpdateAsync(ServerStatusUpdateRegistration registration)
|
||||
{
|
||||
var registrationKey = registration.SteamEndpoint.ToString();
|
||||
|
||||
//
|
||||
// First check the process status
|
||||
//
|
||||
var processStatus = GetServerProcessStatus(registration, out Process process);
|
||||
switch (processStatus)
|
||||
{
|
||||
case ServerProcessStatus.NotInstalled:
|
||||
return new ServerStatusUpdate { Status = WatcherServerStatus.NotInstalled };
|
||||
|
||||
case ServerProcessStatus.Stopped:
|
||||
return new ServerStatusUpdate { Status = WatcherServerStatus.Stopped };
|
||||
|
||||
case ServerProcessStatus.Unknown:
|
||||
return new ServerStatusUpdate { Status = WatcherServerStatus.Unknown };
|
||||
|
||||
case ServerProcessStatus.Running:
|
||||
break;
|
||||
|
||||
default:
|
||||
Debugger.Break();
|
||||
break;
|
||||
}
|
||||
|
||||
var currentStatus = WatcherServerStatus.Initializing;
|
||||
|
||||
//
|
||||
// If the process was running do we then perform network checks.
|
||||
//
|
||||
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server local network status at {registration.LocalEndpoint}");
|
||||
|
||||
// get the server information direct from the server using local connection.
|
||||
GetLocalNetworkStatus(registration.GameFile, registration.LocalEndpoint, out QueryMaster.ServerInfo localInfo, out int onlinePlayerCount);
|
||||
|
||||
if (localInfo != null)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.RunningLocalCheck;
|
||||
|
||||
//
|
||||
// Now that it's running, we can check the publication status.
|
||||
//
|
||||
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public status direct at {registration.SteamEndpoint}");
|
||||
|
||||
// get the server information direct from the server using public connection.
|
||||
var serverStatus = CheckServerStatusDirect(registration.SteamEndpoint);
|
||||
// check if the server returned the information.
|
||||
if (!serverStatus)
|
||||
{
|
||||
// server did not return any information
|
||||
var nextExternalStatusQuery = _nextExternalStatusQuery.ContainsKey(registrationKey) ? _nextExternalStatusQuery[registrationKey] : DateTime.MinValue;
|
||||
if (DateTime.Now >= nextExternalStatusQuery)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.RunningExternalCheck;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerStatusUrlFormat))
|
||||
{
|
||||
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public status via api at {registration.SteamEndpoint}");
|
||||
|
||||
// get the server information direct from the server using external connection.
|
||||
var uri = new Uri(string.Format(Config.Default.ServerStatusUrlFormat, Config.Default.ServerManagerCode, App.Instance.Version, registration.SteamEndpoint.Address, registration.SteamEndpoint.Port));
|
||||
serverStatus = await NetworkUtils.CheckServerStatusViaAPI(uri, registration.SteamEndpoint);
|
||||
}
|
||||
|
||||
_nextExternalStatusQuery[registrationKey] = DateTime.Now.AddMilliseconds(Config.Default.ServerStatusWatcher_RemoteStatusQueryDelay);
|
||||
}
|
||||
}
|
||||
|
||||
// check if the server returned the information.
|
||||
if (serverStatus)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.Published;
|
||||
}
|
||||
}
|
||||
|
||||
var statusUpdate = new ServerStatusUpdate
|
||||
{
|
||||
Process = process,
|
||||
Status = currentStatus,
|
||||
ServerInfo = localInfo,
|
||||
OnlinePlayerCount = onlinePlayerCount,
|
||||
};
|
||||
|
||||
return await Task.FromResult(statusUpdate);
|
||||
}
|
||||
|
||||
private static bool GetLocalNetworkStatus(string gameFile, IPEndPoint endpoint, out QueryMaster.ServerInfo serverInfo, out int onlinePlayerCount)
|
||||
{
|
||||
serverInfo = null;
|
||||
onlinePlayerCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
using (var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint))
|
||||
{
|
||||
try
|
||||
{
|
||||
serverInfo = server.GetInfo();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
serverInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// load the player data from the files.
|
||||
onlinePlayerCount = DataContainer.GetOnlinePlayerCount(gameFile);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
onlinePlayerCount = 0;
|
||||
}
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
// Common when the server is unreachable. Log and Ignore it.
|
||||
Logger.Debug($"{nameof(GetLocalNetworkStatus)} failed: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CheckServerStatusDirect(IPEndPoint endpoint)
|
||||
{
|
||||
try
|
||||
{
|
||||
QueryMaster.ServerInfo serverInfo;
|
||||
|
||||
using (var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint))
|
||||
{
|
||||
serverInfo = server.GetInfo();
|
||||
}
|
||||
|
||||
return serverInfo != null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug($"{nameof(CheckServerStatusDirect)} - Failed checking status direct for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool.Lib.ViewModel
|
||||
{
|
||||
public class EnumDescriptionTypeConverter : EnumConverter
|
||||
{
|
||||
public EnumDescriptionTypeConverter(Type type)
|
||||
: base(type)
|
||||
{
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
var strType = value.GetType().Name;
|
||||
var strVal = value.ToString();
|
||||
|
||||
return GlobalizedApplication.Instance.GetResourceString($"{strType}_{strVal}") ?? strVal;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
using ServerManagerTool.Utils;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using WPFSharp.Globalizer;
|
||||
|
||||
namespace ServerManagerTool.Lib.ViewModel
|
||||
{
|
||||
public class MapNameValueConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
try
|
||||
{
|
||||
var valueString = value as string;
|
||||
if (valueString == null)
|
||||
return string.Empty;
|
||||
|
||||
var name = GlobalizedApplication.Instance.GetResourceString(valueString);
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
return name;
|
||||
|
||||
name = GameData.FriendlyMapNameForClass(valueString, true);
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
return name;
|
||||
|
||||
var mapName = ModUtils.GetMapName(valueString);
|
||||
|
||||
// check if the name is stored in the globalization file
|
||||
name = GlobalizedApplication.Instance.GetResourceString(mapName);
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
return name;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(mapName))
|
||||
return mapName;
|
||||
|
||||
return valueString;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return value ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
160
src/ConanServerManager/Lib/ViewModel/PlayerInfo.cs
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
using ConanData;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ServerManagerTool.Lib.ViewModel
|
||||
{
|
||||
public class PlayerInfo : INotifyPropertyChanged
|
||||
{
|
||||
public PlayerInfo()
|
||||
{
|
||||
PlayerId = string.Empty;
|
||||
PlayerName = string.Empty;
|
||||
CharacterName = string.Empty;
|
||||
IsOnline = false;
|
||||
IsAdmin = false;
|
||||
IsWhitelisted = false;
|
||||
GuildName = string.Empty;
|
||||
IsValid = true;
|
||||
LastOnline = null;
|
||||
PlayerData = null;
|
||||
}
|
||||
|
||||
public string PlayerId
|
||||
{
|
||||
get { return Get<string>(); }
|
||||
set { Set(value); }
|
||||
}
|
||||
public string PlayerName
|
||||
{
|
||||
get { return Get<string>(); }
|
||||
set
|
||||
{
|
||||
Set(value);
|
||||
|
||||
PlatformNameFilterString = value?.ToLower();
|
||||
}
|
||||
}
|
||||
public string PlatformNameFilterString
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public long CharacterId
|
||||
{
|
||||
get { return Get<long>(); }
|
||||
set { Set(value); }
|
||||
}
|
||||
public string CharacterName
|
||||
{
|
||||
get { return Get<string>(); }
|
||||
set
|
||||
{
|
||||
Set(value);
|
||||
|
||||
CharacterNameFilterString = value?.ToLower();
|
||||
}
|
||||
}
|
||||
public string CharacterNameFilterString
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public bool IsOnline
|
||||
{
|
||||
get { return Get<bool>(); }
|
||||
set { Set(value); }
|
||||
}
|
||||
public bool IsAdmin
|
||||
{
|
||||
get { return Get<bool>(); }
|
||||
set { Set(value); }
|
||||
}
|
||||
public bool IsWhitelisted
|
||||
{
|
||||
get { return Get<bool>(); }
|
||||
set { Set(value); }
|
||||
}
|
||||
public string GuildName
|
||||
{
|
||||
get { return Get<string>(); }
|
||||
set
|
||||
{
|
||||
Set(value);
|
||||
|
||||
GuildNameFilterString = value?.ToLower();
|
||||
}
|
||||
}
|
||||
public string GuildNameFilterString
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public bool IsValid
|
||||
{
|
||||
get { return Get<bool>(); }
|
||||
set { Set(value); }
|
||||
}
|
||||
public int? LastOnline
|
||||
{
|
||||
get { return Get<int?>(); }
|
||||
set { Set(value); }
|
||||
}
|
||||
public PlayerData PlayerData
|
||||
{
|
||||
get { return Get<PlayerData>(); }
|
||||
set { Set(value); }
|
||||
}
|
||||
|
||||
public void UpdateData(PlayerData playerData)
|
||||
{
|
||||
this.PlayerData = playerData;
|
||||
this.PlayerId = playerData?.PlayerId;
|
||||
this.CharacterId = playerData?.CharacterId ?? 0L;
|
||||
this.CharacterName = playerData?.CharacterName;
|
||||
this.GuildName = playerData?.Guild?.GuildName;
|
||||
this.IsOnline = playerData?.Online ?? false;
|
||||
this.LastOnline = playerData?.LastOnline;
|
||||
}
|
||||
|
||||
public void UpdatePlatformData(PlayerData playerData)
|
||||
{
|
||||
if (playerData == null)
|
||||
return;
|
||||
|
||||
playerData.PlayerName = PlayerData?.PlayerName;
|
||||
playerData.LastPlatformUpdateUtc = PlayerData?.LastPlatformUpdateUtc ?? DateTime.MinValue;
|
||||
}
|
||||
|
||||
#region INotifyPropertyChanged
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private Dictionary<string, object> _properties = new Dictionary<string, object>();
|
||||
|
||||
protected T Get<T>([CallerMemberName] string name = null)
|
||||
{
|
||||
object value = null;
|
||||
if (_properties?.TryGetValue(name, out value) ?? false)
|
||||
return value == null ? default : (T)value;
|
||||
return default;
|
||||
}
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
protected void Set<T>(T value, [CallerMemberName] string name = null)
|
||||
{
|
||||
if (Equals(value, Get<T>(name)))
|
||||
return;
|
||||
if (_properties == null)
|
||||
_properties = new Dictionary<string, object>();
|
||||
_properties[name] = value;
|
||||
OnPropertyChanged(name);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
75
src/ConanServerManager/NLog.config
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<variable name="logDir" value=""/>
|
||||
|
||||
<targets>
|
||||
<target name="debug"
|
||||
xsi:type="Debugger"
|
||||
layout="${time} DEBUG: ${message}"
|
||||
/>
|
||||
<target name="error"
|
||||
xsi:type="Debugger"
|
||||
layout="${time} ERROR: ${message}"
|
||||
/>
|
||||
<target name="debugFile" xsi:type="File"
|
||||
fileName="${logDir}/ServerManager_Debug.log"
|
||||
layout="${time} ${message}"
|
||||
archiveFileName="${logDir}/ServerManager_Debug.{#}.log"
|
||||
archiveNumbering="DateAndSequence"
|
||||
archiveEvery="Day"
|
||||
archiveDateFormat="yyyyMMdd"
|
||||
maxArchiveFiles="30"
|
||||
/>
|
||||
<target name="errorFile" xsi:type="File"
|
||||
fileName="${logDir}/ServerManager_Error.log"
|
||||
layout="${time} ${message}"
|
||||
archiveFileName="${logDir}/ServerManager_Error.{#}.log"
|
||||
archiveNumbering="DateAndSequence"
|
||||
archiveEvery="Day"
|
||||
archiveDateFormat="yyyyMMdd"
|
||||
maxArchiveFiles="30"
|
||||
/>
|
||||
<target name="scripts" xsi:type="File"
|
||||
fileName="${logDir}/ServerManager_Scripts.log"
|
||||
layout="${time} ${message}"
|
||||
archiveFileName="${logDir}/ServerManager_Scripts.{#}.log"
|
||||
archiveNumbering="DateAndSequence"
|
||||
archiveEvery="Day"
|
||||
archiveDateFormat="yyyyMMdd"
|
||||
maxArchiveFiles="30"
|
||||
/>
|
||||
<target name="statuswatcher" xsi:type="File"
|
||||
fileName="${logDir}/ServerManager_ServerStatus.log"
|
||||
layout="${time} ${message}"
|
||||
archiveFileName="${logDir}/ServerManager_ServerStatus.{#}.log"
|
||||
archiveNumbering="DateAndSequence"
|
||||
archiveEvery="Day"
|
||||
archiveDateFormat="yyyyMMdd"
|
||||
maxArchiveFiles="30"
|
||||
/>
|
||||
<target name="taskscheduler" xsi:type="File"
|
||||
fileName="${logDir}/ServerManager_TaskScheduler.log"
|
||||
layout="${time} ${message}"
|
||||
archiveFileName="${logDir}/ServerManager_TaskScheduler.{#}.log"
|
||||
archiveNumbering="DateAndSequence"
|
||||
archiveEvery="Day"
|
||||
archiveDateFormat="yyyyMMdd"
|
||||
maxArchiveFiles="30"
|
||||
/>
|
||||
</targets>
|
||||
|
||||
<rules>
|
||||
<logger enabled="false" name="*" maxlevel="debug" writeTo="debug"/>
|
||||
<logger enabled="false" name="*" minlevel="error" writeTo="error"/>
|
||||
|
||||
<logger enabled="false" name="*" maxlevel="debug" writeTo="debugFile"/>
|
||||
<logger enabled="true" name="*" minlevel="error" writeTo="errorFile"/>
|
||||
|
||||
<logger enabled="true" name="ServerManagerTool.Common.Utils.ScriptUtils" minlevel="info" writeTo="scripts"/>
|
||||
<logger enabled="true" name="ServerManagerTool.Common.Utils.TaskSchedulerUtils" minlevel="info" writeTo="taskscheduler"/>
|
||||
<logger enabled="true" name="ServerManagerTool.Lib.ServerStatusWatcher" minlevel="info" writeTo="statuswatcher"/>
|
||||
</rules>
|
||||
|
||||
</nlog>
|
||||
55
src/ConanServerManager/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Conan Exiles™ Server Manager")]
|
||||
[assembly: AssemblyDescription("The server manager makes it easy to setup and manage your Conan Exiles™ dedicated servers.")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Bletch1971")]
|
||||
[assembly: AssemblyProduct("Server Managers")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015-2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
//where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.None,
|
||||
//where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0")]
|
||||
[assembly: AssemblyVersion("1.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.1")]
|
||||
54
src/ConanServerManager/Properties/app.manifest
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<!-- UAC Manifest Options
|
||||
If you want to change the Windows User Account Control level replace the
|
||||
requestedExecutionLevel node with one of the following.
|
||||
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||
|
||||
Specifying requestedExecutionLevel node will disable file and registry virtualization.
|
||||
If you want to utilize File and Registry Virtualization for backward
|
||||
compatibility then delete the requestedExecutionLevel node.
|
||||
-->
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
<applicationRequestMinimum>
|
||||
<defaultAssemblyRequest permissionSetReference="Custom" />
|
||||
<PermissionSet class="System.Security.PermissionSet" version="1" ID="Custom" SameSite="site" Unrestricted="true" />
|
||||
</applicationRequestMinimum>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of all Windows versions that this application is designed to work with.
|
||||
Windows will automatically select the most compatible environment.-->
|
||||
<!-- If your application is designed to work with Windows Vista, uncomment the following supportedOS node-->
|
||||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>-->
|
||||
<!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
|
||||
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->
|
||||
<!-- If your application is designed to work with Windows 8, uncomment the following supportedOS node-->
|
||||
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>-->
|
||||
<!-- If your application is designed to work with Windows 8.1, uncomment the following supportedOS node-->
|
||||
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>-->
|
||||
</application>
|
||||
</compatibility>
|
||||
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
|
||||
<!-- <dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>-->
|
||||
</asmv1:assembly>
|
||||
55
src/ConanServerManager/Styles/Default.xaml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<Globalization:StyleResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:Globalization="clr-namespace:WPFSharp.Globalizer;assembly=WPFSharp.Globalizer"
|
||||
Name="Default">
|
||||
|
||||
<!--<FlowDirection x:Key="FlowDirection_Default">LeftToRight</FlowDirection>
|
||||
<FlowDirection x:Key="FlowDirection_Reverse">RightToLeft</FlowDirection>-->
|
||||
|
||||
<!--<sys:Double x:Key="CommonFontSize">12</sys:Double>-->
|
||||
|
||||
<SolidColorBrush x:Key="SolidBackground" Color="White" />
|
||||
|
||||
<!--BeigeGradient-->
|
||||
<LinearGradientBrush x:Key="GradientBackground" EndPoint="0.5,1" StartPoint="0.5,0">
|
||||
<GradientStop Color="#FFECE1D4" Offset="1"/>
|
||||
<GradientStop Color="#FFEAE8E6"/>
|
||||
</LinearGradientBrush>
|
||||
|
||||
|
||||
<!--Generic control styles-->
|
||||
<Style TargetType="{x:Type Label}">
|
||||
<Setter Property="Foreground" Value="Black" />
|
||||
</Style>
|
||||
|
||||
<!--Named styles-->
|
||||
<Style x:Key="BorderLabel" TargetType="{x:Type Border}">
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Width" Value="Auto"/>
|
||||
<Setter Property="Height" Value="Auto"/>
|
||||
<Setter Property="BorderBrush" Value="#FFD8CCBC"/>
|
||||
<Setter Property="Background" Value="#FFE6DFD8"/>
|
||||
</Style>
|
||||
|
||||
|
||||
<!--AnnotatedSlider-->
|
||||
<SolidColorBrush x:Key="SliderThumb.Static.Foreground" Color="#FFE5E5E5"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.MouseOver.Background" Color="#FFDCECFC"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.MouseOver.Border" Color="#FF7Eb4EA"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Pressed.Background" Color="#FFDAECFC"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Pressed.Border" Color="#FF569DE5"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Disabled.Background" Color="#FFF0F0F0"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Disabled.Border" Color="#FFD9D9D9"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Static.Background" Color="#FFF0F0F0"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Static.Border" Color="#FFACACAC"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Track.Border" Color="#FFD6D6D6"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Track.BorderBackground" Color="#FFE7EAEA"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Grip.Fill" Color="#FFE6DFD8"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Tick.Bottom" Color="#FFD8CCBC"/>
|
||||
<SolidColorBrush x:Key="SliderThumb.Track.Background" Color="#FFBFA786"/>
|
||||
|
||||
<SolidColorBrush x:Key="WarningMessage" Color="Red"/>
|
||||
|
||||
</Globalization:StyleResourceDictionary>
|
||||
183
src/ConanServerManager/Utils/ModUtils.cs
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
using ServerManagerTool.Common;
|
||||
using ServerManagerTool.Common.Lib;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace ServerManagerTool.Utils
|
||||
{
|
||||
public static class ModUtils
|
||||
{
|
||||
public const string MODTYPE_UNKNOWN = "0";
|
||||
public const string MODTYPE_MOD = "1";
|
||||
public const string MODTYPE_MAP = "2";
|
||||
|
||||
public static void CopyMod(string sourceFolder, string destinationFolder, string modId, ProgressDelegate progressCallback)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sourceFolder))
|
||||
throw new DirectoryNotFoundException($"Source folder must be specified.");
|
||||
if (!Directory.Exists(sourceFolder))
|
||||
throw new DirectoryNotFoundException($"Source folder was not found.\r\n{sourceFolder}");
|
||||
if (string.IsNullOrWhiteSpace(destinationFolder))
|
||||
throw new DirectoryNotFoundException($"Destination folder must be specified.");
|
||||
|
||||
var modFileName = $"{modId}.pak";
|
||||
var modFile = IOUtils.NormalizePath(Path.Combine(destinationFolder, modFileName));
|
||||
var timeFileName = $"{modId}.txt";
|
||||
var timeFile = IOUtils.NormalizePath(Path.Combine(destinationFolder, timeFileName));
|
||||
|
||||
progressCallback?.Invoke(0, "Deleting existing mod files.");
|
||||
|
||||
// delete the server mod file.
|
||||
if (File.Exists(modFile))
|
||||
File.Delete(modFile);
|
||||
if (File.Exists(timeFile))
|
||||
File.Delete(timeFile);
|
||||
|
||||
progressCallback?.Invoke(0, "Copying mod files.");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(destinationFolder) || !Directory.Exists(destinationFolder))
|
||||
Directory.CreateDirectory(destinationFolder);
|
||||
|
||||
// update the mod files from the cache.
|
||||
foreach (var sourceFile in Directory.GetFiles(sourceFolder, "*.pak", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
File.Copy(sourceFile, modFile, true);
|
||||
}
|
||||
|
||||
// copy the last updated file.
|
||||
var fileName = IOUtils.NormalizePath(Path.Combine(sourceFolder, Config.Default.LastUpdatedTimeFile));
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
progressCallback?.Invoke(0, "Copying mod version file.");
|
||||
|
||||
File.Copy(fileName, timeFile, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CreateModListFile(string installDirectory, List<string> modIdList)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(installDirectory) || !Directory.Exists(installDirectory))
|
||||
return;
|
||||
|
||||
// get the folder/file details
|
||||
var modRootFolder = GetModRootPath(installDirectory);
|
||||
var modListFileName = Config.Default.ServerModListFile;
|
||||
var modListFile = IOUtils.NormalizePath(Path.Combine(modRootFolder, modListFileName));
|
||||
|
||||
// check if any mods to write
|
||||
if (modIdList == null || modIdList.Count == 0)
|
||||
{
|
||||
// no mods, check if foldler exists
|
||||
if (!Directory.Exists(modRootFolder))
|
||||
return;
|
||||
|
||||
// check if the file exists, if so then delete it.
|
||||
if (File.Exists(modListFile))
|
||||
File.Delete(modListFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if the folder exists, if not then create it.
|
||||
if (!Directory.Exists(modRootFolder))
|
||||
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();
|
||||
// create the mod file.
|
||||
File.WriteAllLines(modListFile, modFileItems);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetLatestModCacheTimeFile(string modId) => IOUtils.NormalizePath(Path.Combine(GetModCachePath(modId), Config.Default.LastUpdatedTimeFile));
|
||||
|
||||
public static string GetLatestModTimeFile(string installDirectory, string modId) => IOUtils.NormalizePath(Path.Combine(installDirectory, Config.Default.ServerModsRelativePath, $"{modId}.txt"));
|
||||
|
||||
public static string GetMapName(string serverMap)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(serverMap))
|
||||
return string.Empty;
|
||||
|
||||
return serverMap.Trim();
|
||||
}
|
||||
|
||||
public static string GetModCachePath(string modId) => IOUtils.NormalizePath(Path.Combine(Config.Default.DataPath, CommonConfig.Default.SteamCmdRelativePath, Config.Default.AppSteamWorkshopFolderRelativePath, modId));
|
||||
|
||||
public static List<string> GetModIdList(string modIds)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(modIds))
|
||||
return new List<string>();
|
||||
|
||||
return modIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
}
|
||||
|
||||
public static int GetModLatestTime(string timeFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(timeFile))
|
||||
return 0;
|
||||
|
||||
var value = File.ReadAllText(timeFile);
|
||||
|
||||
int unixTime;
|
||||
return int.TryParse(value, out unixTime) ? unixTime : 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetModRootPath(string installDirectory) => IOUtils.NormalizePath(Path.Combine(installDirectory, Config.Default.ServerModsRelativePath));
|
||||
|
||||
public static string GetModPath(string installDirectory, string modId) => GetModRootPath(installDirectory);
|
||||
|
||||
public static string GetSteamManifestFile(string installDirectory) => IOUtils.NormalizePath(Path.Combine(installDirectory, Config.Default.SteamManifestFolderRelativePath, Config.Default.AppSteamManifestFile));
|
||||
|
||||
public static string GetSteamWorkshopFile() => IOUtils.NormalizePath(Path.Combine(Config.Default.DataPath, CommonConfig.Default.SteamCmdRelativePath, Config.Default.SteamWorkshopFolderRelativePath, Config.Default.AppSteamWorkshopFile));
|
||||
|
||||
public static int GetSteamWorkshopLatestTime(string workshopFile, string modId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = SteamUtils.ReadSteamCmdAppWorkshopFile(workshopFile);
|
||||
if (result == null)
|
||||
return 0;
|
||||
|
||||
var detail = result.WorkshopItemDetails.FirstOrDefault(v => v.publishedfileid.Equals(modId));
|
||||
if (detail == null)
|
||||
return 0;
|
||||
|
||||
int unixTime;
|
||||
return int.TryParse(detail.timeupdated, out unixTime) ? unixTime : 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsOfficialMod(string modId)
|
||||
{
|
||||
switch (modId)
|
||||
{
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<string> ValidateModList(List<string> modIdList)
|
||||
{
|
||||
// remove all duplicate mod ids.
|
||||
var newModIdList = modIdList.Distinct().ToList();
|
||||
|
||||
// remove any official mods.
|
||||
|
||||
return newModIdList;
|
||||
}
|
||||
}
|
||||
}
|
||||
1348
src/ConanServerManager/VersionFeed.xml
Normal file
33
src/ConanServerManager/VersionFeedBeta.xml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
|
||||
<id>urn:uuid:F9268CD1-3230-46A7-BD1D-023A2620A33B</id>
|
||||
<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>2020-11-25T00:00:00Z</updated>
|
||||
|
||||
<entry>
|
||||
<id>urn:uuid:6914861A-2D4E-4F08-89A3-D3D7A77F74C1</id>
|
||||
<title>1.1.50 (1.1.50.1)</title>
|
||||
<summary>1.1.50.1</summary>
|
||||
<link href="" />
|
||||
<updated>2020-11-25T00: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 - Added option to automatically manage the Public IP, default to True. If disabled, then the Public IP must be updated manually.</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</content>
|
||||
<author>
|
||||
<name>bletch</name>
|
||||
<email>bletch1971@hotmail.com</email>
|
||||
</author>
|
||||
</entry>
|
||||
|
||||
</feed>
|
||||
31
src/ConanServerManager/Windows/AddUserWindow.xaml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<Window x:Class="ServerManagerTool.AddUserWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
MinHeight="200" Width="300" Height="200" WindowStyle="ToolWindow" WindowStartupLocation="CenterOwner" ShowInTaskbar="False" ResizeMode="CanResize"
|
||||
Icon="../Art/favicon.ico" Title="{DynamicResource AddUser_Title}">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="..\Globalization\en-US\en-US.xaml"/>
|
||||
<ResourceDictionary Source="..\Styles\Default.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Background="{StaticResource GradientBackground}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBox Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Users, Mode=TwoWay}" Margin="5,5,5,0" TextWrapping="NoWrap" VerticalScrollBarVisibility="Auto" AcceptsReturn="true"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="5,5,5,0" Text="{DynamicResource AddUser_InstructionLabel}" VerticalAlignment="Center" TextWrapping="Wrap" />
|
||||
<Button Grid.Row="2" Grid.Column="0" Content="{DynamicResource AddUser_ProcessButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Right" Click="Process_Click"/>
|
||||
<Button Grid.Row="2" Grid.Column="1" Content="{DynamicResource AddUser_CancelButtonLabel}" Margin="5" MinWidth="75" HorizontalAlignment="Left" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
||||