├── SolutionResources ├── .gitignore ├── ClientSecrets.cs ├── ServerSecrets.cs └── README.md ├── img ├── firewall-1.png ├── router-1.png ├── router-2.png ├── vsg_logo_16.png ├── vsg_logo_256.png ├── vds-install-1.png ├── vds-install-2.png ├── vsg_logo_social.png ├── Screenshot-Players.png ├── old │ └── v1 │ │ ├── Screenshot-Logs.png │ │ ├── Screenshot-Players.png │ │ ├── Screenshot-ServerControls.png │ │ └── Screenshot-ServerDetails.png ├── Screenshot-ServerControls.png ├── Screenshot-ServerDetails.png └── Screenshot-AdvancedControls.png ├── ValheimServerGUI.Serverless ├── appsettings.Development.json ├── appsettings.json ├── Services │ ├── ServerlessLogger.cs │ ├── XboxApiClient.cs │ └── SteamApiClient.cs ├── Properties │ └── launchSettings.json ├── Dockerfile ├── aws-lambda-tools-defaults.json ├── LocalEntryPoint.cs ├── Middleware │ └── RuneberryAuthMiddleware.cs ├── ValheimServerGUI.Serverless.csproj ├── Startup.cs ├── serverless.template └── LambdaEntryPoint.cs ├── ValheimServerGUI ├── Resources │ ├── Add_16x.png │ ├── Run_16x.png │ ├── Copy_16x.png │ ├── Edit_16x.png │ ├── Save_16x.png │ ├── Steam_16x.png │ ├── Stop_16x.png │ ├── Cancel_16x.png │ ├── DiscordLogo.png │ ├── DonateLogo.png │ ├── GitHubLogo.png │ ├── Loading_16x.png │ ├── NewBug_16x.png │ ├── NewFile_16x.png │ ├── OpenFile_16x.png │ ├── OpenWeb_16x.png │ ├── Restart_16x.png │ ├── Settings_16x.png │ ├── StatusOK_16x.png │ ├── XboxLive_16x.png │ ├── vsg_logo_16.png │ ├── OpenFolder_16x.png │ ├── Remove_Red_16x.png │ ├── RuneberryLogo.png │ ├── StatusRun_16x.png │ ├── StatusStop_16x.png │ ├── ApplicationIcon.ico │ ├── Loading_Blue_16x.png │ ├── Restart_grey_16x.png │ ├── StatusAlert_16x.png │ ├── StatusWarning_16x.png │ ├── AddImmediateWindow_16x.png │ ├── FolderInformation_16x.png │ ├── StartWithoutDebug_16x.png │ ├── StatusInformation_16x.png │ ├── StatusNotStarted_16x.png │ ├── StatusPause_grey_16x.png │ ├── StatusCriticalError_16x.png │ └── UnsyncedCommits_16x_Horiz.png ├── post-publish.bat ├── Game │ ├── PlayerStatus.cs │ ├── ServerStatus.cs │ ├── StartupArgsProvider.cs │ ├── WorldGenKeys.cs │ ├── WorldPreferencesFile.cs │ ├── WorldGenPresets.cs │ ├── WorldPreferences.cs │ ├── ServerPreferencesFile.cs │ ├── UserPreferencesFile.cs │ └── ValheimPathExtensions.cs ├── Tools │ ├── Logging │ │ ├── LogViews.cs │ │ ├── Components │ │ │ ├── LogBufferSink.cs │ │ │ ├── TimestampTransformer.cs │ │ │ ├── LogLevelTransformer.cs │ │ │ ├── RegexTransformer.cs │ │ │ ├── RollingFileSink.cs │ │ │ └── RegexFilter.cs │ │ ├── LogRule.cs │ │ ├── ValheimServerLogger.cs │ │ └── ApplicationLogger.cs │ ├── ExceptionExtensions.cs │ ├── FormProvider.cs │ ├── TimeFormats.cs │ ├── OpenHelper.cs │ ├── GitHubClient.cs │ ├── PathExtensions.cs │ └── RuneberryApiClient.cs ├── Properties │ └── PublishProfiles │ │ ├── small-x64-debug.pubxml │ │ └── small-x64-release.pubxml ├── Controls │ ├── EditButton.cs │ ├── RefreshButton.cs │ ├── SettingsButton.cs │ ├── CopyButton.cs │ ├── OpenButton.cs │ ├── SettingsButton.Designer.cs │ ├── CopyButton.Designer.cs │ ├── OpenButton.Designer.cs │ ├── EditButton.Designer.cs │ ├── RefreshButton.Designer.cs │ ├── CopyButton.resx │ ├── EditButton.resx │ ├── OpenButton.resx │ └── RefreshButton.resx ├── Forms │ ├── AboutForm.cs │ ├── AboutForm.resx │ ├── SplashForm.resx │ └── TextPromptPopout.resx └── ValheimServerGUI.csproj ├── ValheimServerGUI.Tools ├── Delegates.cs ├── Data │ ├── IPrimaryKeyEntity.cs │ ├── IFileProvider.cs │ ├── JsonDataFile.cs │ ├── DataFileProviderExtensions.cs │ ├── DataFileRepositoryContext.cs │ └── IDataRepository.cs ├── Processes │ ├── IProcessProvider.cs │ ├── ProcessProvider.cs │ └── ProcessExtensions.cs ├── Models │ ├── ErrorResponse.cs │ ├── PlayerInfoResponse.cs │ ├── PlayerPlatforms.cs │ └── CrashReport.cs ├── Http │ ├── HttpClientProvider.cs │ ├── RestClientContext.cs │ ├── RestClient.cs │ └── RestClientRequestExtensions.cs ├── ValheimServerGUI.Tools.csproj ├── DictionaryExtensions.cs ├── ObjectExtensions.cs └── Logging │ └── ConcurrentBuffer.cs ├── ValheimServerGUI.Serverless.Tests ├── appsettings.json ├── Properties │ └── launchSettings.json ├── SampleRequests │ └── ValuesController-Get.json ├── ValuesControllerTests.cs └── ValheimServerGUI.Serverless.Tests.csproj ├── ValheimServerGUI.Tests ├── Forms │ ├── MainWindowTests.cs │ └── SplashFormTests.cs ├── Tools │ ├── MockProcessProvider.cs │ ├── MockUserPreferencesProvider.cs │ ├── MockDataFileProvider.cs │ └── MockHttpClientProvider.cs ├── ValheimServerGUI.Tests.csproj ├── BaseTest.Events.cs └── BaseTest.cs ├── ValheimServerGUI.Controls ├── IFormField.cs ├── ValheimServerGUI.Controls.csproj ├── Extensions │ └── ControlExtensions.cs └── Controls │ ├── HelpLabel.cs │ ├── CheckboxFormField.cs │ ├── TextFormField.cs │ ├── NumericFormField.cs │ ├── IconButton.cs │ ├── RadioFormField.cs │ ├── IconButton.Designer.cs │ ├── LabelField.cs │ ├── LogViewer.Designer.cs │ ├── HelpLabel.Designer.cs │ ├── DataListView.resx │ ├── HelpLabel.resx │ ├── IconButton.resx │ ├── LabelField.resx │ ├── LogViewer.resx │ ├── TextFormField.resx │ ├── CheckboxFormField.resx │ ├── DropdownFormField.resx │ ├── FilenameFormField.resx │ ├── NumericFormField.resx │ ├── RadioFormField.resx │ └── DataListView.Designer.cs └── .github └── workflows └── default.yml /SolutionResources/.gitignore: -------------------------------------------------------------------------------- 1 | ValheimServerGUI.snk 2 | appsettings.local.json 3 | *Secrets.*.cs -------------------------------------------------------------------------------- /img/firewall-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/firewall-1.png -------------------------------------------------------------------------------- /img/router-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/router-1.png -------------------------------------------------------------------------------- /img/router-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/router-2.png -------------------------------------------------------------------------------- /img/vsg_logo_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/vsg_logo_16.png -------------------------------------------------------------------------------- /img/vsg_logo_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/vsg_logo_256.png -------------------------------------------------------------------------------- /img/vds-install-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/vds-install-1.png -------------------------------------------------------------------------------- /img/vds-install-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/vds-install-2.png -------------------------------------------------------------------------------- /img/vsg_logo_social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/vsg_logo_social.png -------------------------------------------------------------------------------- /img/Screenshot-Players.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/Screenshot-Players.png -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWS": { 3 | "Region": "DefaultRegion" 4 | } 5 | } -------------------------------------------------------------------------------- /img/old/v1/Screenshot-Logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/old/v1/Screenshot-Logs.png -------------------------------------------------------------------------------- /img/Screenshot-ServerControls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/Screenshot-ServerControls.png -------------------------------------------------------------------------------- /img/Screenshot-ServerDetails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/Screenshot-ServerDetails.png -------------------------------------------------------------------------------- /img/old/v1/Screenshot-Players.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/old/v1/Screenshot-Players.png -------------------------------------------------------------------------------- /img/Screenshot-AdvancedControls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/Screenshot-AdvancedControls.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Add_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Add_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Run_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Run_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Copy_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Copy_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Edit_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Edit_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Save_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Save_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Steam_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Steam_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Stop_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Stop_16x.png -------------------------------------------------------------------------------- /img/old/v1/Screenshot-ServerControls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/old/v1/Screenshot-ServerControls.png -------------------------------------------------------------------------------- /img/old/v1/Screenshot-ServerDetails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/img/old/v1/Screenshot-ServerDetails.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Cancel_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Cancel_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/DiscordLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/DiscordLogo.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/DonateLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/DonateLogo.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/GitHubLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/GitHubLogo.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Loading_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Loading_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/NewBug_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/NewBug_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/NewFile_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/NewFile_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/OpenFile_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/OpenFile_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/OpenWeb_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/OpenWeb_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Restart_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Restart_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Settings_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Settings_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StatusOK_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StatusOK_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/XboxLive_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/XboxLive_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/vsg_logo_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/vsg_logo_16.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/OpenFolder_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/OpenFolder_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Remove_Red_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Remove_Red_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/RuneberryLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/RuneberryLogo.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StatusRun_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StatusRun_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StatusStop_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StatusStop_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/ApplicationIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/ApplicationIcon.ico -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Loading_Blue_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Loading_Blue_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/Restart_grey_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/Restart_grey_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StatusAlert_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StatusAlert_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StatusWarning_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StatusWarning_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/AddImmediateWindow_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/AddImmediateWindow_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/FolderInformation_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/FolderInformation_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StartWithoutDebug_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StartWithoutDebug_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StatusInformation_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StatusInformation_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StatusNotStarted_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StatusNotStarted_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StatusPause_grey_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StatusPause_grey_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/StatusCriticalError_16x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/StatusCriticalError_16x.png -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Delegates.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Tools 2 | { 3 | public delegate void KeyValueEventHandler(object sender, string key, string value); 4 | } 5 | -------------------------------------------------------------------------------- /ValheimServerGUI/Resources/UnsyncedCommits_16x_Horiz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runeberry/ValheimServerGUI/HEAD/ValheimServerGUI/Resources/UnsyncedCommits_16x_Horiz.png -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Data/IPrimaryKeyEntity.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Tools.Data 2 | { 3 | public interface IPrimaryKeyEntity 4 | { 5 | public string Key { get; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ValheimServerGUI/post-publish.bat: -------------------------------------------------------------------------------- 1 | signtool.exe sign /tr http://timestamp.digicert.com /fd sha256 /td sha256 /sm /sha1 "965524420735aa0b37db63f217f9d2f3e1899071" /d "Valheim Server GUI" ..\publish\small-x64\ValheimServerGUI.exe -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information" 5 | } 6 | }, 7 | "S3BucketName": "runeberry-valheim-server-gui", 8 | "S3BucketRegion": "us-east-1" 9 | } -------------------------------------------------------------------------------- /ValheimServerGUI/Game/PlayerStatus.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Game 2 | { 3 | public enum PlayerStatus 4 | { 5 | Offline = 0, 6 | Joining = 1, 7 | Online = 2, 8 | Leaving = 3, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ValheimServerGUI/Game/ServerStatus.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Game 2 | { 3 | public enum ServerStatus 4 | { 5 | Stopped = 0, 6 | Starting = 1, 7 | Running = 2, 8 | Stopping = 3, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/LogViews.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Tools.Logging 2 | { 3 | public static class LogViews 4 | { 5 | public const string Application = "Application"; 6 | 7 | public const string Server = "Server"; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless.Tests/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Lambda.Logging": { 3 | "IncludeCategory": false, 4 | "IncludeLogLevel": false, 5 | "IncludeNewline": true, 6 | "LogLevel": { 7 | "Default": "Debug", 8 | "Microsoft": "Information" 9 | } 10 | }, 11 | "AWS": { 12 | "Region": "DefaultRegion" 13 | } 14 | } -------------------------------------------------------------------------------- /ValheimServerGUI.Tests/Forms/MainWindowTests.cs: -------------------------------------------------------------------------------- 1 | using ValheimServerGUI.Forms; 2 | using Xunit; 3 | 4 | namespace ValheimServerGUI.Tests.Forms 5 | { 6 | public class MainWindowTests : BaseTest 7 | { 8 | [Fact] 9 | public void CanConstructMainWindow() 10 | { 11 | GetForm(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Processes/IProcessProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace ValheimServerGUI.Tools.Processes 4 | { 5 | public interface IProcessProvider 6 | { 7 | void AddProcess(string key, Process process); 8 | 9 | Process GetProcess(string key); 10 | 11 | void StartIO(Process process); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Models/ErrorResponse.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace ValheimServerGUI.Tools.Models 4 | { 5 | public class ErrorResponse 6 | { 7 | public ErrorResponse(string message) 8 | { 9 | Message = message; 10 | } 11 | 12 | [JsonProperty("message")] 13 | public string Message { get; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/Services/ServerlessLogger.cs: -------------------------------------------------------------------------------- 1 | using Amazon.Lambda.Core; 2 | using Serilog; 3 | using Serilog.Events; 4 | 5 | namespace ValheimServerGUI.Serverless.Services 6 | { 7 | public class ServerlessLogger : ILogger 8 | { 9 | public void Write(LogEvent logEvent) 10 | { 11 | LambdaLogger.Log(logEvent.RenderMessage()); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/IFormField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ValheimServerGUI 4 | { 5 | public interface IFormField 6 | { 7 | string LabelText { get; set; } 8 | 9 | string HelpText { get; set; } 10 | } 11 | 12 | public interface IFormField : IFormField 13 | { 14 | T Value { get; set; } 15 | 16 | event EventHandler ValueChanged; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tests/Forms/SplashFormTests.cs: -------------------------------------------------------------------------------- 1 | using ValheimServerGUI.Forms; 2 | using Xunit; 3 | 4 | namespace ValheimServerGUI.Tests.Forms 5 | { 6 | public class SplashFormTests : BaseTest 7 | { 8 | public SplashFormTests() 9 | { 10 | } 11 | 12 | [Fact] 13 | public void CanConstructSplashForm() 14 | { 15 | GetForm(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Http/HttpClientProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | 3 | namespace ValheimServerGUI.Tools.Http 4 | { 5 | public interface IHttpClientProvider 6 | { 7 | public HttpClient CreateClient(); 8 | } 9 | 10 | public class HttpClientProvider : IHttpClientProvider 11 | { 12 | public HttpClient CreateClient() 13 | { 14 | return new HttpClient(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Data/IFileProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace ValheimServerGUI.Tools.Data 5 | { 6 | public interface IFileProvider 7 | { 8 | event EventHandler DataLoaded; 9 | 10 | event EventHandler DataSaved; 11 | 12 | Task LoadAsync(string filePath) where TFile : class; 13 | 14 | Task SaveAsync(string filePath, TFile data) where TFile : class; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/ExceptionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ValheimServerGUI.Tools 4 | { 5 | public static class ExceptionExtensions 6 | { 7 | public static Exception GetPrimaryException(this Exception exception) 8 | { 9 | if (exception is AggregateException agg) 10 | { 11 | return agg.InnerException.GetPrimaryException() ?? agg; 12 | } 13 | 14 | return exception; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Data/JsonDataFile.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace ValheimServerGUI.Tools.Data 5 | { 6 | public class JsonDataFile 7 | { 8 | public JsonDataFile() 9 | { 10 | } 11 | 12 | public JsonDataFile(Dictionary data) 13 | { 14 | Data = data; 15 | } 16 | 17 | [JsonProperty("data")] 18 | public Dictionary Data { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/ValheimServerGUI.Tools.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | true 8 | ..\SolutionResources\ValheimServerGUI.snk 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless.Tests/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "IIS Express": { 4 | "commandName": "IISExpress", 5 | "launchBrowser": true, 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | } 9 | }, 10 | "ValheimServerGUI.Serverless.Tests": { 11 | "commandName": "Project" 12 | } 13 | }, 14 | "iisSettings": { 15 | "windowsAuthentication": false, 16 | "anonymousAuthentication": true, 17 | "iisExpress": { 18 | "applicationUrl": "http://localhost:55165/", 19 | "sslPort": 44357 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ValheimServerGUI/Game/StartupArgsProvider.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Game 2 | { 3 | public interface IStartupArgsProvider 4 | { 5 | public string ServerProfileName { get; } 6 | } 7 | 8 | public class StartupArgsProvider : IStartupArgsProvider 9 | { 10 | public StartupArgsProvider(string[] args) 11 | { 12 | if (args == null || args.Length == 0) return; 13 | ServerProfileName = args[0]; 14 | } 15 | 16 | #region IStartupArgsProvider implementation 17 | 18 | public string ServerProfileName { get; private set; } 19 | 20 | #endregion 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Models/PlayerInfoResponse.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace ValheimServerGUI.Tools.Models 4 | { 5 | public class PlayerInfoResponse 6 | { 7 | public PlayerInfoResponse(string platform, string id, string name) 8 | { 9 | Platform = platform; 10 | Id = id; 11 | Name = name; 12 | } 13 | 14 | [JsonProperty("id")] 15 | public string Id { get; set; } 16 | 17 | [JsonProperty("name")] 18 | public string Name { get; set; } 19 | 20 | [JsonProperty("platform")] 21 | public string Platform { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/Components/LogBufferSink.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Core; 2 | using Serilog.Events; 3 | using System.Collections.Generic; 4 | 5 | namespace ValheimServerGUI.Tools.Logging.Components 6 | { 7 | public class LogBufferSink : ILogEventSink 8 | { 9 | private readonly ConcurrentBuffer Buffer; 10 | 11 | public IEnumerable Logs => Buffer; 12 | 13 | public LogBufferSink(int bufferSize) 14 | { 15 | Buffer = new(bufferSize); 16 | } 17 | 18 | public void Emit(LogEvent logEvent) 19 | { 20 | Buffer.Enqueue(logEvent.RenderMessage()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Data/DataFileProviderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace ValheimServerGUI.Tools.Data 4 | { 5 | public static class DataFileProviderExtensions 6 | { 7 | public static void Load(this IFileProvider provider, string filePath) 8 | where TFile : class 9 | { 10 | Task.Run(() => provider.LoadAsync(filePath)); 11 | } 12 | 13 | public static void Save(this IFileProvider provider, string filePath, TFile data) 14 | where TFile : class 15 | { 16 | Task.Run(() => provider.SaveAsync(filePath, data)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Http/RestClientContext.cs: -------------------------------------------------------------------------------- 1 | using Serilog; 2 | 3 | namespace ValheimServerGUI.Tools.Http 4 | { 5 | public interface IRestClientContext 6 | { 7 | ILogger Logger { get; } 8 | 9 | IHttpClientProvider HttpClientProvider { get; } 10 | } 11 | 12 | public class RestClientContext : IRestClientContext 13 | { 14 | public ILogger Logger { get; } 15 | 16 | public IHttpClientProvider HttpClientProvider { get; } 17 | 18 | public RestClientContext(ILogger logger, IHttpClientProvider provider) 19 | { 20 | Logger = logger; 21 | HttpClientProvider = provider; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/DictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace ValheimServerGUI.Tools 5 | { 6 | public static class DictionaryExtensions 7 | { 8 | /// 9 | /// Returns a new dictionary where values become keys and vice-versa. 10 | /// Probably throws an exception if any values are duplicated (i.e. would create a duplicate key). 11 | /// 12 | public static Dictionary Invert(this Dictionary dictionary) 13 | { 14 | return dictionary.ToDictionary(kvp => kvp.Value, kvp => kvp.Key); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ValheimServerGUI/Properties/PublishProfiles/small-x64-debug.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Debug 8 | Any CPU 9 | ..\publish\small-x64\ 10 | FileSystem 11 | net6.0-windows 12 | win-x64 13 | False 14 | True 15 | True 16 | 17 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/ObjectExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ValheimServerGUI.Tools 4 | { 5 | public static class ObjectExtensions 6 | { 7 | public static bool IsAnyValue(this T value, params T[] allowedValues) 8 | { 9 | if (allowedValues == null || allowedValues.Length == 0) return false; 10 | 11 | foreach (var allowedValue in allowedValues) 12 | { 13 | if (EqualityComparer.Default.Equals(value, allowedValue)) 14 | { 15 | return true; 16 | } 17 | } 18 | 19 | return false; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ValheimServerGUI/Properties/PublishProfiles/small-x64-release.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | ..\publish\small-x64\ 10 | FileSystem 11 | net6.0-windows 12 | win-x64 13 | False 14 | True 15 | True 16 | 17 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/ValheimServerGUI.Controls.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0-windows 5 | true 6 | ValheimServerGUI 7 | 8 | 9 | true 10 | ..\SolutionResources\ValheimServerGUI.snk 11 | 12 | 13 | 14 | 15 | UserControl 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ValheimServerGUI/Game/WorldGenKeys.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ValheimServerGUI.Game 4 | { 5 | public static class WorldGenKeys 6 | { 7 | public const string NoBuildCost = "nobuildcost"; 8 | public const string PlayerEvents = "playerevents"; 9 | public const string PassiveMobs = "passivemobs"; 10 | public const string NoMap = "nomap"; 11 | public const string Fire = "fire"; 12 | 13 | public static readonly IReadOnlyList All = new List 14 | { 15 | NoBuildCost, 16 | PlayerEvents, 17 | PassiveMobs, 18 | NoMap, 19 | Fire, 20 | }; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Data/DataFileRepositoryContext.cs: -------------------------------------------------------------------------------- 1 | using Serilog; 2 | 3 | namespace ValheimServerGUI.Tools.Data 4 | { 5 | public interface IDataFileRepositoryContext 6 | { 7 | IFileProvider DataFileProvider { get; } 8 | 9 | ILogger Logger { get; } 10 | } 11 | 12 | public class DataFileRepositoryContext : IDataFileRepositoryContext 13 | { 14 | public IFileProvider DataFileProvider { get; } 15 | 16 | public ILogger Logger { get; } 17 | 18 | public DataFileRepositoryContext(IFileProvider dataFileProvider, ILogger logger) 19 | { 20 | DataFileProvider = dataFileProvider; 21 | Logger = logger; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ValheimServerGUI/Game/WorldPreferencesFile.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace ValheimServerGUI.Game 6 | { 7 | public class WorldPreferencesFile 8 | { 9 | [JsonProperty("worldName")] 10 | public string WorldName { get; set; } 11 | 12 | [JsonProperty("lastSaved")] 13 | public DateTime? LastSaved { get; set; } 14 | 15 | [JsonProperty("preset")] 16 | public string Preset { get; set; } 17 | 18 | [JsonProperty("modifiers")] 19 | public Dictionary Modifiers { get; set; } 20 | 21 | [JsonProperty("keys")] 22 | public List Keys { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/FormProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System; 3 | using System.Windows.Forms; 4 | 5 | namespace ValheimServerGUI.Tools 6 | { 7 | public class FormProvider : IFormProvider 8 | { 9 | private readonly IServiceProvider ServiceProvider; 10 | 11 | public FormProvider(IServiceProvider serviceProvider) 12 | { 13 | ServiceProvider = serviceProvider; 14 | } 15 | 16 | public T GetForm() where T : Form 17 | { 18 | return ServiceProvider.GetRequiredService(); 19 | } 20 | } 21 | 22 | public interface IFormProvider 23 | { 24 | T GetForm() where T : Form; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/default.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: .NET 5 | 6 | on: 7 | push: 8 | branches: [ $default-branch ] 9 | pull_request: 10 | branches: [ $default-branch ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Setup .NET 20 | uses: actions/setup-dotnet@v3 21 | with: 22 | dotnet-version: 6.0.x 23 | - name: Restore dependencies 24 | run: dotnet restore 25 | - name: Build 26 | run: dotnet build --no-restore 27 | - name: Test 28 | run: dotnet test --no-build --verbosity normal -------------------------------------------------------------------------------- /SolutionResources/ClientSecrets.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Properties 2 | { 3 | /// 4 | /// The values in this class are populated by the static constructor in the corresponding 5 | /// partial class, which is kept out of source control. 6 | /// 7 | public static partial class ClientSecrets 8 | { 9 | /// 10 | /// The HTTP header that will contain the API key for requests made to the Runeberry API. 11 | /// 12 | public static string RuneberryApiKeyHeader { get; } = string.Empty; 13 | 14 | /// 15 | /// The API key that will be attached to all VSG client requests to the Runeberry API. 16 | /// 17 | public static string RuneberryClientApiKey { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ValheimServerGUI/Game/WorldGenPresets.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ValheimServerGUI.Game 4 | { 5 | public static class WorldGenPresets 6 | { 7 | public const string Normal = "normal"; 8 | public const string Casual = "casual"; 9 | public const string Easy = "easy"; 10 | public const string Hard = "hard"; 11 | public const string Hardcore = "hardcore"; 12 | public const string Immersive = "immersive"; 13 | public const string Hammer = "hammer"; 14 | 15 | public static readonly IReadOnlyList All = new List() 16 | { 17 | Normal, 18 | Casual, 19 | Easy, 20 | Hard, 21 | Hardcore, 22 | Immersive, 23 | Hammer, 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Extensions/ControlExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Windows.Forms; 4 | 5 | namespace ValheimServerGUI.Extensions 6 | { 7 | public static class ControlExtensions 8 | { 9 | public static IEnumerable FindAllControls(this Control control) 10 | where TControl : Control 11 | { 12 | foreach (var c1 in control.Controls.OfType()) 13 | { 14 | if (c1 is TControl typed) 15 | { 16 | yield return typed; 17 | } 18 | 19 | foreach (var c2 in c1.FindAllControls()) 20 | { 21 | yield return c2; 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/Components/TimestampTransformer.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Events; 2 | 3 | namespace ValheimServerGUI.Tools.Logging.Components 4 | { 5 | public class TimestampTransformer : LogTransformer 6 | { 7 | private readonly string Format; 8 | private readonly string Space; 9 | 10 | public TimestampTransformer(string format, int space = 0) 11 | { 12 | Format = format; 13 | Space = space <= 0 ? string.Empty : new(' ', space); 14 | } 15 | 16 | public static readonly TimestampTransformer Default = new(TimeFormats.LogPrefix, 1); 17 | 18 | public override string Transform(LogEvent logEvent, string renderedMessage) 19 | { 20 | return $"{logEvent.Timestamp.ToString(Format)}{Space}{renderedMessage}"; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/EditButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace ValheimServerGUI.Forms 6 | { 7 | public partial class EditButton : UserControl 8 | { 9 | [Browsable(false)] 10 | public Action EditFunction { get; set; } 11 | 12 | public string HelpText 13 | { 14 | get => IconButton.HelpText; 15 | set => IconButton.HelpText = value; 16 | } 17 | 18 | public EditButton() 19 | { 20 | InitializeComponent(); 21 | 22 | IconButton.IconClicked = OnIconClicked; 23 | } 24 | 25 | private bool OnIconClicked() 26 | { 27 | if (EditFunction == null) return false; 28 | 29 | EditFunction.Invoke(); 30 | return true; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/RefreshButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace ValheimServerGUI.Forms 6 | { 7 | public partial class RefreshButton : UserControl 8 | { 9 | [Browsable(false)] 10 | public Action RefreshFunction { get; set; } 11 | 12 | public string HelpText 13 | { 14 | get => IconButton.HelpText; 15 | set => IconButton.HelpText = value; 16 | } 17 | 18 | public RefreshButton() 19 | { 20 | InitializeComponent(); 21 | 22 | IconButton.IconClicked = OnIconClicked; 23 | } 24 | 25 | private bool OnIconClicked() 26 | { 27 | if (RefreshFunction == null) return false; 28 | 29 | RefreshFunction.Invoke(); 30 | return true; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/SettingsButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace ValheimServerGUI.Controls 6 | { 7 | public partial class SettingsButton : UserControl 8 | { 9 | [Browsable(false)] 10 | public Action ClickFunction { get; set; } 11 | 12 | public string HelpText 13 | { 14 | get => IconButton.HelpText; 15 | set => IconButton.HelpText = value; 16 | } 17 | 18 | public SettingsButton() 19 | { 20 | InitializeComponent(); 21 | 22 | IconButton.IconClicked = OnIconClicked; 23 | } 24 | 25 | private bool OnIconClicked() 26 | { 27 | if (ClickFunction == null) return false; 28 | 29 | ClickFunction.Invoke(); 30 | return true; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "IIS Express": { 4 | "commandName": "IISExpress", 5 | "launchBrowser": true, 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | } 9 | }, 10 | "ValheimServerGUI.Serverless": { 11 | "commandName": "Project" 12 | }, 13 | "Mock Lambda Test Tool": { 14 | "commandName": "Executable", 15 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe", 16 | "commandLineArgs": "--port 5050", 17 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0" 18 | } 19 | }, 20 | "iisSettings": { 21 | "windowsAuthentication": false, 22 | "anonymousAuthentication": true, 23 | "iisExpress": { 24 | "applicationUrl": "http://localhost:55164/", 25 | "sslPort": 44385 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/dotnet:6 2 | 3 | WORKDIR /var/task 4 | 5 | # This COPY command copies the .NET Lambda project's build artifacts from the host machine into the image. 6 | # The source of the COPY should match where the .NET Lambda project publishes its build artifacts. If the Lambda function is being built 7 | # with the AWS .NET Lambda Tooling, the `--docker-host-build-output-dir` switch controls where the .NET Lambda project 8 | # will be built. The .NET Lambda project templates default to having `--docker-host-build-output-dir` 9 | # set in the aws-lambda-tools-defaults.json file to "bin/Release/net6.0/linux-x64/publish". 10 | # 11 | # Alternatively Docker multi-stage build could be used to build the .NET Lambda project inside the image. 12 | # For more information on this approach checkout the project's README.md file. 13 | COPY "bin/Release/net6.0/linux-x64/publish" . 14 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/HelpLabel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows.Forms; 3 | 4 | namespace ValheimServerGUI.Controls 5 | { 6 | public partial class HelpLabel : UserControl 7 | { 8 | [Editor("System.ComponentModel.Design.MultilineStringEditor", "System.Drawing.Design.UITypeEditor")] 9 | [EditorBrowsable(EditorBrowsableState.Always)] 10 | [Browsable(true)] 11 | [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] 12 | public override string Text 13 | { 14 | get => ToolTip.GetToolTip(Label); 15 | set 16 | { 17 | ToolTip.SetToolTip(Label, value); 18 | Label.Visible = !string.IsNullOrWhiteSpace(value); 19 | } 20 | } 21 | 22 | public HelpLabel() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/CopyButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace ValheimServerGUI.Forms 6 | { 7 | public partial class CopyButton : UserControl 8 | { 9 | [Browsable(false)] 10 | public Func CopyFunction { get; set; } 11 | 12 | public string HelpText 13 | { 14 | get => IconButton.HelpText; 15 | set => IconButton.HelpText = value; 16 | } 17 | 18 | public CopyButton() 19 | { 20 | InitializeComponent(); 21 | 22 | IconButton.IconClicked = OnIconClicked; 23 | } 24 | 25 | private bool OnIconClicked() 26 | { 27 | var str = CopyFunction?.Invoke(); 28 | if (string.IsNullOrEmpty(str)) return false; 29 | 30 | Clipboard.SetText(str); 31 | return true; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/OpenButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | using ValheimServerGUI.Tools; 5 | 6 | namespace ValheimServerGUI.Forms 7 | { 8 | public partial class OpenButton : UserControl 9 | { 10 | [Browsable(false)] 11 | public Func PathFunction { get; set; } 12 | 13 | public string HelpText 14 | { 15 | get => IconButton.HelpText; 16 | set => IconButton.HelpText = value; 17 | } 18 | 19 | public OpenButton() 20 | { 21 | InitializeComponent(); 22 | 23 | IconButton.IconClicked = OnIconClicked; 24 | } 25 | 26 | private bool OnIconClicked() 27 | { 28 | var path = PathFunction?.Invoke(); 29 | if (string.IsNullOrWhiteSpace(path)) return false; 30 | 31 | OpenHelper.OpenDirectory(path); 32 | return true; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/Components/LogLevelTransformer.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Events; 2 | using System.Collections.Generic; 3 | 4 | namespace ValheimServerGUI.Tools.Logging.Components 5 | { 6 | public class LogLevelTransformer : LogTransformer 7 | { 8 | private static readonly Dictionary LevelPrefixes = new() 9 | { 10 | { LogEventLevel.Verbose, "[VER] " }, 11 | { LogEventLevel.Debug, "[DBG] " }, 12 | { LogEventLevel.Information, "" }, 13 | { LogEventLevel.Warning, "[WRN] " }, 14 | { LogEventLevel.Error, "[ERR] " }, 15 | { LogEventLevel.Fatal, "[FAT] " }, 16 | }; 17 | 18 | public static readonly LogLevelTransformer Default = new(); 19 | 20 | public override string Transform(LogEvent logEvent, string renderedMessage) 21 | { 22 | return $"{LevelPrefixes[logEvent.Level]}{renderedMessage}"; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Data/IDataRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ValheimServerGUI.Tools.Data 5 | { 6 | public interface IDataRepository where TEntity : IPrimaryKeyEntity 7 | { 8 | event EventHandler DataReady; 9 | 10 | event EventHandler DataUpdated; 11 | 12 | event EventHandler DataCleared; 13 | 14 | event EventHandler EntityUpdated; 15 | 16 | event EventHandler EntityRemoved; 17 | 18 | IEnumerable Data { get; } 19 | 20 | TEntity FindById(string id); 21 | 22 | void Upsert(TEntity entity); 23 | 24 | void UpsertBulk(IEnumerable entities); 25 | 26 | void Remove(string key); 27 | 28 | void Remove(TEntity entity); 29 | 30 | void RemoveBulk(IEnumerable keys); 31 | 32 | void RemoveBulk(IEnumerable entities); 33 | 34 | void RemoveAll(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "Information" : [ 4 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 5 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 6 | "dotnet lambda help", 7 | "All the command line options for the Lambda command can be specified in this file." 8 | ], 9 | "profile" : "toolkit-sso", 10 | "region" : "us-east-1", 11 | "configuration" : "Release", 12 | "s3-prefix" : "ValheimServerGUI.Serverless/", 13 | "template" : "serverless.template", 14 | "template-parameters" : "", 15 | "docker-host-build-output-dir" : "./bin/Release/net6.0/linux-x64/publish", 16 | "s3-bucket" : "runeberry-cf-templates", 17 | "stack-name" : "valheim-server-gui-stack" 18 | } -------------------------------------------------------------------------------- /ValheimServerGUI.Tests/Tools/MockProcessProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Diagnostics; 4 | using ValheimServerGUI.Tools.Processes; 5 | 6 | namespace ValheimServerGUI.Tests.Tools 7 | { 8 | public class MockProcessProvider : IProcessProvider 9 | { 10 | private readonly ConcurrentDictionary Processes = new(); 11 | 12 | public void AddProcess(string key, Process process) 13 | { 14 | if (!Processes.TryAdd(key, process)) 15 | { 16 | throw new InvalidOperationException($"Failed to add process with key: {key}"); 17 | } 18 | } 19 | 20 | public Process GetProcess(string key) 21 | { 22 | if (!Processes.TryGetValue(key, out var process)) return null; 23 | return process; 24 | } 25 | 26 | 27 | public void StartIO(Process process) 28 | { 29 | // no-op for testing 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/Components/RegexTransformer.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Events; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace ValheimServerGUI.Tools.Logging.Components 5 | { 6 | public class RegexTransformer : LogTransformer 7 | { 8 | private readonly string CapturePattern; 9 | private readonly string ReplacePattern; 10 | 11 | public RegexTransformer(string capture, string replace) 12 | { 13 | CapturePattern = capture; 14 | ReplacePattern = replace; 15 | } 16 | 17 | public static RegexTransformer Replace(string capture, string replace) => new(capture, replace); 18 | public static RegexTransformer Remove(string pattern) => new(pattern, string.Empty); 19 | 20 | #region LogTransformer implementation 21 | 22 | public override string Transform(LogEvent logEvent, string renderedMessage) 23 | { 24 | return Regex.Replace(renderedMessage, CapturePattern, ReplacePattern); 25 | } 26 | 27 | #endregion 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tests/Tools/MockUserPreferencesProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ValheimServerGUI.Game; 3 | 4 | namespace ValheimServerGUI.Tests.Tools 5 | { 6 | public class MockUserPreferencesProvider : IUserPreferencesProvider 7 | { 8 | private UserPreferences UserPrefs = UserPreferences.GetDefault(); 9 | 10 | public void SetUserPreferences(UserPreferences prefs) 11 | { 12 | UserPrefs = prefs; 13 | } 14 | 15 | public void SetUserPreferences(Action prefsBuilder) 16 | { 17 | prefsBuilder(UserPrefs); 18 | } 19 | 20 | #region IUserPreferencesProvider implementation 21 | 22 | public event EventHandler PreferencesSaved; 23 | 24 | public UserPreferences LoadPreferences() 25 | { 26 | return UserPrefs; 27 | } 28 | 29 | public void SavePreferences(UserPreferences preferences) 30 | { 31 | PreferencesSaved?.Invoke(this, preferences); 32 | } 33 | 34 | #endregion 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/TimeFormats.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ValheimServerGUI.Tools 4 | { 5 | public static class TimeFormats 6 | { 7 | public const string DisplayISO = "yyyy-MM-ddTHH:mm:ssZ"; 8 | public const string FilenameISO = "yyyy-MM-dd_HH-mm-ssZ"; 9 | public const string LogPrefix = "[HH:mm:ss.fff]"; 10 | public const string ServerElapsed = @"hh\:mm\:ss"; 11 | 12 | public static string ToDisplayISOFormat(this DateTime dateTime) 13 | { 14 | return dateTime.ToString(DisplayISO); 15 | } 16 | 17 | public static string ToFilenameISOFormat(this DateTime dateTime) 18 | { 19 | return dateTime.ToString(FilenameISO); 20 | } 21 | 22 | public static string ToLogPrefixFormat(this DateTimeOffset dateTime) 23 | { 24 | return dateTime.ToString(LogPrefix); 25 | } 26 | 27 | public static string ToServerElapsedFormat(this TimeSpan timeSpan) 28 | { 29 | return timeSpan.ToString(ServerElapsed); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tests/Tools/MockDataFileProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using ValheimServerGUI.Tools.Data; 4 | 5 | namespace ValheimServerGUI.Tests.Tools 6 | { 7 | public class MockDataFileProvider : IFileProvider 8 | { 9 | private object DataFile; 10 | 11 | public void SetData(TFile data) 12 | { 13 | DataFile = data; 14 | } 15 | 16 | #region IDataFileProvider implementation 17 | 18 | public event EventHandler DataLoaded; 19 | public event EventHandler DataSaved; 20 | 21 | public Task LoadAsync(string filePath) where TFile : class 22 | { 23 | DataLoaded?.Invoke(this, DataFile); 24 | return Task.FromResult(DataFile as TFile); 25 | } 26 | 27 | public Task SaveAsync(string filePath, TFile data) where TFile : class 28 | { 29 | DataFile = data; 30 | DataSaved?.Invoke(this, data); 31 | return Task.CompletedTask; 32 | } 33 | 34 | #endregion 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless.Tests/SampleRequests/ValuesController-Get.json: -------------------------------------------------------------------------------- 1 | { 2 | "resource": "/{proxy+}", 3 | "path": "/api/values", 4 | "httpMethod": "GET", 5 | "headers": null, 6 | "queryStringParameters": null, 7 | "pathParameters": { 8 | "proxy": "api/values" 9 | }, 10 | "stageVariables": null, 11 | "requestContext": { 12 | "accountId": "AAAAAAAAAAAA", 13 | "resourceId": "5agfss", 14 | "stage": "test-invoke-stage", 15 | "requestId": "test-invoke-request", 16 | "identity": { 17 | "cognitoIdentityPoolId": null, 18 | "accountId": "AAAAAAAAAAAA", 19 | "cognitoIdentityId": null, 20 | "caller": "BBBBBBBBBBBB", 21 | "apiKey": "test-invoke-api-key", 22 | "sourceIp": "test-invoke-source-ip", 23 | "cognitoAuthenticationType": null, 24 | "cognitoAuthenticationProvider": null, 25 | "userArn": "arn:aws:iam::AAAAAAAAAAAA:root", 26 | "userAgent": "Apache-HttpClient/4.5.x (Java/1.8.0_102)", 27 | "user": "AAAAAAAAAAAA" 28 | }, 29 | "resourcePath": "/{proxy+}", 30 | "httpMethod": "GET", 31 | "apiId": "t2yh6sjnmk" 32 | }, 33 | "body": null 34 | } -------------------------------------------------------------------------------- /SolutionResources/ServerSecrets.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ValheimServerGUI.Properties 4 | { 5 | /// 6 | /// The values in this class are populated by the static constructor in the corresponding 7 | /// partial class, which is kept out of source control. 8 | /// 9 | public static partial class ServerSecrets 10 | { 11 | /// 12 | /// The HTTP header that will contain the API key for requests made to the Runeberry API. 13 | /// 14 | public static string RuneberryApiKeyHeader { get; } = string.Empty; 15 | 16 | /// 17 | /// The Runeberry API keys that will be accepted by the server. 18 | /// 19 | public static HashSet RuneberryServerApiKeys { get; } = new(); 20 | 21 | /// 22 | /// API key for interacting with the Steamworks Web API. 23 | /// 24 | public static string SteamApiKey { get; } 25 | 26 | /// 27 | /// API key for interacting with the OpenXBL API. 28 | /// 29 | public static string XboxApiKey { get; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tests/ValheimServerGUI.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0-windows 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | all 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | all 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/Components/RollingFileSink.cs: -------------------------------------------------------------------------------- 1 | using Serilog; 2 | using System; 3 | using System.IO; 4 | 5 | namespace ValheimServerGUI.Tools.Logging.Components 6 | { 7 | public static class RollingFileSinkExtensions 8 | { 9 | private const string DefaultOutputTemplate = "{Message:lj}{NewLine}"; 10 | 11 | public static LoggerConfiguration WriteToRollingFile( 12 | this LoggerConfiguration config, 13 | string directory, 14 | string filename) 15 | { 16 | filename = PathExtensions.GetValidFileName(filename); 17 | directory = Environment.ExpandEnvironmentVariables(directory); 18 | var filepath = Path.Join(directory, $"{filename}_.txt"); 19 | 20 | if (!Directory.Exists(directory)) 21 | { 22 | Directory.CreateDirectory(directory); 23 | } 24 | 25 | return config.WriteTo.File(filepath, 26 | rollingInterval: RollingInterval.Day, 27 | retainedFileTimeLimit: TimeSpan.FromDays(30), 28 | outputTemplate: DefaultOutputTemplate, 29 | shared: true); // Allows multiple processes to write to same file 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/LocalEntryPoint.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.Hosting; 4 | 5 | namespace ValheimServerGUI.Serverless 6 | { 7 | /// 8 | /// The Main function can be used to run the ASP.NET Core application locally using the Kestrel webserver. 9 | /// 10 | public class LocalEntryPoint 11 | { 12 | public static void Main(string[] args) 13 | { 14 | CreateHostBuilder(args).Build().Run(); 15 | } 16 | 17 | public static IHostBuilder CreateHostBuilder(string[] args) => 18 | Host.CreateDefaultBuilder(args) 19 | .ConfigureWebHostDefaults(webBuilder => 20 | { 21 | webBuilder.ConfigureAppConfiguration(config => 22 | { 23 | var executingLocation = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); 24 | config.AddJsonFile(System.IO.Path.Join(executingLocation, "appsettings.local.json"), optional: true); 25 | }); 26 | webBuilder.UseStartup(); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Models/PlayerPlatforms.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ValheimServerGUI.Tools.Models 4 | { 5 | public static class PlayerPlatforms 6 | { 7 | public const string Steam = "Steam"; 8 | public const string Xbox = "Xbox"; 9 | 10 | public static readonly HashSet All = new() 11 | { 12 | Steam, 13 | Xbox, 14 | }; 15 | 16 | /// 17 | /// Gets a case-corrected platform name from an input string. 18 | /// 19 | public static bool TryGetValidPlatform(string input, out string platform) 20 | { 21 | if (input == null) 22 | { 23 | platform = null; 24 | return false; 25 | } 26 | 27 | switch (input.Trim().ToLowerInvariant()) 28 | { 29 | case "steam": 30 | platform = Steam; 31 | return true; 32 | case "xbox": 33 | platform = Xbox; 34 | return true; 35 | default: 36 | platform = null; 37 | return false; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Http/RestClient.cs: -------------------------------------------------------------------------------- 1 | using Serilog; 2 | using System.Net.Http; 3 | 4 | namespace ValheimServerGUI.Tools.Http 5 | { 6 | public class RestClient 7 | { 8 | public IRestClientContext Context { get; } 9 | 10 | public ILogger Logger => Context.Logger; 11 | 12 | public RestClient(IRestClientContext context) 13 | { 14 | Context = context; 15 | } 16 | 17 | public RestClientRequest Request(HttpMethod method, string uri, object payload = null) 18 | { 19 | return BuildRequest(method, uri, payload); 20 | } 21 | 22 | public RestClientRequest Get(string uri) 23 | { 24 | return BuildRequest(HttpMethod.Get, uri); 25 | } 26 | 27 | public RestClientRequest Post(string uri, object payload = null) 28 | { 29 | return BuildRequest(HttpMethod.Post, uri, payload); 30 | } 31 | 32 | private RestClientRequest BuildRequest(HttpMethod method, string uri, object payload = null) 33 | { 34 | return new RestClientRequest(this) 35 | { 36 | Method = method, 37 | Uri = uri, 38 | RequestContent = payload, 39 | }; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless.Tests/ValuesControllerTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | using Xunit; 4 | 5 | 6 | namespace ValheimServerGUI.Serverless.Tests 7 | { 8 | public class ValuesControllerTests 9 | { 10 | [Fact] 11 | public Task TestGet() 12 | { 13 | return Task.CompletedTask; 14 | // todo: (jb, 5/16/21) This was the test generated by the AWS scaffolder. 15 | // Need to come back and write tests for the real Serverless application. 16 | 17 | //var lambdaFunction = new LambdaEntryPoint(); 18 | 19 | //var requestStr = File.ReadAllText("./SampleRequests/ValuesController-Get.json"); 20 | //var request = JsonConvert.DeserializeObject(requestStr); 21 | //var context = new TestLambdaContext(); 22 | //var response = await lambdaFunction.FunctionHandlerAsync(request, context); 23 | 24 | //Assert.Equal(200, response.StatusCode); 25 | //Assert.Equal("[\"value1\",\"value2\"]", response.Body); 26 | //Assert.True(response.MultiValueHeaders.ContainsKey("Content-Type")); 27 | //Assert.Equal("application/json; charset=utf-8", response.MultiValueHeaders["Content-Type"][0]); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/OpenHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace ValheimServerGUI.Tools 5 | { 6 | public static class OpenHelper 7 | { 8 | public static void OpenDirectory(string path) 9 | { 10 | if (string.IsNullOrWhiteSpace(path)) return; 11 | 12 | path = Environment.ExpandEnvironmentVariables(path); 13 | 14 | try 15 | { 16 | // If this is a path to a valid file, open that file's directory 17 | path = PathExtensions.GetFileInfo(path).Directory.FullName; 18 | } 19 | catch 20 | { 21 | try 22 | { 23 | // Otherwise, check if this is a path to a valid directory 24 | path = PathExtensions.GetDirectoryInfo(path).FullName; 25 | } 26 | catch 27 | { 28 | // If neither, do nothing 29 | return; 30 | } 31 | } 32 | 33 | Process.Start("explorer.exe", path); 34 | } 35 | 36 | public static void OpenWebAddress(string url) 37 | { 38 | if (string.IsNullOrWhiteSpace(url)) return; 39 | Process.Start("explorer.exe", url); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/LogRule.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Events; 2 | 3 | namespace ValheimServerGUI.Tools.Logging 4 | { 5 | public abstract class LogRule 6 | { 7 | protected LogRule() { } 8 | 9 | public virtual bool Include(LogEvent logEvent, string renderedMessage) 10 | { 11 | return true; 12 | } 13 | 14 | public virtual string Transform(LogEvent logEvent, string renderedMessage) 15 | { 16 | return renderedMessage; 17 | } 18 | } 19 | 20 | public abstract class LogFilter : LogRule 21 | { 22 | protected LogFilter() { } 23 | 24 | public override abstract bool Include(LogEvent logEvent, string renderedMessage); 25 | 26 | public override sealed string Transform(LogEvent logEvent, string renderedMessage) 27 | { 28 | return base.Transform(logEvent, renderedMessage); 29 | } 30 | } 31 | 32 | public abstract class LogTransformer : LogRule 33 | { 34 | protected LogTransformer() { } 35 | 36 | public override sealed bool Include(LogEvent logEvent, string renderedMessage) 37 | { 38 | return base.Include(logEvent, renderedMessage); 39 | } 40 | 41 | public override abstract string Transform(LogEvent logEvent, string renderedMessage); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Models/CrashReport.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace ValheimServerGUI.Tools.Models 6 | { 7 | public class CrashReport 8 | { 9 | [JsonProperty("id")] 10 | public string CrashReportId { get; set; } 11 | 12 | [JsonProperty("clientCorrelationId")] 13 | public string ClientCorrelationId { get; set; } 14 | 15 | [JsonProperty("source")] 16 | public string Source { get; set; } 17 | 18 | [JsonProperty("timestamp")] 19 | public DateTimeOffset? Timestamp { get; set; } 20 | 21 | [JsonProperty("appVersion")] 22 | public string AppVersion { get; set; } 23 | 24 | [JsonProperty("osVersion")] 25 | public string OsVersion { get; set; } 26 | 27 | [JsonProperty("dotnetVersion")] 28 | public string DotnetVersion { get; set; } 29 | 30 | [JsonProperty("currentCulture")] 31 | public string CurrentCulture { get; set; } 32 | 33 | [JsonProperty("currentUiCulture")] 34 | public string CurrentUICulture { get; set; } 35 | 36 | [JsonProperty("additionalInfo")] 37 | public Dictionary AdditionalInfo { get; set; } 38 | 39 | [JsonProperty("logs")] 40 | public List Logs { get; set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ValheimServerGUI/Forms/AboutForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using ValheimServerGUI.Properties; 4 | using ValheimServerGUI.Tools; 5 | 6 | namespace ValheimServerGUI.Forms 7 | { 8 | public partial class AboutForm : Form 9 | { 10 | public AboutForm() 11 | { 12 | InitializeComponent(); 13 | this.AddApplicationIcon(); 14 | 15 | try 16 | { 17 | VersionLabel.Text = $"Version: {AssemblyHelper.GetApplicationVersion()}"; 18 | VersionLabel.Text += $"{Environment.NewLine}Build Date: {AssemblyHelper.GetApplicationBuildDate().ToUniversalTime().ToDisplayISOFormat()}"; 19 | } 20 | catch { } 21 | } 22 | 23 | private void ButtonDonate_Click(object sender, EventArgs e) 24 | { 25 | OpenHelper.OpenWebAddress(Resources.UrlDonate); 26 | } 27 | 28 | private void ButtonGitHub_Click(object sender, EventArgs e) 29 | { 30 | OpenHelper.OpenWebAddress(Resources.UrlGithubApplication); 31 | } 32 | 33 | private void ButtonValheimSite_Click(object sender, EventArgs e) 34 | { 35 | OpenHelper.OpenWebAddress(Resources.UrlValheimGameSite); 36 | } 37 | 38 | private void ButtonDiscord_Click(object sender, EventArgs e) 39 | { 40 | OpenHelper.OpenWebAddress(Resources.UrlDiscord); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/CheckboxFormField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace ValheimServerGUI.Controls 6 | { 7 | public partial class CheckboxFormField : UserControl, IFormField 8 | { 9 | #region IFormField implementation 10 | 11 | public string LabelText 12 | { 13 | get => CheckBox.Text; 14 | set => CheckBox.Text = value; 15 | } 16 | 17 | [Editor("System.ComponentModel.Design.MultilineStringEditor", "System.Drawing.Design.UITypeEditor")] 18 | public string HelpText 19 | { 20 | get => HelpLabel.Text; 21 | set => HelpLabel.Text = value; 22 | } 23 | 24 | public bool Value 25 | { 26 | get => CheckBox.Checked; 27 | set 28 | { 29 | if (value == Value) return; 30 | 31 | CheckBox.Checked = value; 32 | ValueChanged?.Invoke(this, value); 33 | } 34 | } 35 | 36 | public event EventHandler ValueChanged; 37 | 38 | #endregion 39 | 40 | public CheckboxFormField() 41 | { 42 | InitializeComponent(); 43 | 44 | CheckBox.CheckedChanged += CheckBox_Changed; 45 | } 46 | 47 | private void CheckBox_Changed(object sender, EventArgs e) 48 | { 49 | ValueChanged?.Invoke(this, Value); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ValheimServerGUI/Game/WorldPreferences.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace ValheimServerGUI.Game 6 | { 7 | public class WorldPreferences 8 | { 9 | public string WorldName { get; set; } 10 | 11 | public DateTime LastSaved { get; set; } = DateTime.UnixEpoch; 12 | 13 | public string Preset { get; set; } 14 | 15 | public Dictionary Modifiers { get; set; } = new(); 16 | 17 | public HashSet Keys { get; set; } = new(); 18 | 19 | public static WorldPreferences FromFile(WorldPreferencesFile file) 20 | { 21 | var prefs = new WorldPreferences(); 22 | 23 | if (file == null) return prefs; 24 | 25 | prefs.WorldName = file.WorldName; 26 | prefs.LastSaved = file.LastSaved ?? prefs.LastSaved; 27 | prefs.Preset = file.Preset; 28 | prefs.Modifiers = file.Modifiers; 29 | prefs.Keys = file.Keys.ToHashSet(); 30 | 31 | return prefs; 32 | } 33 | 34 | public WorldPreferencesFile ToFile() 35 | { 36 | var file = new WorldPreferencesFile() 37 | { 38 | WorldName = WorldName, 39 | LastSaved = LastSaved, 40 | Preset = Preset, 41 | Modifiers = Modifiers, 42 | Keys = Keys.ToList(), 43 | }; 44 | 45 | return file; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/ValheimServerLogger.cs: -------------------------------------------------------------------------------- 1 | using Serilog; 2 | using ValheimServerGUI.Game; 3 | using ValheimServerGUI.Tools.Logging.Components; 4 | 5 | namespace ValheimServerGUI.Tools.Logging 6 | { 7 | public interface IValheimServerLogger : IBaseLogger 8 | { 9 | } 10 | 11 | public class ValheimServerLogger : BaseLogger, IValheimServerLogger 12 | { 13 | private readonly IValheimServerOptions Options; 14 | 15 | public ValheimServerLogger(IValheimServerOptions options) 16 | { 17 | Options = options; 18 | 19 | // Remove default timestamp when it's present on a log 20 | AddRule(RegexTransformer.Remove(@"^\d+\/\d+\/\d+ \d+:\d+:\d+:\s+")); 21 | 22 | if (!Options.LogFilteringDisabled) 23 | { 24 | // Ignore excess Unity logs 25 | AddRule(RegexFilter.Exclude(@"^\(Filename:")); 26 | AddRule(RegexFilter.Exclude(@"^Console: ")); 27 | 28 | // Ignore empty lines 29 | AddRule(RegexFilter.Exclude(@"^\s*?$")); 30 | } 31 | 32 | // Add a timestamp after filtering 33 | AddRule(TimestampTransformer.Default); 34 | } 35 | 36 | #region BaseLogger overrides 37 | 38 | protected override void ConfigureLogger(LoggerConfiguration config) 39 | { 40 | if (Options.LogToFile) AddFileLogging(config, $"ServerLogs-{Options.Name}"); 41 | } 42 | 43 | #endregion 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Processes/ProcessProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Diagnostics; 4 | 5 | namespace ValheimServerGUI.Tools.Processes 6 | { 7 | public class ProcessProvider : IProcessProvider 8 | { 9 | private readonly ConcurrentDictionary Processes = new(); 10 | 11 | public void AddProcess(string key, Process process) 12 | { 13 | if (!Processes.TryAdd(key, process)) 14 | { 15 | throw new InvalidOperationException($"Failed to add process with key: {key}"); 16 | } 17 | 18 | // Remove this process from the provider when the process exits. 19 | process.Exited += (_, _) => Processes.TryRemove(key, out var _); 20 | } 21 | 22 | public Process GetProcess(string key) 23 | { 24 | if (!Processes.TryGetValue(key, out var process)) return null; 25 | 26 | try 27 | { 28 | // Don't return a process if it's already exited 29 | if (process.HasExited) return null; 30 | } 31 | catch 32 | { 33 | // HasExited will throw if the process hasn't started yet, so ignore that 34 | } 35 | 36 | return process; 37 | } 38 | 39 | public void StartIO(Process process) 40 | { 41 | process.Start(); 42 | process.BeginOutputReadLine(); 43 | process.BeginErrorReadLine(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/Middleware/RuneberryAuthMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Mvc; 3 | using System; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using ValheimServerGUI.Properties; 7 | 8 | namespace ValheimServerGUI.Serverless.Middleware 9 | { 10 | [ApiController] 11 | public class RuneberryAuthMiddleware 12 | { 13 | private static readonly bool ApiKeyEnabled; 14 | 15 | static RuneberryAuthMiddleware() 16 | { 17 | ApiKeyEnabled = !string.IsNullOrWhiteSpace(ServerSecrets.RuneberryApiKeyHeader) && ServerSecrets.RuneberryApiKeyHeader.Any(); 18 | } 19 | 20 | public static async Task Authorize(HttpContext context, Func next) 21 | { 22 | if (ApiKeyEnabled) 23 | { 24 | if (!context.Request.Headers.TryGetValue(ServerSecrets.RuneberryApiKeyHeader, out var apiKey)) 25 | { 26 | context.Response.StatusCode = 401; 27 | await context.Response.WriteAsJsonAsync(new { message = "Missing API key" }); 28 | return; 29 | } 30 | 31 | if (!ServerSecrets.RuneberryServerApiKeys.Contains(apiKey)) 32 | { 33 | context.Response.StatusCode = 401; 34 | await context.Response.WriteAsJsonAsync(new { message = "Invalid API key" }); 35 | return; 36 | } 37 | } 38 | 39 | await next?.Invoke(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless.Tests/ValheimServerGUI.Serverless.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | False 5 | 6 | 7 | 8 | PreserveNewest 9 | 10 | 11 | 12 | 13 | PreserveNewest 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | all 25 | runtime; build; native; contentfiles; analyzers; buildtransitive 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/Components/RegexFilter.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Events; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace ValheimServerGUI.Tools.Logging.Components 5 | { 6 | public class RegexFilter : LogFilter 7 | { 8 | private readonly Regex Pattern; 9 | private readonly bool IncludeMatch; 10 | private readonly bool MatchAgainstTemplate; 11 | 12 | public RegexFilter(Regex pattern, bool includeMatch, bool matchAgainstTemplate) 13 | { 14 | Pattern = pattern; 15 | IncludeMatch = includeMatch; 16 | MatchAgainstTemplate = matchAgainstTemplate; 17 | } 18 | 19 | public RegexFilter(string pattern, bool includeMatch, bool matchAgainstTemplate) 20 | : this(new Regex(pattern), includeMatch, matchAgainstTemplate) { } 21 | 22 | public static RegexFilter Exclude(string pattern) => new(pattern, false, false); 23 | public static RegexFilter Include(string pattern) => new(pattern, true, false); 24 | public static RegexFilter ExcludeTemplate(string pattern) => new(pattern, false, true); 25 | public static RegexFilter IncludeTemplate(string pattern) => new(pattern, true, true); 26 | 27 | #region LogFilter implementation 28 | 29 | public override bool Include(LogEvent logEvent, string renderedMessage) 30 | { 31 | var message = MatchAgainstTemplate ? logEvent.MessageTemplate.Text : renderedMessage; 32 | var isMatch = Pattern.IsMatch(message); 33 | var include = IncludeMatch ? isMatch : !isMatch; 34 | 35 | return include; 36 | } 37 | 38 | #endregion 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/Logging/ApplicationLogger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Serilog; 3 | using System; 4 | using ValheimServerGUI.Game; 5 | using ValheimServerGUI.Tools.Logging.Components; 6 | 7 | namespace ValheimServerGUI.Tools.Logging 8 | { 9 | public interface IApplicationLogger : IBaseLogger 10 | { 11 | } 12 | 13 | public class ApplicationLogger : BaseLogger, IApplicationLogger 14 | { 15 | private readonly IServiceProvider ServiceProvider; 16 | private IUserPreferencesProvider UserPrefsProvider; 17 | 18 | public ApplicationLogger(IServiceProvider services) 19 | { 20 | // Dependencies are injected late to avoid creating a circular dependency 21 | ServiceProvider = services; 22 | 23 | AddRule(LogLevelTransformer.Default); 24 | AddRule(TimestampTransformer.Default); 25 | } 26 | 27 | private void OnUserPreferencesSaved(object sender, UserPreferences prefs) 28 | { 29 | RebuildLogger(); 30 | } 31 | 32 | #region BaseLogger overrides 33 | 34 | protected override void ConfigureLogger(LoggerConfiguration config) 35 | { 36 | if (UserPrefsProvider == null) 37 | { 38 | UserPrefsProvider = ServiceProvider.GetRequiredService(); 39 | UserPrefsProvider.PreferencesSaved += OnUserPreferencesSaved; 40 | } 41 | 42 | var prefs = UserPrefsProvider.LoadPreferences(); 43 | if (prefs.WriteApplicationLogsToFile) AddFileLogging(config, "ApplicationLogs"); 44 | } 45 | 46 | #endregion 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /SolutionResources/README.md: -------------------------------------------------------------------------------- 1 | # Solution Resources 2 | 3 | This folder contains code, configuration, and/or assets that are used in multiple projects in the Solution. Some files are considered "secret" and are not committed to source control. However, the solution is set up so that you **should not need any of these secret files** in order to do local development - only to publish the app or Serverless code. 4 | 5 | In some cases, however, you may want to supply your own mock secret values for testing. Examples of these files are provided below for your reference. 6 | 7 | ### ValheimServerGUI.snk 8 | 9 | This is only needed when publishing the desktop client application in the Release configuration. If you need to publish the application locally for some reason, simply change the Publish Profile (.pubxml) to publish to Debug configuration temporarily. 10 | 11 | ### ClientSecrets.Values.cs 12 | 13 | This is a... "clever" way of providing secret information to both the client and Serverless applications at compile time. Use this partial static class to set the values of any properties in **ClientSecrets.cs**. 14 | 15 | ```csharp 16 | namespace ValheimServerGUI.Properties 17 | { 18 | public static partial class Secrets 19 | { 20 | static Secrets() 21 | { 22 | // Set the values of any properties in Secrets.cs below 23 | RuneberryApiKeyHeader = "some-header-key"; 24 | } 25 | } 26 | } 27 | ``` 28 | 29 | ### appsettings.local.json 30 | 31 | Configuration values for the Serverless application only when running locally. You can set AWS Lambda environment variables here to imitate running in a cloud environment. 32 | 33 | ```jsonc 34 | { 35 | // These are required to access other AWS services from within the API 36 | "AWS_ACCESS_KEY_ID": "", 37 | "AWS_SECRET_ACCESS_KEY": "" 38 | } 39 | ``` -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/ValheimServerGUI.Serverless.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | true 5 | Lambda 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | %(RecursiveDir)%(Filename)%(Extension) 30 | PreserveNewest 31 | 32 | 33 | -------------------------------------------------------------------------------- /ValheimServerGUI/Game/ServerPreferencesFile.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | 4 | namespace ValheimServerGUI.Game 5 | { 6 | public class ServerPreferencesFile 7 | { 8 | [JsonProperty("profileName")] 9 | public string ProfileName { get; set; } 10 | 11 | [JsonProperty("lastSaved")] 12 | public DateTime? LastSaved { get; set; } 13 | 14 | [JsonProperty("name")] 15 | public string Name { get; set; } 16 | 17 | [JsonProperty("password")] 18 | public string Password { get; set; } 19 | 20 | [JsonProperty("world")] 21 | public string WorldName { get; set; } 22 | 23 | [JsonProperty("community")] 24 | public bool? Community { get; set; } 25 | 26 | [JsonProperty("port")] 27 | public int? Port { get; set; } 28 | 29 | [JsonProperty("crossplay")] 30 | public bool? Crossplay { get; set; } 31 | 32 | [JsonProperty("saveInterval")] 33 | public int? SaveInterval { get; set; } 34 | 35 | [JsonProperty("backupCount")] 36 | public int? BackupCount { get; set; } 37 | 38 | [JsonProperty("backupIntervalShort")] 39 | public int? BackupIntervalShort { get; set; } 40 | 41 | [JsonProperty("backupIntervalLong")] 42 | public int? BackupIntervalLong { get; set; } 43 | 44 | [JsonProperty("autoStart")] 45 | public bool? AutoStart { get; set; } 46 | 47 | [JsonProperty("additionalArgs")] 48 | public string AdditionalArgs { get; set; } 49 | 50 | [JsonProperty("valheimServerPath")] 51 | public string ServerExePath { get; set; } 52 | 53 | [JsonProperty("valheimSaveDataFolder")] 54 | public string SaveDataFolderPath { get; set; } 55 | 56 | [JsonProperty("writeServerLogsToFile")] 57 | public bool? WriteServerLogsToFile { get; set; } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Logging/ConcurrentBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace ValheimServerGUI.Tools.Logging 8 | { 9 | public class ConcurrentBuffer : IEnumerable, IEnumerable, IReadOnlyCollection 10 | { 11 | public int BufferSize { get; } 12 | 13 | private ConcurrentQueue ConcurrentQueue = new(); 14 | 15 | public ConcurrentBuffer(int bufferSize) 16 | { 17 | if (bufferSize < 0) throw new ArgumentException("Buffer size must be >= 0"); 18 | 19 | BufferSize = bufferSize; 20 | } 21 | 22 | public int Count => ConcurrentQueue.Count; 23 | 24 | public bool IsReadOnly => false; 25 | 26 | public void Enqueue(T item) 27 | { 28 | ConcurrentQueue.Enqueue(item); 29 | 30 | while (ConcurrentQueue.Count > BufferSize) 31 | { 32 | ConcurrentQueue.TryDequeue(out var _); 33 | } 34 | } 35 | 36 | public T Dequeue() 37 | { 38 | if (ConcurrentQueue.TryDequeue(out var item)) 39 | { 40 | return item; 41 | } 42 | 43 | return default; 44 | } 45 | 46 | public void Clear() 47 | { 48 | ConcurrentQueue.Clear(); 49 | } 50 | 51 | public bool Contains(T item) 52 | { 53 | return ConcurrentQueue.Contains(item); 54 | } 55 | 56 | public void CopyTo(T[] array, int arrayIndex) 57 | { 58 | ConcurrentQueue.CopyTo(array, arrayIndex); 59 | } 60 | 61 | public IEnumerator GetEnumerator() 62 | { 63 | return ConcurrentQueue.GetEnumerator(); 64 | } 65 | 66 | IEnumerator IEnumerable.GetEnumerator() 67 | { 68 | return ConcurrentQueue.GetEnumerator(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tests/Tools/MockHttpClientProvider.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Net; 5 | using System.Net.Http; 6 | using ValheimServerGUI.Tools.Http; 7 | 8 | namespace ValheimServerGUI.Tests.Tools 9 | { 10 | public class MockHttpClientProvider : IHttpClientProvider 11 | { 12 | private Action BuildDefaultResponse = res => res.StatusCode = HttpStatusCode.NotImplemented; 13 | 14 | private readonly List<(Func, Action)> Setups = new(); 15 | 16 | public MockHttpClientProvider SetResponse(Func condition, Action responseBuilder) 17 | { 18 | Setups.Add((condition, responseBuilder)); 19 | return this; 20 | } 21 | 22 | public MockHttpClientProvider SetDefaultResponse(Action responseBuilder) 23 | { 24 | BuildDefaultResponse = responseBuilder; 25 | return this; 26 | } 27 | 28 | public HttpClient CreateClient() 29 | { 30 | var mockClient = new Mock(); 31 | 32 | mockClient 33 | .Setup(c => c.SendAsync(It.IsAny())) 34 | .ReturnsAsync(() => GetResponseMessage(BuildDefaultResponse)); 35 | 36 | foreach (var (condition, responseBuilder) in Setups) 37 | { 38 | mockClient 39 | .Setup(c => c.SendAsync(It.Is(r => condition(r)))) 40 | .ReturnsAsync(() => GetResponseMessage(responseBuilder)); 41 | } 42 | 43 | return mockClient.Object; 44 | } 45 | 46 | private static HttpResponseMessage GetResponseMessage(Action builder) 47 | { 48 | var response = new HttpResponseMessage(); 49 | builder(response); 50 | return response; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ValheimServerGUI/Game/UserPreferencesFile.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace ValheimServerGUI.Game 6 | { 7 | /// 8 | /// Represents the deserialized user preferences file, and provides the model as it's 9 | /// written to / read from disk. 10 | /// 11 | public class UserPreferencesFile 12 | { 13 | // (jb, 2/19/23) This field was previously recorded, but never used. 14 | //[JsonProperty("valheimGamePath")] 15 | //public string ValheimGamePath { get; set; } 16 | 17 | [JsonProperty("valheimServerPath")] 18 | public string ServerExePath { get; set; } 19 | 20 | [JsonProperty("valheimSaveDataFolder")] 21 | public string SaveDataFolderPath { get; set; } 22 | 23 | [JsonProperty("startWithWindows")] 24 | public bool? StartWithWindows { get; set; } 25 | 26 | [JsonProperty("startServerAutomatically"), Obsolete("Moved to server preferences", true)] 27 | public bool? StartServerAutomatically { get; set; } 28 | 29 | [JsonProperty("startMinimized")] 30 | public bool? StartMinimized { get; set; } 31 | 32 | [JsonProperty("checkServerRunning"), Obsolete("Removed with multi-server support", true)] 33 | public bool? CheckServerRunning { get; set; } 34 | 35 | [JsonProperty("checkForUpdates")] 36 | public bool? CheckForUpdates { get; set; } 37 | 38 | [JsonProperty("saveProfileOnStart")] 39 | public bool? SaveProfileOnStart { get; set; } 40 | 41 | [JsonProperty("writeApplicationLogsToFile")] 42 | public bool? WriteApplicationLogsToFile { get; set; } 43 | 44 | [JsonProperty("enablePasswordValidation")] 45 | public bool? EnablePasswordValidation { get; set; } 46 | 47 | [JsonProperty("servers")] 48 | public List Servers { get; set; } 49 | 50 | [JsonProperty("worlds")] 51 | public List Worlds { get; set; } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/GitHubClient.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using ValheimServerGUI.Properties; 6 | using ValheimServerGUI.Tools.Http; 7 | 8 | namespace ValheimServerGUI.Tools 9 | { 10 | public interface IGitHubClient 11 | { 12 | Task GetLatestReleaseAsync(); 13 | } 14 | 15 | public class GitHubClient : RestClient, IGitHubClient 16 | { 17 | public GitHubClient(IRestClientContext context) : base(context) 18 | { 19 | } 20 | 21 | public async Task GetLatestReleaseAsync() 22 | { 23 | var releases = await Get($"{Resources.UrlGithubApi}/releases") 24 | .WithHeader("User-Agent", "ValheimServerGUI") 25 | .SendAsync(); 26 | 27 | if (releases == null) 28 | { 29 | throw new Exception("Unable to reach GitHub."); 30 | } 31 | 32 | var latestRelease = releases 33 | .Where(r => r.Assets != null && r.Assets.Any()) 34 | .Where(r => !r.Prerelease && !r.Draft) 35 | .OrderByDescending(r => r.PublishedAt) 36 | .FirstOrDefault(); 37 | 38 | return latestRelease; 39 | } 40 | } 41 | 42 | public class GitHubRelease 43 | { 44 | [JsonProperty("assets")] 45 | public object[] Assets { get; set; } 46 | 47 | [JsonProperty("body")] 48 | public string Body { get; set; } 49 | 50 | [JsonProperty("draft")] 51 | public bool Draft { get; set; } 52 | 53 | [JsonProperty("html_url")] 54 | public string HtmlUrl { get; set; } 55 | 56 | [JsonProperty("name")] 57 | public string Name { get; set; } 58 | 59 | [JsonProperty("prerelease")] 60 | public bool Prerelease { get; set; } 61 | 62 | [JsonProperty("published_at")] 63 | public DateTime PublishedAt { get; set; } 64 | 65 | [JsonProperty("tag_name")] 66 | public string TagName { get; set; } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Serilog; 7 | using ValheimServerGUI.Serverless.Middleware; 8 | using ValheimServerGUI.Serverless.Services; 9 | using ValheimServerGUI.Tools.Http; 10 | 11 | namespace ValheimServerGUI.Serverless 12 | { 13 | public class Startup 14 | { 15 | public Startup(IConfiguration configuration) 16 | { 17 | Configuration = configuration; 18 | } 19 | 20 | public static IConfiguration Configuration { get; private set; } 21 | 22 | // This method gets called by the runtime. Use this method to add services to the container 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | services.AddControllers().AddNewtonsoftJson(); 26 | 27 | services.AddSingleton(); 28 | services.AddSingleton(); 29 | services.AddSingleton(); 30 | 31 | services.AddSingleton(); 32 | services.AddSingleton(); 33 | } 34 | 35 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline 36 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 37 | { 38 | app.UseHttpsRedirection(); 39 | 40 | app.UseRouting(); 41 | 42 | app.UseAuthorization(); 43 | 44 | app.Use(RuneberryAuthMiddleware.Authorize); 45 | 46 | app.UseEndpoints(endpoints => 47 | { 48 | endpoints.MapControllers(); 49 | endpoints.MapGet("/", async context => 50 | { 51 | await context.Response.WriteAsync("Welcome to running ASP.NET Core on AWS Lambda"); 52 | }); 53 | }); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/SettingsButton.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Controls 2 | { 3 | partial class SettingsButton 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | IconButton = new IconButton(); 32 | SuspendLayout(); 33 | // 34 | // IconButton 35 | // 36 | IconButton.ConfirmImage = null; 37 | IconButton.HelpText = ""; 38 | IconButton.IconClicked = null; 39 | IconButton.Image = Properties.Resources.Settings_16x; 40 | IconButton.Location = new System.Drawing.Point(0, 0); 41 | IconButton.Name = "IconButton"; 42 | IconButton.Size = new System.Drawing.Size(16, 16); 43 | IconButton.TabIndex = 0; 44 | // 45 | // SettingsButton 46 | // 47 | AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 48 | AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 49 | Controls.Add(IconButton); 50 | Name = "SettingsButton"; 51 | Size = new System.Drawing.Size(16, 16); 52 | ResumeLayout(false); 53 | } 54 | 55 | #endregion 56 | 57 | private IconButton IconButton; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/serverless.template: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Transform": "AWS::Serverless-2016-10-31", 4 | "Description": "An AWS Serverless Application that uses the ASP.NET Core framework running in Amazon Lambda.", 5 | "Parameters": {}, 6 | "Conditions": {}, 7 | "Resources": { 8 | "AspNetCoreFunction": { 9 | "Type": "AWS::Serverless::Function", 10 | "Properties": { 11 | "PackageType": "Image", 12 | "ImageConfig": { 13 | "EntryPoint": [ 14 | "/lambda-entrypoint.sh" 15 | ], 16 | "Command": [ 17 | "ValheimServerGUI.Serverless::ValheimServerGUI.Serverless.LambdaEntryPoint::FunctionHandlerAsync" 18 | ] 19 | }, 20 | "ImageUri": "", 21 | "MemorySize": 256, 22 | "Timeout": 30, 23 | "Role": null, 24 | "Policies": [ 25 | "AWSLambda_FullAccess", 26 | "AmazonS3FullAccess", 27 | "CloudWatchLambdaInsightsExecutionRolePolicy" 28 | ], 29 | "Events": { 30 | "ProxyResource": { 31 | "Type": "Api", 32 | "Properties": { 33 | "Path": "/{proxy+}", 34 | "Method": "ANY" 35 | } 36 | }, 37 | "RootResource": { 38 | "Type": "Api", 39 | "Properties": { 40 | "Path": "/", 41 | "Method": "ANY" 42 | } 43 | } 44 | } 45 | }, 46 | "Metadata": { 47 | "Dockerfile": "Dockerfile", 48 | "DockerContext": ".", 49 | "DockerTag": "" 50 | } 51 | }, 52 | "S3Bucket": { 53 | "Type": "AWS::S3::Bucket", 54 | "DeletionPolicy": "Retain", 55 | "Properties": { 56 | "BucketName": "runeberry-valheim-server-gui", 57 | "VersioningConfiguration": { 58 | "Status": "Enabled" 59 | } 60 | } 61 | } 62 | }, 63 | "Outputs": { 64 | "ApiURL": { 65 | "Description": "API endpoint URL for Prod environment", 66 | "Value": { 67 | "Fn::Sub": "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" 68 | } 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Http/RestClientRequestExtensions.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Net.Http; 4 | 5 | namespace ValheimServerGUI.Tools.Http 6 | { 7 | public static class RestClientRequestExtensions 8 | { 9 | public static RestClientRequest WithClientOptions(this RestClientRequest request, Action options) 10 | { 11 | request.ClientBuilders.Add(options); 12 | return request; 13 | } 14 | 15 | public static RestClientRequest WithRequestOptions(this RestClientRequest request, Action options) 16 | { 17 | request.RequestBuilders.Add(options); 18 | return request; 19 | } 20 | 21 | public static RestClientRequest WithResponseType(this RestClientRequest request) 22 | { 23 | request.ResponseContentType = typeof(T); 24 | return request; 25 | } 26 | 27 | public static RestClientRequest WithHeader(this RestClientRequest request, string key, string value) 28 | { 29 | request.RequestBuilders.Add(message => 30 | { 31 | message.Headers.TryAddWithoutValidation(key, value); 32 | }); 33 | 34 | return request; 35 | } 36 | 37 | public static RestClientRequest WithCallback(this RestClientRequest request, EventHandler callback) 38 | { 39 | request.Callbacks.Add(callback); 40 | return request; 41 | } 42 | 43 | public static RestClientRequest WithCallback(this RestClientRequest request, EventHandler callback) 44 | { 45 | request.WithResponseType(); 46 | request.WithCallback((_, message) => 47 | { 48 | if (callback == null) return; 49 | 50 | var responseContent = message.Content.ReadAsStringAsync().GetAwaiter().GetResult(); 51 | var typed = JsonConvert.DeserializeObject(responseContent); 52 | 53 | callback.Invoke(request, typed); 54 | }); 55 | 56 | return request; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/TextFormField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace ValheimServerGUI.Forms.Controls 6 | { 7 | public partial class TextFormField : UserControl, IFormField 8 | { 9 | private const char PasswordChar = '●'; 10 | private const char PasswordCharDisabled = '\0'; 11 | 12 | #region IFormField implementation 13 | 14 | public string LabelText 15 | { 16 | get => Label.Text; 17 | set => Label.Text = value; 18 | } 19 | 20 | [Editor("System.ComponentModel.Design.MultilineStringEditor", "System.Drawing.Design.UITypeEditor")] 21 | public string HelpText 22 | { 23 | get => HelpLabel.Text; 24 | set => HelpLabel.Text = value; 25 | } 26 | 27 | public string Value 28 | { 29 | get => TextBox.Text; 30 | set 31 | { 32 | if (TextBox.Text == value) return; 33 | 34 | TextBox.Text = value; 35 | ValueChanged?.Invoke(this, value); 36 | } 37 | } 38 | 39 | public event EventHandler ValueChanged; 40 | 41 | #endregion 42 | 43 | public bool HideValue 44 | { 45 | get => TextBox.PasswordChar != PasswordCharDisabled; 46 | set => TextBox.PasswordChar = value ? PasswordChar : PasswordCharDisabled; 47 | } 48 | 49 | public int MaxLength 50 | { 51 | get => TextBox.MaxLength; 52 | set => TextBox.MaxLength = value; 53 | } 54 | 55 | public bool Multiline 56 | { 57 | get => TextBox.Multiline; 58 | set => TextBox.Multiline = value; 59 | } 60 | 61 | public TextFormField() 62 | { 63 | InitializeComponent(); 64 | 65 | TextBox.TextChanged += OnTextChanged; 66 | } 67 | 68 | public void SelectAll() 69 | { 70 | TextBox.SelectAll(); 71 | } 72 | 73 | private void OnTextChanged(object sender, EventArgs args) 74 | { 75 | ValueChanged?.Invoke(this, Value); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tests/BaseTest.Events.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Threading.Tasks; 4 | 5 | namespace ValheimServerGUI.Tests 6 | { 7 | public partial class BaseTest 8 | { 9 | protected async Task ListenForEventAsync(Action assigner, Action optionsBuilder = null) 10 | { 11 | var options = new EventListenerOptions(); 12 | optionsBuilder?.Invoke(options); 13 | 14 | var resolved = false; 15 | 16 | EventHandler handler = (_, _) => resolved = true; 17 | assigner(handler); 18 | 19 | var sw = Stopwatch.StartNew(); 20 | 21 | do 22 | { 23 | CheckTimeout(sw, options); 24 | await Task.Delay(options.Interval); 25 | } 26 | while (!resolved); 27 | } 28 | 29 | protected async Task ListenForEventAsync(Action> assigner, Action optionsBuilder = null) 30 | { 31 | var options = new EventListenerOptions(); 32 | optionsBuilder?.Invoke(options); 33 | 34 | var resolved = false; 35 | TArgs eventArgs = default; 36 | 37 | EventHandler handler = (_, args) => 38 | { 39 | resolved = true; 40 | eventArgs = args; 41 | }; 42 | assigner(handler); 43 | 44 | var sw = Stopwatch.StartNew(); 45 | 46 | do 47 | { 48 | CheckTimeout(sw, options); 49 | await Task.Delay(options.Interval); 50 | } 51 | while (!resolved); 52 | 53 | return eventArgs; 54 | } 55 | 56 | private void CheckTimeout(Stopwatch sw, EventListenerOptions options) 57 | { 58 | if (sw.ElapsedMilliseconds > options.Timeout) 59 | { 60 | throw new TimeoutException($"The event was not fired during the timeout period ({options.Timeout}ms)."); 61 | } 62 | } 63 | 64 | public class EventListenerOptions 65 | { 66 | public int Timeout { get; set; } = 1000; 67 | 68 | public int Interval { get; set; } = 50; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/CopyButton.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Forms 2 | { 3 | partial class CopyButton 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.IconButton = new ValheimServerGUI.Controls.IconButton(); 32 | this.SuspendLayout(); 33 | // 34 | // iconButton1 35 | // 36 | this.IconButton.ConfirmImage = global::ValheimServerGUI.Properties.Resources.StatusOK_16x; 37 | this.IconButton.HelpText = ""; 38 | this.IconButton.Image = global::ValheimServerGUI.Properties.Resources.Copy_16x; 39 | this.IconButton.Location = new System.Drawing.Point(0, 0); 40 | this.IconButton.Name = "iconButton1"; 41 | this.IconButton.Size = new System.Drawing.Size(16, 16); 42 | this.IconButton.TabIndex = 0; 43 | // 44 | // CopyButton 45 | // 46 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 47 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 48 | this.Controls.Add(this.IconButton); 49 | this.Name = "CopyButton"; 50 | this.Size = new System.Drawing.Size(16, 16); 51 | this.ResumeLayout(false); 52 | 53 | } 54 | 55 | #endregion 56 | 57 | private ValheimServerGUI.Controls.IconButton IconButton; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tests/BaseTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.DependencyInjection.Extensions; 3 | using System; 4 | using System.Windows.Forms; 5 | using ValheimServerGUI.Game; 6 | using ValheimServerGUI.Tests.Tools; 7 | using ValheimServerGUI.Tools; 8 | using ValheimServerGUI.Tools.Data; 9 | using ValheimServerGUI.Tools.Http; 10 | using ValheimServerGUI.Tools.Processes; 11 | 12 | namespace ValheimServerGUI.Tests 13 | { 14 | public partial class BaseTest 15 | { 16 | protected IServiceCollection ServiceCollection { get; } 17 | 18 | protected IServiceProvider ServiceProvider { get; } 19 | 20 | protected MockDataFileProvider MockDataFileProvider { get; } 21 | 22 | protected MockHttpClientProvider MockHttpClientProvider { get; } 23 | 24 | protected MockProcessProvider MockProcessProvider { get; } 25 | 26 | protected MockUserPreferencesProvider MockUserPreferencesProvider { get; } 27 | 28 | public BaseTest() 29 | { 30 | ServiceCollection = new ServiceCollection(); 31 | Program.ConfigureServices(ServiceCollection, Array.Empty()); 32 | 33 | MockDataFileProvider = new(); 34 | MockProcessProvider = new(); 35 | MockHttpClientProvider = new(); 36 | MockUserPreferencesProvider = new(); 37 | 38 | ServiceCollection.Replace(ServiceDescriptor.Singleton(MockDataFileProvider)); 39 | ServiceCollection.Replace(ServiceDescriptor.Singleton(MockProcessProvider)); 40 | ServiceCollection.Replace(ServiceDescriptor.Singleton(MockHttpClientProvider)); 41 | ServiceCollection.Replace(ServiceDescriptor.Singleton(MockUserPreferencesProvider)); 42 | 43 | ServiceProvider = ServiceCollection.BuildServiceProvider(); 44 | } 45 | 46 | protected TService GetService() 47 | { 48 | return ServiceProvider.GetRequiredService(); 49 | } 50 | 51 | protected TForm GetForm() where TForm : Form 52 | { 53 | var formProvider = ServiceProvider.GetRequiredService(); 54 | return formProvider.GetForm(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/OpenButton.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Forms 2 | { 3 | partial class OpenButton 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.IconButton = new ValheimServerGUI.Controls.IconButton(); 32 | this.SuspendLayout(); 33 | // 34 | // IconButton 35 | // 36 | this.IconButton.ConfirmImage = null; 37 | this.IconButton.HelpText = "Open this folder in Explorer"; 38 | this.IconButton.IconClicked = null; 39 | this.IconButton.Image = global::ValheimServerGUI.Properties.Resources.OpenFolder_16x; 40 | this.IconButton.Location = new System.Drawing.Point(0, 0); 41 | this.IconButton.Name = "IconButton"; 42 | this.IconButton.Size = new System.Drawing.Size(16, 16); 43 | this.IconButton.TabIndex = 0; 44 | // 45 | // OpenButton 46 | // 47 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 49 | this.Controls.Add(this.IconButton); 50 | this.Name = "OpenButton"; 51 | this.Size = new System.Drawing.Size(16, 16); 52 | this.ResumeLayout(false); 53 | 54 | } 55 | 56 | #endregion 57 | 58 | private ValheimServerGUI.Controls.IconButton IconButton; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/NumericFormField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows.Forms; 4 | 5 | namespace ValheimServerGUI.Controls 6 | { 7 | public partial class NumericFormField : UserControl, IFormField 8 | { 9 | #region IFormField implementation 10 | 11 | public string LabelText 12 | { 13 | get => Label.Text; 14 | set => Label.Text = value; 15 | } 16 | 17 | [Editor("System.ComponentModel.Design.MultilineStringEditor", "System.Drawing.Design.UITypeEditor")] 18 | public string HelpText 19 | { 20 | get => HelpLabel.Text; 21 | set => HelpLabel.Text = value; 22 | } 23 | 24 | public int Value 25 | { 26 | get => GetValidatedValue((int)NumericUpDown.Value); 27 | set 28 | { 29 | var validValue = GetValidatedValue(value); 30 | if (validValue != NumericUpDown.Value) 31 | { 32 | NumericUpDown.Value = validValue; 33 | ValueChanged?.Invoke(this, Value); 34 | } 35 | } 36 | } 37 | 38 | public event EventHandler ValueChanged; 39 | 40 | #endregion 41 | 42 | public int Minimum 43 | { 44 | get => (int)NumericUpDown.Minimum; 45 | set => NumericUpDown.Minimum = value; 46 | } 47 | 48 | public int Maximum 49 | { 50 | get => (int)NumericUpDown.Maximum; 51 | set => NumericUpDown.Maximum = value; 52 | } 53 | 54 | public NumericFormField() 55 | { 56 | InitializeComponent(); 57 | 58 | NumericUpDown.ValueChanged += OnValueChanged; 59 | } 60 | 61 | private void OnValueChanged(object sender, EventArgs args) 62 | { 63 | ValueChanged?.Invoke(this, Value); 64 | } 65 | 66 | private int GetValidatedValue(int val) 67 | { 68 | if (val < NumericUpDown.Minimum) 69 | { 70 | val = (int)NumericUpDown.Minimum; 71 | } 72 | else if (val > NumericUpDown.Maximum) 73 | { 74 | val = (int)NumericUpDown.Maximum; 75 | } 76 | 77 | return val; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/EditButton.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Forms 2 | { 3 | partial class EditButton 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.IconButton = new ValheimServerGUI.Controls.IconButton(); 32 | this.SuspendLayout(); 33 | // 34 | // IconButton 35 | // 36 | this.IconButton.ConfirmImage = global::ValheimServerGUI.Properties.Resources.StatusOK_16x; 37 | this.IconButton.HelpText = "Edit"; 38 | this.IconButton.IconClicked = null; 39 | this.IconButton.Image = global::ValheimServerGUI.Properties.Resources.Edit_16x; 40 | this.IconButton.Location = new System.Drawing.Point(0, 0); 41 | this.IconButton.Name = "IconButton"; 42 | this.IconButton.Size = new System.Drawing.Size(16, 16); 43 | this.IconButton.TabIndex = 0; 44 | // 45 | // EditButton 46 | // 47 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 49 | this.Controls.Add(this.IconButton); 50 | this.Name = "EditButton"; 51 | this.Size = new System.Drawing.Size(16, 16); 52 | this.ResumeLayout(false); 53 | 54 | } 55 | 56 | #endregion 57 | 58 | private ValheimServerGUI.Controls.IconButton IconButton; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/RefreshButton.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Forms 2 | { 3 | partial class RefreshButton 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.IconButton = new ValheimServerGUI.Controls.IconButton(); 32 | this.SuspendLayout(); 33 | // 34 | // IconButton 35 | // 36 | this.IconButton.ConfirmImage = global::ValheimServerGUI.Properties.Resources.StatusOK_16x; 37 | this.IconButton.HelpText = "Refresh"; 38 | this.IconButton.IconClicked = null; 39 | this.IconButton.Image = global::ValheimServerGUI.Properties.Resources.Restart_16x; 40 | this.IconButton.Location = new System.Drawing.Point(0, 0); 41 | this.IconButton.Name = "IconButton"; 42 | this.IconButton.Size = new System.Drawing.Size(16, 16); 43 | this.IconButton.TabIndex = 0; 44 | // 45 | // RefreshButton 46 | // 47 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 49 | this.Controls.Add(this.IconButton); 50 | this.Name = "RefreshButton"; 51 | this.Size = new System.Drawing.Size(16, 16); 52 | this.ResumeLayout(false); 53 | 54 | } 55 | 56 | #endregion 57 | 58 | private ValheimServerGUI.Controls.IconButton IconButton; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ValheimServerGUI.Tools/Processes/ProcessExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace ValheimServerGUI.Tools.Processes 4 | { 5 | public static class ProcessExtensions 6 | { 7 | // todo: Validate that taskkill exists on the system and that the user can access it 8 | private const string KillCommand = "taskkill"; 9 | 10 | public static Process AddBackgroundProcess(this IProcessProvider provider, string key, string command, string args) 11 | { 12 | var process = new Process 13 | { 14 | EnableRaisingEvents = true, 15 | StartInfo = 16 | { 17 | FileName = command, 18 | Arguments = args, 19 | CreateNoWindow = true, 20 | UseShellExecute = false, 21 | RedirectStandardError = true, 22 | RedirectStandardOutput = true, 23 | }, 24 | }; 25 | 26 | provider.AddProcess(key, process); 27 | 28 | return provider.GetProcess(key); 29 | } 30 | 31 | /// 32 | /// Starts a secondary process to safely kill the provided process. 33 | /// Returns the provided process. 34 | /// 35 | public static Process SafelyKillProcess(this IProcessProvider provider, Process process) 36 | { 37 | if (process != null) 38 | { 39 | var killProcess = provider.AddBackgroundProcess($"{KillCommand}-{process.Id}", KillCommand, $"/pid {process.Id}"); 40 | 41 | // todo: Send output to application logs 42 | provider.StartIO(killProcess); 43 | } 44 | 45 | return process; 46 | } 47 | 48 | /// 49 | /// Starts a secondary process to safely kill the process with the specified key. 50 | /// Returns the process with the specified key, which you can then wait for to exit. 51 | /// 52 | public static Process SafelyKillProcess(this IProcessProvider provider, string key) 53 | { 54 | return provider.SafelyKillProcess(provider.GetProcess(key)); 55 | } 56 | 57 | public static bool IsProcessRunning(this IProcessProvider provider, string key) 58 | { 59 | var process = provider.GetProcess(key); 60 | 61 | if (process == null) return false; 62 | 63 | return !process.HasExited; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/IconButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | 6 | namespace ValheimServerGUI.Controls 7 | { 8 | public partial class IconButton : UserControl 9 | { 10 | public Image Image { get; set; } 11 | 12 | public Image ConfirmImage { get; set; } 13 | 14 | [Browsable(false)] 15 | public Func IconClicked { get; set; } 16 | 17 | public string HelpText 18 | { 19 | get => ToolTip.GetToolTip(PictureBox); 20 | set => ToolTip.SetToolTip(PictureBox, value); 21 | } 22 | 23 | private static readonly ToolTip ToolTip = new(); 24 | private bool IsLocked; 25 | 26 | public IconButton() 27 | { 28 | InitializeComponent(); 29 | VisibleChanged += OnVisibleChanged; 30 | } 31 | 32 | private void OnVisibleChanged(object sender, EventArgs e) 33 | { 34 | SetImage(Image, Cursors.Hand); 35 | 36 | PictureBox.Click += PictureBox_Click; 37 | Timer.Tick += Timer_Tick; 38 | 39 | // Only run the first time the control is shown 40 | VisibleChanged -= OnVisibleChanged; 41 | } 42 | 43 | protected void PictureBox_Click(object sender, EventArgs args) 44 | { 45 | if (IsLocked || IconClicked == null) return; 46 | 47 | try 48 | { 49 | if (IconClicked.Invoke()) 50 | { 51 | ShowConfirm(); 52 | } 53 | } 54 | catch 55 | { 56 | // Suppress all errors 57 | } 58 | } 59 | 60 | protected void Timer_Tick(object sender, EventArgs args) 61 | { 62 | if (!IsLocked) return; 63 | 64 | SetImage(Image, Cursors.Hand); 65 | Timer.Stop(); 66 | IsLocked = false; 67 | } 68 | 69 | private void SetImage(Image image, Cursor cursor) 70 | { 71 | PictureBox.Image = image; 72 | PictureBox.Cursor = cursor; 73 | PictureBox.Refresh(); 74 | PictureBox.Visible = true; 75 | } 76 | 77 | private void ShowConfirm() 78 | { 79 | if (IsLocked || ConfirmImage == null) return; 80 | 81 | SetImage(ConfirmImage, Cursors.Default); 82 | Timer.Start(); 83 | IsLocked = true; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/RadioFormField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Windows.Forms; 6 | using ValheimServerGUI.Extensions; 7 | 8 | namespace ValheimServerGUI.Controls 9 | { 10 | public partial class RadioFormField : UserControl, IFormField 11 | { 12 | #region IFormField implementation 13 | 14 | public string LabelText 15 | { 16 | get => RadioButton.Text; 17 | set => RadioButton.Text = value; 18 | } 19 | 20 | [Editor("System.ComponentModel.Design.MultilineStringEditor", "System.Drawing.Design.UITypeEditor")] 21 | public string HelpText 22 | { 23 | get => HelpLabel.Text; 24 | set => HelpLabel.Text = value; 25 | } 26 | 27 | public bool Value 28 | { 29 | get => RadioButton.Checked; 30 | set 31 | { 32 | if (value == Value) return; 33 | 34 | RadioButton.Checked = value; 35 | ValueChanged?.Invoke(this, value); 36 | } 37 | } 38 | 39 | public event EventHandler ValueChanged; 40 | 41 | #endregion 42 | 43 | public string GroupName { get; set; } 44 | 45 | public IReadOnlyList RadioGroup { get; private set; } 46 | 47 | public RadioFormField() 48 | { 49 | InitializeComponent(); 50 | 51 | RadioButton.CheckedChanged += RadioButton_Changed; 52 | } 53 | 54 | public void RefreshRadioGroup() 55 | { 56 | RadioGroup = FindForm() 57 | .FindAllControls() 58 | .Where(r => r.GroupName == GroupName) 59 | .ToList(); 60 | } 61 | 62 | protected override void OnVisibleChanged(EventArgs e) 63 | { 64 | base.OnVisibleChanged(e); 65 | 66 | if (Visible && RadioGroup == null) 67 | { 68 | RefreshRadioGroup(); 69 | } 70 | } 71 | 72 | private void RadioButton_Changed(object sender, EventArgs e) 73 | { 74 | ValueChanged?.Invoke(this, Value); 75 | 76 | if (Value && RadioGroup != null) 77 | { 78 | foreach (var other in RadioGroup.Where(r => r != this)) 79 | { 80 | other.Value = false; 81 | } 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/PathExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace ValheimServerGUI.Tools 5 | { 6 | public static class PathExtensions 7 | { 8 | private static readonly string NL = Environment.NewLine; 9 | 10 | public static FileInfo GetFileInfo(string path, string extension = null) 11 | { 12 | path = Environment.ExpandEnvironmentVariables(path); 13 | 14 | if (string.IsNullOrWhiteSpace(path)) 15 | { 16 | throw new ArgumentException($"Cannot open file, path is not defined."); 17 | } 18 | 19 | if (extension != null && !Path.HasExtension(path)) 20 | { 21 | throw new ArgumentException($"Cannot open file, must point to a valid {extension} file:{NL}{path}"); 22 | } 23 | 24 | if (!File.Exists(path)) 25 | { 26 | throw new FileNotFoundException($"File not found at path:{NL}{path}"); 27 | } 28 | 29 | return new FileInfo(path); 30 | } 31 | 32 | public static DirectoryInfo GetDirectoryInfo(string path, bool checkExists = false) 33 | { 34 | path = Environment.ExpandEnvironmentVariables(path); 35 | 36 | if (string.IsNullOrWhiteSpace(path)) 37 | { 38 | throw new ArgumentException($"Cannot open directory, path is not defined."); 39 | } 40 | 41 | if (checkExists && !Directory.Exists(path)) 42 | { 43 | throw new DirectoryNotFoundException($"Directory not found at path:{NL}{path}"); 44 | } 45 | 46 | return new DirectoryInfo(path); 47 | } 48 | 49 | public static string GetValidFileName(string filename, bool addTimestamp = false) 50 | { 51 | if (string.IsNullOrWhiteSpace(filename)) 52 | { 53 | return "file"; 54 | } 55 | 56 | if (filename.Length > 150) 57 | { 58 | // Max filename length is likely closer to 255, but I'm just gonna play it safe 59 | filename = filename[..150]; 60 | } 61 | 62 | if (addTimestamp) 63 | { 64 | filename = $"{filename}_{DateTime.Now.ToFilenameISOFormat()}"; 65 | } 66 | 67 | foreach (var c in Path.GetInvalidFileNameChars()) 68 | { 69 | filename = filename.Replace(c, '-'); 70 | } 71 | 72 | return filename; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/LambdaEntryPoint.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace ValheimServerGUI.Serverless 5 | { 6 | /// 7 | /// This class extends from APIGatewayProxyFunction which contains the method FunctionHandlerAsync which is the 8 | /// actual Lambda function entry point. The Lambda handler field should be set to 9 | /// 10 | /// ValheimServerGUI.Serverless::ValheimServerGUI.Serverless.LambdaEntryPoint::FunctionHandlerAsync 11 | /// 12 | public class LambdaEntryPoint : 13 | 14 | // The base class must be set to match the AWS service invoking the Lambda function. If not Amazon.Lambda.AspNetCoreServer 15 | // will fail to convert the incoming request correctly into a valid ASP.NET Core request. 16 | // 17 | // API Gateway REST API -> Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction 18 | // API Gateway HTTP API payload version 1.0 -> Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction 19 | // API Gateway HTTP API payload version 2.0 -> Amazon.Lambda.AspNetCoreServer.APIGatewayHttpApiV2ProxyFunction 20 | // Application Load Balancer -> Amazon.Lambda.AspNetCoreServer.ApplicationLoadBalancerFunction 21 | // 22 | // Note: When using the AWS::Serverless::Function resource with an event type of "HttpApi" then payload version 2.0 23 | // will be the default and you must make Amazon.Lambda.AspNetCoreServer.APIGatewayHttpApiV2ProxyFunction the base class. 24 | 25 | Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction 26 | { 27 | /// 28 | /// The builder has configuration, logging and Amazon API Gateway already configured. The startup class 29 | /// needs to be configured in this method using the UseStartup<>() method. 30 | /// 31 | /// 32 | protected override void Init(IWebHostBuilder builder) 33 | { 34 | builder 35 | .UseStartup(); 36 | } 37 | 38 | /// 39 | /// Use this override to customize the services registered with the IHostBuilder. 40 | /// 41 | /// It is recommended not to call ConfigureWebHostDefaults to configure the IWebHostBuilder inside this method. 42 | /// Instead customize the IWebHostBuilder in the Init(IWebHostBuilder) overload. 43 | /// 44 | /// 45 | protected override void Init(IHostBuilder builder) 46 | { 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/Services/XboxApiClient.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using ValheimServerGUI.Properties; 7 | using ValheimServerGUI.Tools.Http; 8 | using ValheimServerGUI.Tools.Models; 9 | 10 | namespace ValheimServerGUI.Serverless.Services 11 | { 12 | public interface IXboxApiClient 13 | { 14 | Task GetPlayerSummary(string xuid); 15 | } 16 | 17 | /// 18 | /// Client for interacting with the OpenXBL API. 19 | /// 20 | /// 21 | /// Reference the Swagger page at: https://xbl.io/console 22 | /// 23 | public class XboxApiClient : RestClient, IXboxApiClient 24 | { 25 | public XboxApiClient(IRestClientContext context) : base(context) 26 | { 27 | } 28 | 29 | public async Task GetPlayerSummary(string xuid) 30 | { 31 | if (string.IsNullOrWhiteSpace(xuid)) 32 | { 33 | throw new ArgumentNullException(nameof(xuid)); 34 | } 35 | 36 | var response = await Get($"https://xbl.io/api/v2/player/summary/{xuid}") 37 | .WithHeader("x-authorization", ServerSecrets.XboxApiKey) 38 | .SendAsync(); 39 | 40 | if (response == null) 41 | { 42 | throw new Exception($"Unsuccessful request with xuid: {xuid}"); 43 | } 44 | 45 | if (response.People == null || !response.People.Any()) 46 | { 47 | throw new Exception($"No players on response for xuid: {xuid}"); 48 | } 49 | 50 | var person = response.People.FirstOrDefault(p => p.Xuid == xuid); 51 | if (person == null) 52 | { 53 | throw new Exception($"No players matching xuid on response for: {xuid}"); 54 | } 55 | 56 | return new PlayerInfoResponse(PlayerPlatforms.Xbox, person.Xuid, person.DisplayName); 57 | } 58 | 59 | #region Nested symbols 60 | 61 | private class XboxPlayerSummaryResponse 62 | { 63 | [JsonProperty("people")] 64 | public List People { get; set; } 65 | 66 | public class Person 67 | { 68 | [JsonProperty("xuid")] 69 | public string Xuid { get; set; } 70 | 71 | [JsonProperty("displayName")] 72 | public string DisplayName { get; set; } 73 | } 74 | } 75 | 76 | #endregion 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/IconButton.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ValheimServerGUI.Controls 2 | { 3 | partial class IconButton 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.Timer = new System.Windows.Forms.Timer(this.components); 33 | this.PictureBox = new System.Windows.Forms.PictureBox(); 34 | ((System.ComponentModel.ISupportInitialize)(this.PictureBox)).BeginInit(); 35 | this.SuspendLayout(); 36 | // 37 | // Timer 38 | // 39 | this.Timer.Interval = 2000; 40 | // 41 | // PictureBox 42 | // 43 | this.PictureBox.Cursor = System.Windows.Forms.Cursors.Hand; 44 | this.PictureBox.InitialImage = null; 45 | this.PictureBox.Location = new System.Drawing.Point(0, 0); 46 | this.PictureBox.Name = "PictureBox"; 47 | this.PictureBox.Size = new System.Drawing.Size(16, 16); 48 | this.PictureBox.TabIndex = 0; 49 | this.PictureBox.TabStop = false; 50 | // 51 | // IconButton 52 | // 53 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 54 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 55 | this.Controls.Add(this.PictureBox); 56 | this.Name = "IconButton"; 57 | this.Size = new System.Drawing.Size(16, 16); 58 | ((System.ComponentModel.ISupportInitialize)(this.PictureBox)).EndInit(); 59 | this.ResumeLayout(false); 60 | 61 | } 62 | 63 | #endregion 64 | protected System.Windows.Forms.PictureBox PictureBox; 65 | protected System.Windows.Forms.Timer Timer; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/LabelField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | 6 | namespace ValheimServerGUI.Controls 7 | { 8 | public partial class LabelField : UserControl, IFormField 9 | { 10 | #region IFormField implementation 11 | 12 | public string LabelText 13 | { 14 | get => FormLabel.Text; 15 | set => FormLabel.Text = value; 16 | } 17 | 18 | [Editor("System.ComponentModel.Design.MultilineStringEditor", "System.Drawing.Design.UITypeEditor")] 19 | public string HelpText 20 | { 21 | get => HelpLabel.Text; 22 | set => HelpLabel.Text = value; 23 | } 24 | 25 | public string Value 26 | { 27 | get => ValueLabel.Text; 28 | set 29 | { 30 | if (ValueLabel.Text == value) return; 31 | 32 | ValueLabel.Text = value; 33 | ValueChanged?.Invoke(this, value); 34 | } 35 | } 36 | 37 | public event EventHandler ValueChanged; 38 | 39 | #endregion 40 | 41 | private double _lsr = 0.5; 42 | public double LabelSplitRatio 43 | { 44 | get => _lsr; 45 | set 46 | { 47 | _lsr = value; 48 | ResizeLabels(); 49 | } 50 | } 51 | 52 | public ContentAlignment LabelTextAlign 53 | { 54 | get => FormLabel.TextAlign; 55 | set => FormLabel.TextAlign = value; 56 | } 57 | 58 | public ContentAlignment ValueTextAlign 59 | { 60 | get => ValueLabel.TextAlign; 61 | set => ValueLabel.TextAlign = value; 62 | } 63 | 64 | public LabelField() 65 | { 66 | InitializeComponent(); 67 | 68 | ResizeLabels(); 69 | } 70 | 71 | protected override void OnResize(EventArgs e) 72 | { 73 | base.OnResize(e); 74 | 75 | ResizeLabels(); 76 | } 77 | 78 | private void ResizeLabels() 79 | { 80 | var fillWidth = Width - FormLabel.Location.X - HelpLabel.Width; 81 | var split = Math.Min(1.0, Math.Max(0.0, LabelSplitRatio)); 82 | 83 | // The Label and Value should each fill up 50% of the available space 84 | FormLabel.Width = (int)(fillWidth * split); 85 | ValueLabel.Width = (int)(fillWidth * (1 - split)); 86 | 87 | // The Value should always be anchored directly to the right of the Label 88 | var locX = FormLabel.Location.X + FormLabel.Width; 89 | ValueLabel.Location = new Point(locX, ValueLabel.Location.Y); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/LogViewer.Designer.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace ValheimServerGUI.Controls 3 | { 4 | partial class LogViewer 5 | { 6 | /// 7 | /// Required designer variable. 8 | /// 9 | private System.ComponentModel.IContainer components = null; 10 | 11 | /// 12 | /// Clean up any resources being used. 13 | /// 14 | /// true if managed resources should be disposed; otherwise, false. 15 | protected override void Dispose(bool disposing) 16 | { 17 | if (disposing && (components != null)) 18 | { 19 | components.Dispose(); 20 | } 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Component Designer generated code 25 | 26 | /// 27 | /// Required method for Designer support - do not modify 28 | /// the contents of this method with the code editor. 29 | /// 30 | private void InitializeComponent() 31 | { 32 | this.TextBox = new System.Windows.Forms.TextBox(); 33 | this.SuspendLayout(); 34 | // 35 | // TextBox 36 | // 37 | this.TextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 38 | | System.Windows.Forms.AnchorStyles.Left) 39 | | System.Windows.Forms.AnchorStyles.Right))); 40 | this.TextBox.BackColor = System.Drawing.SystemColors.Window; 41 | this.TextBox.Font = new System.Drawing.Font("Lucida Console", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); 42 | this.TextBox.Location = new System.Drawing.Point(0, 0); 43 | this.TextBox.Multiline = true; 44 | this.TextBox.Name = "TextBox"; 45 | this.TextBox.ReadOnly = true; 46 | this.TextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; 47 | this.TextBox.Size = new System.Drawing.Size(300, 150); 48 | this.TextBox.TabIndex = 0; 49 | this.TextBox.TabStop = false; 50 | // 51 | // LogViewer 52 | // 53 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 54 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 55 | this.Controls.Add(this.TextBox); 56 | this.Name = "LogViewer"; 57 | this.Size = new System.Drawing.Size(300, 150); 58 | this.ResumeLayout(false); 59 | this.PerformLayout(); 60 | 61 | } 62 | 63 | #endregion 64 | 65 | private System.Windows.Forms.TextBox TextBox; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ValheimServerGUI.Serverless/Services/SteamApiClient.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using ValheimServerGUI.Properties; 7 | using ValheimServerGUI.Tools.Http; 8 | using ValheimServerGUI.Tools.Models; 9 | 10 | namespace ValheimServerGUI.Serverless.Services 11 | { 12 | public interface ISteamApiClient 13 | { 14 | Task GetPlayerSummary(string steamId); 15 | } 16 | 17 | public class SteamApiClient : RestClient, ISteamApiClient 18 | { 19 | public SteamApiClient(IRestClientContext context) : base(context) 20 | { 21 | } 22 | 23 | public async Task GetPlayerSummary(string steamId) 24 | { 25 | if (string.IsNullOrWhiteSpace(steamId)) 26 | { 27 | throw new ArgumentNullException(nameof(steamId)); 28 | } 29 | 30 | var response = await Get($"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?steamids={steamId}") 31 | .WithHeader("x-webapi-key", ServerSecrets.SteamApiKey) 32 | .SendAsync(); 33 | 34 | if (response == null) 35 | { 36 | throw new Exception($"Unsuccessful request with steamId: {steamId}"); 37 | } 38 | 39 | if (response.Response == null || response.Response.Players == null || !response.Response.Players.Any()) 40 | { 41 | throw new Exception($"No players on response for steamId: {steamId}"); 42 | } 43 | 44 | var person = response.Response.Players.FirstOrDefault(p => p.SteamId == steamId); 45 | if (person == null) 46 | { 47 | throw new Exception($"No players matching steamId on response for: {steamId}"); 48 | } 49 | 50 | return new PlayerInfoResponse(PlayerPlatforms.Steam, person.SteamId, person.PersonaName); 51 | } 52 | 53 | #region Nested symbols 54 | 55 | private class SteamPlayerSummaryResponse 56 | { 57 | [JsonProperty("response")] 58 | public ResponseObject Response { get; set; } 59 | 60 | public class ResponseObject 61 | { 62 | [JsonProperty("players")] 63 | public List Players { get; set; } 64 | 65 | public class Player 66 | { 67 | [JsonProperty("steamid")] 68 | public string SteamId { get; set; } 69 | 70 | [JsonProperty("personaname")] 71 | public string PersonaName { get; set; } 72 | } 73 | } 74 | } 75 | 76 | #endregion 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/HelpLabel.Designer.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace ValheimServerGUI.Controls 3 | { 4 | partial class HelpLabel 5 | { 6 | /// 7 | /// Required designer variable. 8 | /// 9 | private System.ComponentModel.IContainer components = null; 10 | 11 | /// 12 | /// Clean up any resources being used. 13 | /// 14 | /// true if managed resources should be disposed; otherwise, false. 15 | protected override void Dispose(bool disposing) 16 | { 17 | if (disposing && (components != null)) 18 | { 19 | components.Dispose(); 20 | } 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Component Designer generated code 25 | 26 | /// 27 | /// Required method for Designer support - do not modify 28 | /// the contents of this method with the code editor. 29 | /// 30 | private void InitializeComponent() 31 | { 32 | this.components = new System.ComponentModel.Container(); 33 | this.Label = new System.Windows.Forms.Label(); 34 | this.ToolTip = new System.Windows.Forms.ToolTip(this.components); 35 | this.SuspendLayout(); 36 | // 37 | // Label 38 | // 39 | this.Label.AutoSize = true; 40 | this.Label.Location = new System.Drawing.Point(0, 0); 41 | this.Label.Name = "Label"; 42 | this.Label.Size = new System.Drawing.Size(12, 15); 43 | this.Label.TabIndex = 0; 44 | this.Label.Text = "?"; 45 | this.Label.Visible = false; 46 | // 47 | // ToolTip 48 | // 49 | this.ToolTip.AutoPopDelay = 30000; 50 | this.ToolTip.InitialDelay = 100; 51 | this.ToolTip.ReshowDelay = 100; 52 | // 53 | // HelpLabel 54 | // 55 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); 56 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 57 | this.Controls.Add(this.Label); 58 | this.Font = new System.Drawing.Font("Segoe UI", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Underline))), System.Drawing.GraphicsUnit.Point); 59 | this.ForeColor = System.Drawing.SystemColors.HotTrack; 60 | this.Name = "HelpLabel"; 61 | this.Size = new System.Drawing.Size(12, 15); 62 | this.ResumeLayout(false); 63 | this.PerformLayout(); 64 | 65 | } 66 | 67 | #endregion 68 | 69 | private System.Windows.Forms.Label Label; 70 | private System.Windows.Forms.ToolTip ToolTip; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ValheimServerGUI/Tools/RuneberryApiClient.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Threading.Tasks; 4 | using ValheimServerGUI.Properties; 5 | using ValheimServerGUI.Tools.Http; 6 | using ValheimServerGUI.Tools.Models; 7 | 8 | namespace ValheimServerGUI.Tools 9 | { 10 | public interface IRuneberryApiClient 11 | { 12 | event EventHandler PlayerInfoAvailable; 13 | 14 | Task RequestPlayerInfoAsync(string platform, string playerId); 15 | 16 | Task SendCrashReportAsync(CrashReport report); 17 | } 18 | 19 | public class RuneberryApiClient : RestClient, IRuneberryApiClient 20 | { 21 | public RuneberryApiClient(IRestClientContext context) : base(context) 22 | { 23 | } 24 | 25 | #region IRuneberryApiClient implementation 26 | 27 | public event EventHandler PlayerInfoAvailable; 28 | 29 | public async Task RequestPlayerInfoAsync(string platform, string playerId) 30 | { 31 | var response = await Get($"{Resources.UrlRuneberryApi}/player-info?platform={platform}&playerId={playerId}") 32 | .WithHeader(ClientSecrets.RuneberryApiKeyHeader, ClientSecrets.RuneberryClientApiKey) 33 | .SendAsync(); 34 | 35 | if (response == null) 36 | { 37 | Logger.Error($"Unable to get info for {platform} player with ID {playerId}"); 38 | return; 39 | } 40 | 41 | PlayerInfoAvailable?.Invoke(this, response); 42 | } 43 | 44 | public async Task SendCrashReportAsync(CrashReport report) 45 | { 46 | var response = await Post($"{Resources.UrlRuneberryApi}/crash-report", report) 47 | .WithHeader(ClientSecrets.RuneberryApiKeyHeader, ClientSecrets.RuneberryClientApiKey) 48 | .SendAsync(); 49 | 50 | if (response == null || !response.IsSuccessStatusCode) 51 | { 52 | string message; 53 | 54 | try 55 | { 56 | if (response != null) 57 | { 58 | var rawResponse = await response.Content.ReadAsStringAsync(); 59 | var exceptionResponse = JsonConvert.DeserializeObject(rawResponse); 60 | message = $"({(int)response.StatusCode}) {exceptionResponse.Message}"; 61 | } 62 | else 63 | { 64 | message = "Unable to reach Runeberry API"; 65 | } 66 | } 67 | catch 68 | { 69 | message = "Unknown error"; 70 | } 71 | 72 | throw new Exception(message); 73 | } 74 | } 75 | 76 | #endregion 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ValheimServerGUI/ValheimServerGUI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net6.0-windows 6 | true 7 | Resources\ApplicationIcon.ico 8 | Runeberry Software, LLC 9 | ValheimServerGUI 10 | A simple user interface for running Valheim Dedicated Server on Windows. 11 | 2022 12 | GNU GPLv3 13 | 2.3.1 14 | 15 | build$([System.DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")) 16 | 17 | 18 | 19 | true 20 | ..\SolutionResources\ValheimServerGUI.snk 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | True 50 | True 51 | Resources.resx 52 | 53 | 54 | 55 | 56 | 57 | ResXFileCodeGenerator 58 | Resources.Designer.cs 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /ValheimServerGUI/Forms/AboutForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI/Forms/SplashForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/CopyButton.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/EditButton.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/OpenButton.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI/Controls/RefreshButton.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI/Forms/TextPromptPopout.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/DataListView.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/HelpLabel.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/IconButton.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/LabelField.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/LogViewer.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/TextFormField.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/CheckboxFormField.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/DropdownFormField.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/FilenameFormField.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/NumericFormField.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/RadioFormField.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | text/microsoft-resx 50 | 51 | 52 | 2.0 53 | 54 | 55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 56 | 57 | 58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 59 | 60 | -------------------------------------------------------------------------------- /ValheimServerGUI.Controls/Controls/DataListView.Designer.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace ValheimServerGUI.Controls 3 | { 4 | partial class DataListView 5 | { 6 | /// 7 | /// Required designer variable. 8 | /// 9 | private System.ComponentModel.IContainer components = null; 10 | 11 | /// 12 | /// Clean up any resources being used. 13 | /// 14 | /// true if managed resources should be disposed; otherwise, false. 15 | protected override void Dispose(bool disposing) 16 | { 17 | if (disposing && (components != null)) 18 | { 19 | components.Dispose(); 20 | } 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Component Designer generated code 25 | 26 | /// 27 | /// Required method for Designer support - do not modify 28 | /// the contents of this method with the code editor. 29 | /// 30 | private void InitializeComponent() 31 | { 32 | this.components = new System.ComponentModel.Container(); 33 | this.ListView = new System.Windows.Forms.ListView(); 34 | this.ImageList = new System.Windows.Forms.ImageList(this.components); 35 | this.SuspendLayout(); 36 | // 37 | // ListView 38 | // 39 | this.ListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 40 | | System.Windows.Forms.AnchorStyles.Left) 41 | | System.Windows.Forms.AnchorStyles.Right))); 42 | this.ListView.FullRowSelect = true; 43 | this.ListView.HideSelection = false; 44 | this.ListView.Location = new System.Drawing.Point(0, 0); 45 | this.ListView.Name = "ListView"; 46 | this.ListView.Size = new System.Drawing.Size(300, 150); 47 | this.ListView.SmallImageList = this.ImageList; 48 | this.ListView.TabIndex = 0; 49 | this.ListView.UseCompatibleStateImageBehavior = false; 50 | this.ListView.View = System.Windows.Forms.View.Details; 51 | // 52 | // ImageList 53 | // 54 | this.ImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; 55 | this.ImageList.ImageSize = new System.Drawing.Size(16, 16); 56 | this.ImageList.TransparentColor = System.Drawing.Color.Transparent; 57 | // 58 | // DataListView 59 | // 60 | this.Controls.Add(this.ListView); 61 | this.Name = "DataListView"; 62 | this.Size = new System.Drawing.Size(300, 150); 63 | this.ResumeLayout(false); 64 | 65 | } 66 | 67 | #endregion 68 | 69 | private System.Windows.Forms.ListView ListView; 70 | private System.Windows.Forms.ImageList ImageList; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ValheimServerGUI/Game/ValheimPathExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using ValheimServerGUI.Tools; 6 | 7 | namespace ValheimServerGUI.Game 8 | { 9 | public static class ValheimPathExtensions 10 | { 11 | /// 12 | /// These are automatic backup files created by Valheim with the transition to 13 | /// the worlds_local folder on 6/20/22. Do not list these as world names. 14 | /// 15 | private static readonly Regex AutoBackupRegex = new(@"^.*?_backup_\d+?-\d+?"); 16 | 17 | public static FileInfo GetValidatedServerExe(this IValheimServerOptions options) 18 | { 19 | return PathExtensions.GetFileInfo(options.ServerExePath, ".exe"); 20 | } 21 | 22 | public static DirectoryInfo GetValidatedSaveDataFolder(this IValheimServerOptions options) 23 | { 24 | return PathExtensions.GetDirectoryInfo(options.SaveDataFolderPath, true); 25 | } 26 | 27 | public static List GetWorldNames(this DirectoryInfo saveDataFolder) 28 | { 29 | try 30 | { 31 | var allNames = new List(); 32 | 33 | foreach (var info in saveDataFolder.GetWorldsFolders()) 34 | { 35 | if (!Directory.Exists(info.FullName)) continue; 36 | 37 | allNames.AddRange(info 38 | .GetFiles("*.fwl") 39 | .Where(f => !AutoBackupRegex.IsMatch(f.Name)) 40 | .Select(f => Path.GetFileNameWithoutExtension(f.FullName))); 41 | } 42 | 43 | return allNames; 44 | } 45 | catch 46 | { 47 | // Return an empty list of names if we cannot load the worlds folders 48 | return new(); 49 | } 50 | } 51 | 52 | public static bool IsWorldNameAvailable(this DirectoryInfo saveDataFolder, string worldName) 53 | { 54 | if (string.IsNullOrWhiteSpace(worldName)) return false; 55 | 56 | try 57 | { 58 | return !saveDataFolder.GetWorldsFolders() 59 | .Select(p => Path.Join(p.FullName, $"{worldName}.fwl")) 60 | .Any(p => File.Exists(p)); 61 | } 62 | catch 63 | { 64 | // Assume the world name is available if we cannot load the worlds folders 65 | return true; 66 | } 67 | } 68 | 69 | #region Helper methods 70 | 71 | private static IEnumerable GetWorldsFolders(this DirectoryInfo saveDataFolder) 72 | { 73 | yield return PathExtensions.GetDirectoryInfo(Path.Join(saveDataFolder.FullName, "worlds")); 74 | yield return PathExtensions.GetDirectoryInfo(Path.Join(saveDataFolder.FullName, "worlds_local")); 75 | } 76 | 77 | #endregion 78 | } 79 | } 80 | --------------------------------------------------------------------------------