diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index af6ae9b..1fdf761 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -76,17 +76,17 @@ Users will be notified that an update is available the next time they open the d
You only need to run the Serverless application locally if you're making changes to the REST API that you want to test. If you're just making changes to the desktop client, you can skip this section.
-To run the serverless application locally:
+To run the serverless application locally (Visual Studio 2022):
-1. Select the **ValheimServerGUI.Serverless** project (or any file in that project) in the Solution Explorer in Visual Studio.
-2. Press **F5** or click the play button to start debugging the application. This will launch a console window.
+1. Right-click the **ValheimServerGUI.Serverless** project in the Solution Explorer, and select "Set as Startup Project".
+2. Press **F5** or click the play button to start debugging the application in IIS Express. This will launch a new browser window.
3. Using a REST client of your choice (such as [Postman](https://www.postman.com/downloads/) or just cURL), you can then query any API route using the base address shown in the console. For example:
```bash
curl --header "Content-Type: application/json" \
--request POST \
--data '{}' \
- http://localhost:5000/crash-report
+ http://localhost:44385/crash-report
```
### Publishing the Serverless API
@@ -96,8 +96,7 @@ _For project maintainers only._
The API is published to AWS using the [Serverless Application Model](https://aws.amazon.com/serverless/sam/), which essentially means that the deployment instructions are contained within a CloudFormation template in this repo - namely, [serverless.template](/ValheimServerGUI.Serverless/serverless.template).
Before publishing, ensure that the following Solution Resources are set up locally:
-* appsettings.secret.json
-* Secrets.Values.cs
+* ServerSecrets.Values.cs
The easiest way to publish the API is to install the [AWS Toolkit Extension](https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.AWSToolkitforVisualStudio2017) for Visual Studio. After installing the extension, follow these steps:
diff --git a/SolutionResources/.gitignore b/SolutionResources/.gitignore
index 2c7ef37..83f1695 100644
--- a/SolutionResources/.gitignore
+++ b/SolutionResources/.gitignore
@@ -1,4 +1,3 @@
ValheimServerGUI.snk
-appsettings.secret.json
appsettings.local.json
-Secrets.Values.cs
\ No newline at end of file
+*Secrets.*.cs
\ No newline at end of file
diff --git a/SolutionResources/ClientSecrets.cs b/SolutionResources/ClientSecrets.cs
new file mode 100644
index 0000000..2c76cb3
--- /dev/null
+++ b/SolutionResources/ClientSecrets.cs
@@ -0,0 +1,19 @@
+namespace ValheimServerGUI.Properties
+{
+ ///
+ /// The values in this class are populated by the static constructor in the corresponding
+ /// partial class, which is kept out of source control.
+ ///
+ public static partial class ClientSecrets
+ {
+ ///
+ /// The HTTP header that will contain the API key for requests made to the Runeberry API.
+ ///
+ public static string RuneberryApiKeyHeader { get; } = string.Empty;
+
+ ///
+ /// The API key that will be attached to all VSG client requests to the Runeberry API.
+ ///
+ public static string RuneberryClientApiKey { get; }
+ }
+}
diff --git a/SolutionResources/README.md b/SolutionResources/README.md
index c36119d..6f774ec 100644
--- a/SolutionResources/README.md
+++ b/SolutionResources/README.md
@@ -8,9 +8,9 @@ In some cases, however, you may want to supply your own mock secret values for t
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.
-### Secrets.Values.cs
+### ClientSecrets.Values.cs
-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 **Secrets.cs**.
+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**.
```csharp
namespace ValheimServerGUI.Properties
@@ -26,16 +26,6 @@ namespace ValheimServerGUI.Properties
}
```
-### appsettings.secret.json
-
-Configuration values for the Serverless application, both when running locally and deployed. This file **must** exist when deploying the Serverless application, else it will fail to start.
-
-```jsonc
-{
- "SteamApiKey": "", // Not yet used, but planned for an upcoming update
-}
-```
-
### appsettings.local.json
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.
diff --git a/SolutionResources/Secrets.cs b/SolutionResources/ServerSecrets.cs
similarity index 70%
rename from SolutionResources/Secrets.cs
rename to SolutionResources/ServerSecrets.cs
index 58b08b2..a9817c6 100644
--- a/SolutionResources/Secrets.cs
+++ b/SolutionResources/ServerSecrets.cs
@@ -6,7 +6,7 @@ namespace ValheimServerGUI.Properties
/// The values in this class are populated by the static constructor in the corresponding
/// partial class, which is kept out of source control.
///
- public static partial class Secrets
+ public static partial class ServerSecrets
{
///
/// The HTTP header that will contain the API key for requests made to the Runeberry API.
@@ -14,13 +14,18 @@ public static partial class Secrets
public static string RuneberryApiKeyHeader { get; } = string.Empty;
///
- /// The API key that will be attached to all VSG client requests to the Runeberry API.
+ /// The Runeberry API keys that will be accepted by the server.
///
- public static string RuneberryClientApiKey { get; }
+ public static HashSet RuneberryServerApiKeys { get; } = new();
///
- /// The Runeberry API keys that will be accepted by the server.
+ /// API key for interacting with the Steamworks Web API.
///
- public static HashSet RuneberryServerApiKeys { get; } = new();
+ public static string SteamApiKey { get; }
+
+ ///
+ /// API key for interacting with the OpenXBL API.
+ ///
+ public static string XboxApiKey { get; }
}
}
diff --git a/ValheimServerGUI.Controls/Controls/LogViewer.cs b/ValheimServerGUI.Controls/Controls/LogViewer.cs
index 09d287a..77da8fd 100644
--- a/ValheimServerGUI.Controls/Controls/LogViewer.cs
+++ b/ValheimServerGUI.Controls/Controls/LogViewer.cs
@@ -26,8 +26,6 @@ public string LogView
public event EventHandler LogViewChanged;
- public string TimestampFormat { get; set; }
-
public LogViewer()
{
InitializeComponent();
@@ -87,11 +85,6 @@ private string StoreLog(string message, string viewName)
}
}
- if (!string.IsNullOrWhiteSpace(TimestampFormat))
- {
- message = $"[{DateTime.Now.ToString(TimestampFormat)}] {message}";
- }
-
list.Add(message);
return message;
diff --git a/ValheimServerGUI.Controls/Controls/SelectListField.Designer.cs b/ValheimServerGUI.Controls/Controls/SelectListField.Designer.cs
new file mode 100644
index 0000000..0b4a220
--- /dev/null
+++ b/ValheimServerGUI.Controls/Controls/SelectListField.Designer.cs
@@ -0,0 +1,87 @@
+namespace ValheimServerGUI.Controls
+{
+ partial class SelectListField
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ ListBox = new System.Windows.Forms.ListBox();
+ Label = new System.Windows.Forms.Label();
+ HelpLabel = new HelpLabel();
+ SuspendLayout();
+ //
+ // ListBox
+ //
+ ListBox.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ListBox.FormattingEnabled = true;
+ ListBox.ItemHeight = 15;
+ ListBox.Items.AddRange(new object[] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" });
+ ListBox.Location = new System.Drawing.Point(3, 21);
+ ListBox.Name = "ListBox";
+ ListBox.ScrollAlwaysVisible = true;
+ ListBox.Size = new System.Drawing.Size(144, 79);
+ ListBox.TabIndex = 0;
+ //
+ // Label
+ //
+ Label.AutoSize = true;
+ Label.Location = new System.Drawing.Point(3, 3);
+ Label.Name = "Label";
+ Label.Size = new System.Drawing.Size(35, 15);
+ Label.TabIndex = 0;
+ Label.Text = "Label";
+ //
+ // HelpLabel
+ //
+ HelpLabel.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
+ HelpLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point);
+ HelpLabel.ForeColor = System.Drawing.SystemColors.HotTrack;
+ HelpLabel.Location = new System.Drawing.Point(135, 3);
+ HelpLabel.Name = "HelpLabel";
+ HelpLabel.Size = new System.Drawing.Size(12, 15);
+ HelpLabel.TabIndex = 0;
+ HelpLabel.TabStop = false;
+ //
+ // SelectListField
+ //
+ AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ Controls.Add(HelpLabel);
+ Controls.Add(Label);
+ Controls.Add(ListBox);
+ Name = "SelectListField";
+ Size = new System.Drawing.Size(150, 104);
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private System.Windows.Forms.ListBox ListBox;
+ private System.Windows.Forms.Label Label;
+ private HelpLabel HelpLabel;
+ }
+}
diff --git a/ValheimServerGUI.Controls/Controls/SelectListField.cs b/ValheimServerGUI.Controls/Controls/SelectListField.cs
new file mode 100644
index 0000000..2b724d7
--- /dev/null
+++ b/ValheimServerGUI.Controls/Controls/SelectListField.cs
@@ -0,0 +1,257 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Windows.Forms;
+
+namespace ValheimServerGUI.Controls
+{
+ public partial class SelectListField : UserControl, IFormField
+ {
+ #region IFormField implementation
+
+ public string LabelText
+ {
+ get => Label.Text;
+ set => Label.Text = value;
+ }
+
+ [Editor("System.ComponentModel.Design.MultilineStringEditor", "System.Drawing.Design.UITypeEditor")]
+ public string HelpText
+ {
+ get => HelpLabel.Text;
+ set => HelpLabel.Text = value;
+ }
+
+ ///
+ /// The string value of the currently selected item, or null if
+ /// no item is currently selected.
+ ///
+ public string Value
+ {
+ get
+ {
+ if (ListBox.SelectedItem == null) return null;
+ return ListBox.GetItemText(ListBox.SelectedItem);
+ }
+ set
+ {
+ var index = GetItemIndex(value);
+ if (index != ListBox.SelectedIndex)
+ {
+ ListBox.SelectedIndex = index;
+ }
+ }
+ }
+
+ public event EventHandler ValueChanged;
+
+ #endregion
+
+ public event Action ItemsChanged;
+
+ public int SelectedIndex => ListBox.SelectedIndex;
+
+ public SelectListField()
+ {
+ InitializeComponent();
+
+ ListBox.SelectedValueChanged += ListBox_SelectedValueChanged;
+ }
+
+ ///
+ /// Adds an item to the end of the list. Returns the index of
+ /// the newly-added item, or -1 if it could not be added.
+ ///
+ public int AddItem(string item)
+ {
+ if (!IsValidItem(item)) return -1;
+
+ var index = ListBox.Items.Add(item);
+ ItemsChanged?.Invoke();
+ return index;
+ }
+
+ ///
+ /// Adds an item to the end of the list, only if the item is not
+ /// already in the list. Returns the index of the newly-added item,
+ /// or the index of the existing item if it was already in the list.
+ ///
+ public int AddDistinctItem(string item)
+ {
+ if (!IsValidItem(item)) return -1;
+
+ var existingIndex = GetItemIndex(item);
+ if (existingIndex >= 0) return existingIndex;
+ return AddItem(item);
+ }
+
+ public void ClearItems()
+ {
+ if (ListBox.Items.Count == 0) return;
+
+ ListBox.Items.Clear();
+ ItemsChanged?.Invoke();
+ }
+
+ ///
+ /// Returns the text at the specified index in the list, or null
+ /// if the index is out of bounds.
+ ///
+ public string GetItem(int index)
+ {
+ if (!IsValidIndex(index)) return null;
+ return ListBox.GetItemText(ListBox.Items[index]);
+ }
+
+ ///
+ /// Returns the text of all items in the list.
+ ///
+ public IEnumerable GetItems()
+ {
+ foreach (var itemObj in ListBox.Items)
+ {
+ if (itemObj == null) continue;
+ yield return ListBox.GetItemText(itemObj);
+ }
+ }
+
+ ///
+ /// Returns the index of the first instance of the specified item in the list.
+ /// Returns -1 if the specified item is null, or if it is not found in the list.
+ ///
+ public int GetItemIndex(string item)
+ {
+ if (!IsValidItem(item)) return -1;
+
+ var i = 0;
+ foreach (var itemObj in ListBox.Items)
+ {
+ if (itemObj != null)
+ {
+ var itemText = ListBox.GetItemText(itemObj);
+ if (itemText == item) return i;
+ }
+ i++;
+ }
+
+ return -1;
+ }
+
+ ///
+ /// Removes the first instance of the specified item from the list.
+ ///
+ public void RemoveItem(string item)
+ {
+ if (!IsValidItem(item)) return;
+ RemoveItem(GetItemIndex(item));
+ }
+
+ ///
+ /// Removes the item at the specified index. Does nothing if the
+ /// specified index is out of range.
+ ///
+ ///
+ public void RemoveItem(int index)
+ {
+ if (!IsValidIndex(index)) return;
+
+ ListBox.Items.RemoveAt(index);
+ ItemsChanged?.Invoke();
+ }
+
+ ///
+ /// Removes the currently selected item from the list. Does nothing
+ /// if no item is currently selected.
+ ///
+ public void RemoveSelectedItem()
+ {
+ RemoveItem(ListBox.SelectedIndex);
+ }
+
+ ///
+ /// Selects the first item that matches the specified text in the list.
+ ///
+ public void SelectItem(string item)
+ {
+ if (!IsValidItem(item)) return;
+ SelectItem(GetItemIndex(item));
+ }
+
+ ///
+ /// Selects the item at the specified index in the list.
+ ///
+ public void SelectItem(int index)
+ {
+ if (!IsValidIndex(index)) return;
+ ListBox.SetSelected(index, true);
+ }
+
+ ///
+ /// Changes the value of the item at the specified index.
+ /// If the index < 0, then the item will be prepended to the beginning
+ /// of the list. If the index > length, then the item will be
+ /// appended to the end of the list.
+ ///
+ public void SetItem(int index, string item)
+ {
+ if (!IsValidIndex(index) || !IsValidItem(item)) return;
+
+ if (index < 0)
+ {
+ ListBox.Items.Insert(0, item);
+ }
+ else if (index >= ListBox.Items.Count)
+ {
+ ListBox.Items.Add(item);
+ }
+ else
+ {
+ var existingItem = GetItem(index);
+ if (existingItem == item) return;
+
+ ListBox.Items[index] = item;
+ }
+
+ ItemsChanged?.Invoke();
+ }
+
+ ///
+ /// Overwrites the list with the provided list of items.
+ /// Always invokes the event.
+ ///
+ public void SetItems(IEnumerable items)
+ {
+ ListBox.Items.Clear();
+
+ bool anyChanged = false;
+
+ foreach (var item in items)
+ {
+ if (!IsValidItem(item)) continue;
+
+ anyChanged = true;
+ ListBox.Items.Add(item);
+ }
+
+ if (anyChanged)
+ {
+ ItemsChanged?.Invoke();
+ }
+ }
+
+ private bool IsValidIndex(int index)
+ {
+ return index >= 0 && index < ListBox.Items.Count;
+ }
+
+ private bool IsValidItem(string item)
+ {
+ return !string.IsNullOrWhiteSpace(item);
+ }
+
+ private void ListBox_SelectedValueChanged(object sender, EventArgs e)
+ {
+ ValueChanged?.Invoke(this, Value);
+ }
+ }
+}
diff --git a/ValheimServerGUI.Controls/Controls/SelectListField.resx b/ValheimServerGUI.Controls/Controls/SelectListField.resx
new file mode 100644
index 0000000..a395bff
--- /dev/null
+++ b/ValheimServerGUI.Controls/Controls/SelectListField.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ValheimServerGUI.Serverless/Controllers/VsgController.cs b/ValheimServerGUI.Serverless/Controllers/VsgController.cs
index 0a8e407..206bf56 100644
--- a/ValheimServerGUI.Serverless/Controllers/VsgController.cs
+++ b/ValheimServerGUI.Serverless/Controllers/VsgController.cs
@@ -8,7 +8,8 @@
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
-using ValheimServerGUI.Tools;
+using ValheimServerGUI.Serverless.Services;
+using ValheimServerGUI.Tools.Models;
namespace ValheimServerGUI.Serverless.Controllers
{
@@ -17,13 +18,21 @@ public class VsgController : ControllerBase
{
private readonly ILogger Logger;
private readonly IConfiguration Configuration;
+ private readonly ISteamApiClient SteamApiClient;
+ private readonly IXboxApiClient XboxApiClient;
private ILambdaContext LambdaContext => HttpContext.Items["LambdaContext"] as ILambdaContext;
- public VsgController(ILogger logger, IConfiguration configuration)
+ public VsgController(
+ ILogger logger,
+ IConfiguration configuration,
+ ISteamApiClient steamApiClient,
+ IXboxApiClient xboxApiClient)
{
Logger = logger;
Configuration = configuration;
+ SteamApiClient = steamApiClient;
+ XboxApiClient = xboxApiClient;
}
[HttpPost("crash-report")]
@@ -71,19 +80,40 @@ public async Task CreateCrashReport([FromBody] CrashReport reques
statusCode = 500;
}
- Logger.LogException(exception, $"{exception.GetType().Name} occurred during S3 upload");
- Logger.LogError(exception.Message);
- Logger.LogError(exception.StackTrace);
+ Logger.LogError(exception, "An exception of type '{typeName}' occurred during S3 upload\n{message}\n{stackTrace}",
+ exception.GetType().Name,
+ exception.Message,
+ exception.StackTrace);
return StatusCode(statusCode, new { message = exception.Message });
}
- [HttpGet("player-steam-info")]
-#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
- public async Task GetPlayerSteamInfo([FromQuery] string steamId)
-#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
+ [HttpGet("player-info")]
+ public async Task GetPlayerInfo([FromQuery] string platform, [FromQuery] string playerId)
{
- return Ok("Player steam info");
+ if (string.IsNullOrWhiteSpace(platform) || string.IsNullOrWhiteSpace(playerId))
+ {
+ return StatusCode(400, new ErrorResponse("'platform' and 'playerId' are required"));
+ }
+
+ try
+ {
+ switch (platform)
+ {
+ case PlayerPlatforms.Steam:
+ var steamPlayer = await SteamApiClient.GetPlayerSummary(playerId);
+ return Ok(steamPlayer);
+ case PlayerPlatforms.Xbox:
+ var xboxPlayer = await XboxApiClient.GetPlayerSummary(playerId);
+ return Ok(xboxPlayer);
+ default:
+ return StatusCode(400, new ErrorResponse($"Unsupported value: platform={platform}"));
+ }
+ }
+ catch (Exception e)
+ {
+ return StatusCode(500, new ErrorResponse(e.Message));
+ }
}
}
}
diff --git a/ValheimServerGUI.Serverless/LambdaEntryPoint.cs b/ValheimServerGUI.Serverless/LambdaEntryPoint.cs
index 94c0fec..43653d7 100644
--- a/ValheimServerGUI.Serverless/LambdaEntryPoint.cs
+++ b/ValheimServerGUI.Serverless/LambdaEntryPoint.cs
@@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
namespace ValheimServerGUI.Serverless
@@ -33,10 +32,6 @@ public class LambdaEntryPoint :
protected override void Init(IWebHostBuilder builder)
{
builder
- .ConfigureAppConfiguration(config =>
- {
- config.AddJsonFile("appsettings.secret.json");
- })
.UseStartup();
}
diff --git a/ValheimServerGUI.Serverless/LocalEntryPoint.cs b/ValheimServerGUI.Serverless/LocalEntryPoint.cs
index cd2af0a..73821e6 100644
--- a/ValheimServerGUI.Serverless/LocalEntryPoint.cs
+++ b/ValheimServerGUI.Serverless/LocalEntryPoint.cs
@@ -21,7 +21,6 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
webBuilder.ConfigureAppConfiguration(config =>
{
var executingLocation = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
- config.AddJsonFile(System.IO.Path.Join(executingLocation, "appsettings.secret.json"), optional: true);
config.AddJsonFile(System.IO.Path.Join(executingLocation, "appsettings.local.json"), optional: true);
});
webBuilder.UseStartup();
diff --git a/ValheimServerGUI.Serverless/Middleware/RuneberryAuthMiddleware.cs b/ValheimServerGUI.Serverless/Middleware/RuneberryAuthMiddleware.cs
index b266216..7afb036 100644
--- a/ValheimServerGUI.Serverless/Middleware/RuneberryAuthMiddleware.cs
+++ b/ValheimServerGUI.Serverless/Middleware/RuneberryAuthMiddleware.cs
@@ -14,21 +14,21 @@ public class RuneberryAuthMiddleware
static RuneberryAuthMiddleware()
{
- ApiKeyEnabled = !string.IsNullOrWhiteSpace(Secrets.RuneberryApiKeyHeader) && Secrets.RuneberryApiKeyHeader.Any();
+ ApiKeyEnabled = !string.IsNullOrWhiteSpace(ServerSecrets.RuneberryApiKeyHeader) && ServerSecrets.RuneberryApiKeyHeader.Any();
}
public static async Task Authorize(HttpContext context, Func next)
{
if (ApiKeyEnabled)
{
- if (!context.Request.Headers.TryGetValue(Secrets.RuneberryApiKeyHeader, out var apiKey))
+ if (!context.Request.Headers.TryGetValue(ServerSecrets.RuneberryApiKeyHeader, out var apiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsJsonAsync(new { message = "Missing API key" });
return;
}
- if (!Secrets.RuneberryServerApiKeys.Contains(apiKey))
+ if (!ServerSecrets.RuneberryServerApiKeys.Contains(apiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsJsonAsync(new { message = "Invalid API key" });
diff --git a/ValheimServerGUI.Serverless/Services/ServerlessLogger.cs b/ValheimServerGUI.Serverless/Services/ServerlessLogger.cs
new file mode 100644
index 0000000..9cf2512
--- /dev/null
+++ b/ValheimServerGUI.Serverless/Services/ServerlessLogger.cs
@@ -0,0 +1,14 @@
+using Amazon.Lambda.Core;
+using Serilog;
+using Serilog.Events;
+
+namespace ValheimServerGUI.Serverless.Services
+{
+ public class ServerlessLogger : ILogger
+ {
+ public void Write(LogEvent logEvent)
+ {
+ LambdaLogger.Log(logEvent.RenderMessage());
+ }
+ }
+}
diff --git a/ValheimServerGUI.Serverless/Services/SteamApiClient.cs b/ValheimServerGUI.Serverless/Services/SteamApiClient.cs
new file mode 100644
index 0000000..b734b9d
--- /dev/null
+++ b/ValheimServerGUI.Serverless/Services/SteamApiClient.cs
@@ -0,0 +1,78 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using ValheimServerGUI.Properties;
+using ValheimServerGUI.Tools.Http;
+using ValheimServerGUI.Tools.Models;
+
+namespace ValheimServerGUI.Serverless.Services
+{
+ public interface ISteamApiClient
+ {
+ Task GetPlayerSummary(string steamId);
+ }
+
+ public class SteamApiClient : RestClient, ISteamApiClient
+ {
+ public SteamApiClient(IRestClientContext context) : base(context)
+ {
+ }
+
+ public async Task GetPlayerSummary(string steamId)
+ {
+ if (string.IsNullOrWhiteSpace(steamId))
+ {
+ throw new ArgumentNullException(nameof(steamId));
+ }
+
+ var response = await Get($"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?steamids={steamId}")
+ .WithHeader("x-webapi-key", ServerSecrets.SteamApiKey)
+ .SendAsync();
+
+ if (response == null)
+ {
+ throw new Exception($"Unsuccessful request with steamId: {steamId}");
+ }
+
+ if (response.Response == null || response.Response.Players == null || !response.Response.Players.Any())
+ {
+ throw new Exception($"No players on response for steamId: {steamId}");
+ }
+
+ var person = response.Response.Players.FirstOrDefault(p => p.SteamId == steamId);
+ if (person == null)
+ {
+ throw new Exception($"No players matching steamId on response for: {steamId}");
+ }
+
+ return new PlayerInfoResponse(PlayerPlatforms.Steam, person.SteamId, person.PersonaName);
+ }
+
+ #region Nested symbols
+
+ private class SteamPlayerSummaryResponse
+ {
+ [JsonProperty("response")]
+ public ResponseObject Response { get; set; }
+
+ public class ResponseObject
+ {
+ [JsonProperty("players")]
+ public List Players { get; set; }
+
+ public class Player
+ {
+ [JsonProperty("steamid")]
+ public string SteamId { get; set; }
+
+ [JsonProperty("personaname")]
+ public string PersonaName { get; set; }
+ }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/ValheimServerGUI.Serverless/Services/XboxApiClient.cs b/ValheimServerGUI.Serverless/Services/XboxApiClient.cs
new file mode 100644
index 0000000..83cd257
--- /dev/null
+++ b/ValheimServerGUI.Serverless/Services/XboxApiClient.cs
@@ -0,0 +1,78 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using ValheimServerGUI.Properties;
+using ValheimServerGUI.Tools.Http;
+using ValheimServerGUI.Tools.Models;
+
+namespace ValheimServerGUI.Serverless.Services
+{
+ public interface IXboxApiClient
+ {
+ Task GetPlayerSummary(string xuid);
+ }
+
+ ///
+ /// Client for interacting with the OpenXBL API.
+ ///
+ ///
+ /// Reference the Swagger page at: https://xbl.io/console
+ ///
+ public class XboxApiClient : RestClient, IXboxApiClient
+ {
+ public XboxApiClient(IRestClientContext context) : base(context)
+ {
+ }
+
+ public async Task GetPlayerSummary(string xuid)
+ {
+ if (string.IsNullOrWhiteSpace(xuid))
+ {
+ throw new ArgumentNullException(nameof(xuid));
+ }
+
+ var response = await Get($"https://xbl.io/api/v2/player/summary/{xuid}")
+ .WithHeader("x-authorization", ServerSecrets.XboxApiKey)
+ .SendAsync();
+
+ if (response == null)
+ {
+ throw new Exception($"Unsuccessful request with xuid: {xuid}");
+ }
+
+ if (response.People == null || !response.People.Any())
+ {
+ throw new Exception($"No players on response for xuid: {xuid}");
+ }
+
+ var person = response.People.FirstOrDefault(p => p.Xuid == xuid);
+ if (person == null)
+ {
+ throw new Exception($"No players matching xuid on response for: {xuid}");
+ }
+
+ return new PlayerInfoResponse(PlayerPlatforms.Xbox, person.Xuid, person.DisplayName);
+ }
+
+ #region Nested symbols
+
+ private class XboxPlayerSummaryResponse
+ {
+ [JsonProperty("people")]
+ public List People { get; set; }
+
+ public class Person
+ {
+ [JsonProperty("xuid")]
+ public string Xuid { get; set; }
+
+ [JsonProperty("displayName")]
+ public string DisplayName { get; set; }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/ValheimServerGUI.Serverless/Startup.cs b/ValheimServerGUI.Serverless/Startup.cs
index 9265370..a0f8307 100644
--- a/ValheimServerGUI.Serverless/Startup.cs
+++ b/ValheimServerGUI.Serverless/Startup.cs
@@ -3,8 +3,10 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
+using Serilog;
using ValheimServerGUI.Serverless.Middleware;
+using ValheimServerGUI.Serverless.Services;
+using ValheimServerGUI.Tools.Http;
namespace ValheimServerGUI.Serverless
{
@@ -20,17 +22,19 @@ public Startup(IConfiguration configuration)
// This method gets called by the runtime. Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
- services.AddControllers();
+ services.AddControllers().AddNewtonsoftJson();
+
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+
+ services.AddSingleton();
+ services.AddSingleton();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
app.UseHttpsRedirection();
app.UseRouting();
diff --git a/ValheimServerGUI.Serverless/ValheimServerGUI.Serverless.csproj b/ValheimServerGUI.Serverless/ValheimServerGUI.Serverless.csproj
index 21116cd..b1becee 100644
--- a/ValheimServerGUI.Serverless/ValheimServerGUI.Serverless.csproj
+++ b/ValheimServerGUI.Serverless/ValheimServerGUI.Serverless.csproj
@@ -6,17 +6,22 @@
true
+
-
+
+
+
+
-
-
+
+
+
diff --git a/ValheimServerGUI.Serverless/aws-lambda-tools-defaults.json b/ValheimServerGUI.Serverless/aws-lambda-tools-defaults.json
index 13050a6..4dce0d6 100644
--- a/ValheimServerGUI.Serverless/aws-lambda-tools-defaults.json
+++ b/ValheimServerGUI.Serverless/aws-lambda-tools-defaults.json
@@ -6,7 +6,7 @@
"dotnet lambda help",
"All the command line options for the Lambda command can be specified in this file."
],
- "profile" : "default",
+ "profile" : "toolkit-sso",
"region" : "us-east-1",
"configuration" : "Release",
"s3-prefix" : "ValheimServerGUI.Serverless/",
diff --git a/ValheimServerGUI.Tests/Game/ValheimServerTests.cs b/ValheimServerGUI.Tests/Game/ValheimServerTests.cs
index ebd5327..aa6fca8 100644
--- a/ValheimServerGUI.Tests/Game/ValheimServerTests.cs
+++ b/ValheimServerGUI.Tests/Game/ValheimServerTests.cs
@@ -1,7 +1,7 @@
-using Microsoft.Extensions.Logging;
-using System;
+using System;
using System.Linq;
using ValheimServerGUI.Game;
+using ValheimServerGUI.Tools.Models;
using Xunit;
namespace ValheimServerGUI.Tests.Game
@@ -9,9 +9,11 @@ namespace ValheimServerGUI.Tests.Game
public class ValheimServerTests : BaseTest
{
private const string MessageJoining = "Got connection SteamID {0}";
+ private const string MessageJoiningCrossplay = "PlayFab socket with remote ID 123456 received local Platform ID {0}_{1}";
private const string MessageOnline = "Got character ZDOID from {0} : {1}:1";
private const string MessageWrongPassword = "Peer {0} has wrong password";
private const string MessageOffline = "Closing socket {0}";
+ private const string MessageOfflineCrossplay = "Destroying abandoned non persistent zdo {0}:1";
private readonly ValheimServer Server;
private readonly IPlayerDataRepository PlayerDataRepository;
@@ -19,6 +21,7 @@ public class ValheimServerTests : BaseTest
public ValheimServerTests()
{
Server = GetService();
+ //Server.Logger.SetFileLoggingEnabled(false); // todo: fix tests for new logging changes
PlayerDataRepository = GetService();
}
@@ -43,13 +46,40 @@ public void CanDetectServerRunning()
[Fact]
public void CanDetectPlayerJoining()
{
- var steamId = "1234";
+ var playerId = "1234";
PlayerInfo eventPlayer = null;
PlayerDataRepository.PlayerStatusChanged += (_, player) => eventPlayer = player;
- Log(MessageJoining, steamId);
+ Log(MessageJoining, playerId);
- var expected = new PlayerInfo { SteamId = steamId, PlayerStatus = PlayerStatus.Joining };
+ var expected = new PlayerInfo
+ {
+ Platform = PlayerPlatforms.Steam,
+ PlayerId = playerId,
+ PlayerStatus = PlayerStatus.Joining
+ };
+ AssertMatch(expected, eventPlayer);
+
+ var dataPlayer = Assert.Single(PlayerDataRepository.Data);
+ AssertMatch(expected, dataPlayer);
+ }
+
+ [Theory]
+ [InlineData(PlayerPlatforms.Steam, "1234")]
+ [InlineData(PlayerPlatforms.Xbox, "5678")]
+ public void CanDetectPlayerJoiningCrossplay(string platform, string playerId)
+ {
+ PlayerInfo eventPlayer = null;
+ PlayerDataRepository.PlayerStatusChanged += (_, player) => eventPlayer = player;
+
+ Log(MessageJoiningCrossplay, platform, playerId);
+
+ var expected = new PlayerInfo
+ {
+ Platform = platform,
+ PlayerId = playerId,
+ PlayerStatus = PlayerStatus.Joining
+ };
AssertMatch(expected, eventPlayer);
var dataPlayer = Assert.Single(PlayerDataRepository.Data);
@@ -59,14 +89,19 @@ public void CanDetectPlayerJoining()
[Fact]
public void CanDetectPlayerLeaving()
{
- var steamId = "1234";
- Log(MessageJoining, steamId);
+ var playerId = "1234";
+ Log(MessageJoining, playerId);
PlayerInfo eventPlayer = null;
PlayerDataRepository.PlayerStatusChanged += (_, player) => eventPlayer = player;
- Log(MessageWrongPassword, steamId);
+ Log(MessageWrongPassword, playerId);
- var expected = new PlayerInfo { SteamId = steamId, PlayerStatus = PlayerStatus.Leaving };
+ var expected = new PlayerInfo
+ {
+ Platform = PlayerPlatforms.Steam,
+ PlayerId = playerId,
+ PlayerStatus = PlayerStatus.Leaving
+ };
AssertMatch(expected, eventPlayer);
var dataPlayer = Assert.Single(PlayerDataRepository.Data);
@@ -76,14 +111,19 @@ public void CanDetectPlayerLeaving()
[Fact]
public void CanDetectPlayerOffline()
{
- var steamId = "1234";
- Log(MessageJoining, steamId);
+ var playerId = "1234";
+ Log(MessageJoining, playerId);
PlayerInfo eventPlayer = null;
PlayerDataRepository.PlayerStatusChanged += (_, player) => eventPlayer = player;
- Log(MessageOffline, steamId);
+ Log(MessageOffline, playerId);
- var expected = new PlayerInfo { SteamId = steamId, PlayerStatus = PlayerStatus.Offline };
+ var expected = new PlayerInfo
+ {
+ Platform = PlayerPlatforms.Steam,
+ PlayerId = playerId,
+ PlayerStatus = PlayerStatus.Offline
+ };
AssertMatch(expected, eventPlayer);
var dataPlayer = Assert.Single(PlayerDataRepository.Data);
@@ -96,18 +136,19 @@ public void CanDetectPlayerOffline()
public void CanMatchPlayerNameSingle()
{
// If only one player by steamId is joining...
- var steamId = "1234";
- Log(MessageJoining, steamId);
+ var platform = PlayerPlatforms.Steam;
+ var playerId = "1234";
+ Log(MessageJoining, playerId);
PlayerInfo eventPlayer = null;
PlayerDataRepository.PlayerStatusChanged += (_, player) => eventPlayer = player;
// And a player by name goes online...
- var (name, zdoid) = ("Broheim", "-56789123");
- Log(MessageOnline, name, zdoid);
+ var (characterName, zdoId) = ("Broheim", "-56789123");
+ Log(MessageOnline, characterName, zdoId);
// ...then that player name and steamId are confidently matched up.
- var expected = CreatePlayer(steamId, name, PlayerStatus.Online, zdoid);
+ var expected = CreatePlayer(platform, playerId, characterName, PlayerStatus.Online, zdoId, lastStatusCharacter: characterName);
AssertMatch(expected, eventPlayer);
var dataPlayer = Assert.Single(PlayerDataRepository.Data);
@@ -117,9 +158,10 @@ public void CanMatchPlayerNameSingle()
// If multiple players are joining at the same time, and no names are known,
// then nobody in the group will go online until all joining players have connected
[Fact]
- public void CanDelayOnlineStatusForAnonymousPlayers()
+ public void CanHandleMultiplePlayersJoiningAtOnce()
{
- // If multiple players are joining by steamId at the same time...
+ // If multiple players are joining at the same time...
+ var platform = PlayerPlatforms.Steam;
var ids = new[] { "123", "456", "789" };
Log(MessageJoining, ids[0]);
Log(MessageJoining, ids[1]);
@@ -135,32 +177,29 @@ public void CanDelayOnlineStatusForAnonymousPlayers()
Assert.Equal(3, PlayerDataRepository.Data.Count());
- // And a player by name goes online...
- var (name1, zdoid1) = ("PlayerOne", "-432");
+ // And a character by name comes online...
+ var (name1, zdoid1) = ("CharacterOne", "-432");
Log(MessageOnline, name1, zdoid1);
- // ...then that player is not yet brought online
- Assert.Null(eventPlayer);
- Assert.Equal(0, eventCalls);
- Assert.True(PlayerDataRepository.Data.All(p => p.PlayerStatus == PlayerStatus.Joining));
+ // ...then the earliest joining player is assigned that name with low confidence
+ var expected = CreatePlayer(platform, ids[0], name1, PlayerStatus.Online, zdoid1, lastStatusCharacter: name1);
+ AssertMatch(expected, eventPlayer);
- // And another player goes online...
- var (name2, zdoid2) = ("PlayerTwo", "5834");
+ // And another character comes online...
+ var (name2, zdoid2) = ("CharacterTwo", "5834");
Log(MessageOnline, name2, zdoid2);
- // ...then *still* no players are brought online
- Assert.Null(eventPlayer);
- Assert.Equal(0, eventCalls);
- Assert.True(PlayerDataRepository.Data.All(p => p.PlayerStatus == PlayerStatus.Joining));
+ // ...then the second-earliest joining player is assigned that name with low confidence
+ expected = CreatePlayer(platform, ids[1], name2, PlayerStatus.Online, zdoid2, lastStatusCharacter: name2);
+ AssertMatch(expected, eventPlayer);
- // And the final player goes online...
- var (name3, zdoid3) = ("PlayerThree", "146131");
+ // And the final player comes online...
+ var (name3, zdoid3) = ("CharacterThree", "146131");
Log(MessageOnline, name3, zdoid3);
- // ...then, finally, all players are brought online
- Assert.NotNull(eventPlayer);
- Assert.Equal(3, eventCalls);
- Assert.True(PlayerDataRepository.Data.All(p => p.PlayerStatus == PlayerStatus.Online));
+ // ...then the last joining player is assigned that name with low confidence
+ expected = CreatePlayer(platform, ids[2], name3, PlayerStatus.Online, zdoid3, lastStatusCharacter: name3);
+ AssertMatch(expected, eventPlayer);
}
// If the same steamId joins under multiple character names, then we can track separate
@@ -169,11 +208,12 @@ public void CanDelayOnlineStatusForAnonymousPlayers()
public void CanTrackMultipleCharactersForSameSteamId()
{
// If a player has joined in the past...
- var steamId = "1234";
- var (name1, zdoid1) = ("PlayerOne", "234");
- Log(MessageJoining, steamId);
+ var platform = PlayerPlatforms.Steam;
+ var playerId = "1234";
+ var (name1, zdoid1) = ("CharacterOne", "234");
+ Log(MessageJoining, playerId);
Log(MessageOnline, name1, zdoid1);
- Log(MessageOffline, steamId);
+ Log(MessageOffline, playerId);
PlayerInfo eventPlayer = null;
PlayerInfo dataPlayer;
@@ -184,65 +224,89 @@ public void CanTrackMultipleCharactersForSameSteamId()
var origTimestamp = dataPlayer.LastStatusChange; // For later assertion
// And joins again...
- Log(MessageJoining, steamId);
+ Log(MessageJoining, playerId);
// ...then that player is marked as Joining
- expected = CreatePlayer(steamId, name1, PlayerStatus.Joining);
+ expected = CreatePlayer(platform, playerId, name1, PlayerStatus.Joining);
AssertMatch(expected, eventPlayer);
dataPlayer = Assert.Single(PlayerDataRepository.Data);
AssertMatch(expected, dataPlayer);
var origKey = dataPlayer.Key; // For lookup in later assertion
- // And that player connects under a different name...
- var (name2, zdoid2) = ("PlayerTwo", "567");
+ // And that player connects under a different character name...
+ var (name2, zdoid2) = ("CharacterTwo", "567");
Log(MessageOnline, name2, zdoid2);
- // ...then a new player is published, and the old one is reverted to Offline
- expected = CreatePlayer(steamId, name2, PlayerStatus.Online, zdoid2);
+ // ...then a new character is added, and lastStatusCharacter is updated
+ expected = CreatePlayer(platform, playerId, name2, PlayerStatus.Online, zdoid2, lastStatusCharacter: name2);
AssertMatch(expected, eventPlayer);
- Assert.Equal(2, PlayerDataRepository.Data.Count());
+ Assert.Single(PlayerDataRepository.Data);
dataPlayer = PlayerDataRepository.FindById(eventPlayer.Key);
AssertMatch(expected, dataPlayer);
-
- // ...then the offline player should have had their timestamp reverted
- dataPlayer = PlayerDataRepository.FindById(origKey);
- Assert.Equal(origTimestamp, dataPlayer.LastStatusChange);
-
- // And that player goes offline...
- Log(MessageOffline, steamId);
-
- // ...then the original player's timestamp is unaffected
- dataPlayer = PlayerDataRepository.FindById(origKey);
- Assert.Equal(origTimestamp, dataPlayer.LastStatusChange);
}
#region Helper methods
private void Log(string message, params object[] args)
{
- Server.Logger.LogInformation(string.Format(message, args));
+ if (Server.Logger == null)
+ {
+ // A new server logger is now instantiated each time the server is started,
+ // so let's pretend to boot one up just for testing the log messages.
+ // A problem with this is that the tests will only pass if it can find the server exe
+ // and save data folders.
+ var options = new ValheimServerOptions
+ {
+ Name = "Test Server",
+ Password = "hunter2",
+ WorldName = "Test World",
+ Public = false,
+ Port = 2456,
+ Crossplay = false,
+ SaveInterval = 30,
+ Backups = 1,
+ BackupShort = 60,
+ BackupLong = 120,
+ ServerExePath = @"%ProgramFiles(x86)%\Steam\steamapps\common\Valheim dedicated server\valheim_server.exe",
+ SaveDataFolderPath = @"%USERPROFILE%\AppData\LocalLow\IronGate\Valheim",
+ LogToFile = false,
+ };
+
+ Server.Start(options);
+ }
+
+ Server.Logger.Information(string.Format(message, args));
}
private static PlayerInfo CreatePlayer(
- string steamId,
- string name = null,
+ string platform,
+ string playerId,
+ string characterName = null,
PlayerStatus? status = null,
string zdoid = null,
bool confident = false,
- string change = null
+ string lastStatusChange = null,
+ string lastStatusCharacter = null
)
{
- return new PlayerInfo
+ var player = new PlayerInfo
{
- SteamId = steamId,
- PlayerName = name,
+ Platform = platform,
+ PlayerId = playerId,
PlayerStatus = status ?? PlayerStatus.Offline,
- LastStatusChange = change != null ? DateTime.Parse(change) : GetNextTimestamp(),
+ LastStatusChange = lastStatusChange != null ? DateTime.Parse(lastStatusChange) : GetNextTimestamp(),
+ LastStatusCharacter = lastStatusCharacter,
ZdoId = zdoid,
- MatchConfident = confident
};
+
+ if (characterName != null)
+ {
+ player.AddCharacter(characterName, confident);
+ }
+
+ return player;
}
private static int TimeCounter = 0;
@@ -256,9 +320,11 @@ private static void AssertMatch(PlayerInfo expected, PlayerInfo actual)
{
Assert.NotNull(actual);
- Assert.Equal(expected.SteamId, actual.SteamId);
+ Assert.Equal(expected.Platform, actual.Platform);
+ Assert.Equal(expected.PlayerId, actual.PlayerId);
Assert.Equal(expected.PlayerStatus, actual.PlayerStatus);
+ if (expected.LastStatusCharacter != null) Assert.Equal(expected.LastStatusCharacter, actual.LastStatusCharacter);
if (expected.PlayerName != null) Assert.Equal(expected.PlayerName, actual.PlayerName);
if (expected.ZdoId != null) Assert.Equal(expected.ZdoId, actual.ZdoId);
}
diff --git a/ValheimServerGUI.Tests/Tools/MockProcessProvider.cs b/ValheimServerGUI.Tests/Tools/MockProcessProvider.cs
index 3bc13f3..2062704 100644
--- a/ValheimServerGUI.Tests/Tools/MockProcessProvider.cs
+++ b/ValheimServerGUI.Tests/Tools/MockProcessProvider.cs
@@ -1,5 +1,5 @@
using System;
-using System.Collections.Generic;
+using System.Collections.Concurrent;
using System.Diagnostics;
using ValheimServerGUI.Tools.Processes;
@@ -7,19 +7,26 @@ namespace ValheimServerGUI.Tests.Tools
{
public class MockProcessProvider : IProcessProvider
{
+ private readonly ConcurrentDictionary Processes = new();
+
public void AddProcess(string key, Process process)
{
- throw new NotImplementedException("Cannot add processes in unit tests!");
+ if (!Processes.TryAdd(key, process))
+ {
+ throw new InvalidOperationException($"Failed to add process with key: {key}");
+ }
}
public Process GetProcess(string key)
{
- throw new NotImplementedException("Cannot get processes in unit tests!");
+ if (!Processes.TryGetValue(key, out var process)) return null;
+ return process;
}
- public List FindExistingProcessesByName(string name)
+
+ public void StartIO(Process process)
{
- return new();
+ // no-op for testing
}
}
}
diff --git a/ValheimServerGUI.Tools/Data/DataFileRepository.cs b/ValheimServerGUI.Tools/Data/DataFileRepository.cs
index 646338d..d63629d 100644
--- a/ValheimServerGUI.Tools/Data/DataFileRepository.cs
+++ b/ValheimServerGUI.Tools/Data/DataFileRepository.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.Logging;
+using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/ValheimServerGUI.Tools/Data/DataFileRepositoryContext.cs b/ValheimServerGUI.Tools/Data/DataFileRepositoryContext.cs
index 60e97b6..7b573cd 100644
--- a/ValheimServerGUI.Tools/Data/DataFileRepositoryContext.cs
+++ b/ValheimServerGUI.Tools/Data/DataFileRepositoryContext.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.Logging;
+using Serilog;
namespace ValheimServerGUI.Tools.Data
{
diff --git a/ValheimServerGUI.Tools/Data/JsonFileProvider.cs b/ValheimServerGUI.Tools/Data/JsonFileProvider.cs
index 194a1c7..ace38b8 100644
--- a/ValheimServerGUI.Tools/Data/JsonFileProvider.cs
+++ b/ValheimServerGUI.Tools/Data/JsonFileProvider.cs
@@ -1,5 +1,5 @@
-using Microsoft.Extensions.Logging;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
+using Serilog;
using System;
using System.IO;
using System.Threading;
@@ -56,7 +56,7 @@ public virtual Task LoadAsync(string filePath) where TFile : class
}
catch (Exception e)
{
- Logger.LogException(e, $"Error loading JSON data from file: {filePath}");
+ Logger.Error(e, "Error loading JSON data from file: {filePath}", filePath);
}
finally
{
@@ -89,7 +89,7 @@ public virtual Task SaveAsync(string filePath, TFile data) where TFile :
}
catch (Exception e)
{
- Logger.LogException(e, $"Error saving JSON data to file: {filePath}");
+ Logger.Error(e, "Error saving JSON data to file: {filePath}", filePath);
}
finally
{
diff --git a/ValheimServerGUI.Tools/Delegates.cs b/ValheimServerGUI.Tools/Delegates.cs
index e3c5b04..8a01bae 100644
--- a/ValheimServerGUI.Tools/Delegates.cs
+++ b/ValheimServerGUI.Tools/Delegates.cs
@@ -1,7 +1,4 @@
-using ValheimServerGUI.Tools.Logging;
-
-namespace ValheimServerGUI.Tools
+namespace ValheimServerGUI.Tools
{
public delegate void KeyValueEventHandler(object sender, string key, string value);
- public delegate void LogEventHandler(object sender, EventLogContext logEvent, string[] captures);
}
diff --git a/ValheimServerGUI.Tools/Http/RestClient.cs b/ValheimServerGUI.Tools/Http/RestClient.cs
index 221d4a9..630e58f 100644
--- a/ValheimServerGUI.Tools/Http/RestClient.cs
+++ b/ValheimServerGUI.Tools/Http/RestClient.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.Logging;
+using Serilog;
using System.Net.Http;
namespace ValheimServerGUI.Tools.Http
diff --git a/ValheimServerGUI.Tools/Http/RestClientContext.cs b/ValheimServerGUI.Tools/Http/RestClientContext.cs
index 7cc5307..af42307 100644
--- a/ValheimServerGUI.Tools/Http/RestClientContext.cs
+++ b/ValheimServerGUI.Tools/Http/RestClientContext.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.Logging;
+using Serilog;
namespace ValheimServerGUI.Tools.Http
{
diff --git a/ValheimServerGUI.Tools/Http/RestClientRequest.cs b/ValheimServerGUI.Tools/Http/RestClientRequest.cs
index c13b9b2..06f126d 100644
--- a/ValheimServerGUI.Tools/Http/RestClientRequest.cs
+++ b/ValheimServerGUI.Tools/Http/RestClientRequest.cs
@@ -1,5 +1,4 @@
-using Microsoft.Extensions.Logging;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
@@ -73,7 +72,7 @@ public async Task SendAsync()
if (!responseMessage.IsSuccessStatusCode)
{
- Context.Logger.LogError("HTTP request was not successful ({0}): {1}", statusCode, logAddress);
+ Context.Logger.Error("HTTP request was not successful ({0}): {1}", statusCode, logAddress);
return responseMessage;
}
@@ -83,7 +82,7 @@ public async Task SendAsync()
ResponseContent = JsonConvert.DeserializeObject(responseContentStr, ResponseContentType);
}
- Context.Logger.LogTrace("HTTP request was successful ({0}): {1}", statusCode, logAddress);
+ Context.Logger.Debug("HTTP request was successful ({0}): {1}", statusCode, logAddress);
foreach (var callback in Callbacks)
{
@@ -94,9 +93,9 @@ public async Task SendAsync()
catch (Exception callbackException)
{
// Log the error, but keep iterating over callbacks
- Context.Logger.LogError(callbackException, "HTTP request callback encountered an unexpected error: {0}", logAddress);
- Context.Logger.LogError(callbackException.Message);
- Context.Logger.LogError(callbackException.StackTrace);
+ Context.Logger.Error(callbackException, "HTTP request callback encountered an unexpected error: {0}", logAddress);
+ Context.Logger.Error(callbackException.Message);
+ Context.Logger.Error(callbackException.StackTrace);
}
}
@@ -104,9 +103,9 @@ public async Task SendAsync()
}
catch (Exception e)
{
- Context.Logger.LogError(e, "HTTP request encountered an unexpected error: {0}", logAddress);
- Context.Logger.LogError(e.Message);
- Context.Logger.LogError(e.StackTrace);
+ Context.Logger.Error(e, "HTTP request encountered an unexpected error: {0}", logAddress);
+ Context.Logger.Error(e.Message);
+ Context.Logger.Error(e.StackTrace);
return null;
}
}
diff --git a/ValheimServerGUI.Tools/LoggerExtensions.cs b/ValheimServerGUI.Tools/LoggerExtensions.cs
deleted file mode 100644
index bdda6d3..0000000
--- a/ValheimServerGUI.Tools/LoggerExtensions.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Microsoft.Extensions.Logging;
-using System;
-
-namespace ValheimServerGUI.Tools
-{
- public static class LoggerExtensions
- {
- public static void LogException(this ILogger logger, Exception e, string message = null)
- {
- if (message != null) logger.LogError(message);
- logger.LogError($"{e.GetType().Name}: {e.Message}");
- logger.LogError(e.StackTrace);
- }
- }
-}
diff --git a/ValheimServerGUI.Tools/Logging/ApplicationLogger.cs b/ValheimServerGUI.Tools/Logging/ApplicationLogger.cs
deleted file mode 100644
index 2dd4d7e..0000000
--- a/ValheimServerGUI.Tools/Logging/ApplicationLogger.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Diagnostics;
-
-namespace ValheimServerGUI.Tools.Logging
-{
- public class ApplicationLogger : EventLogger
- {
- public ApplicationLogger()
- {
- CategoryName = "Application";
-
- LogReceived += OnLogReceived;
- }
-
- private void OnLogReceived(object sender, EventLogContext context)
- {
- Debug.WriteLine($"[{context.Timestamp:T}] {context.Message}");
- }
- }
-}
diff --git a/ValheimServerGUI.Tools/Logging/EventLogContext.cs b/ValheimServerGUI.Tools/Logging/EventLogContext.cs
deleted file mode 100644
index 37e6c45..0000000
--- a/ValheimServerGUI.Tools/Logging/EventLogContext.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Microsoft.Extensions.Logging;
-using System;
-
-namespace ValheimServerGUI.Tools.Logging
-{
- public class EventLogContext
- {
- public string Message;
-
- public DateTime Timestamp;
-
- public string Category;
-
- public LogLevel LogLevel;
-
- public EventId EventId;
-
- public Exception Exception;
- }
-}
diff --git a/ValheimServerGUI.Tools/Logging/EventLogger.cs b/ValheimServerGUI.Tools/Logging/EventLogger.cs
deleted file mode 100644
index 8218140..0000000
--- a/ValheimServerGUI.Tools/Logging/EventLogger.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using Microsoft.Extensions.Logging;
-using System;
-using System.Collections.Generic;
-
-namespace ValheimServerGUI.Tools.Logging
-{
- public class EventLogger : IEventLogger
- {
- private readonly ConcurrentBuffer ConcurrentBuffer = new(1000);
-
- protected string CategoryName { get; set; }
-
- protected virtual bool FilterLog(EventLogContext context)
- {
- return true;
- }
-
- protected virtual string FormatLog(EventLogContext context)
- {
- return context.Message;
- }
-
- #region IEventLogger implementation
-
- public IEnumerable LogBuffer => ConcurrentBuffer;
-
- public event EventHandler LogReceived;
-
- #endregion
-
- #region ILogger implementation
-
- public IDisposable BeginScope(TState state)
- {
- return default;
- }
-
- public bool IsEnabled(LogLevel logLevel)
- {
- return true;
- }
-
- public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
- {
- var context = new EventLogContext
- {
- Message = formatter(state, exception),
- Timestamp = DateTime.Now,
- Category = CategoryName ?? typeof(TState).Name,
- LogLevel = logLevel,
- EventId = eventId,
- Exception = exception,
- };
-
- try
- {
- if (!FilterLog(context)) return;
- }
- catch
- {
- // Suppress any logging errors
- return;
- }
-
- try
- {
- context.Message = FormatLog(context);
- }
- catch
- {
- // Suppress any logging errors
- return;
- }
-
- var formattedMessage = $"[{context.Timestamp:G}] {context.Message}";
- ConcurrentBuffer.Enqueue(formattedMessage);
-
- LogReceived?.Invoke(this, context);
- }
-
- #endregion
- }
-
- public class EventLogger : EventLogger, IEventLogger
- {
- public EventLogger()
- {
- CategoryName = typeof(TCategoryName).Name;
- }
- }
-}
diff --git a/ValheimServerGUI.Tools/Logging/IEventLogger.cs b/ValheimServerGUI.Tools/Logging/IEventLogger.cs
deleted file mode 100644
index b315d30..0000000
--- a/ValheimServerGUI.Tools/Logging/IEventLogger.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Microsoft.Extensions.Logging;
-using System;
-using System.Collections.Generic;
-
-namespace ValheimServerGUI.Tools.Logging
-{
- public interface IEventLogger : ILogger
- {
- IEnumerable LogBuffer { get; }
-
- event EventHandler LogReceived;
- }
-
- public interface IEventLogger : IEventLogger
- {
- }
-}
diff --git a/ValheimServerGUI.Tools/CrashReport.cs b/ValheimServerGUI.Tools/Models/CrashReport.cs
similarity index 96%
rename from ValheimServerGUI.Tools/CrashReport.cs
rename to ValheimServerGUI.Tools/Models/CrashReport.cs
index 499bbfa..eb01c46 100644
--- a/ValheimServerGUI.Tools/CrashReport.cs
+++ b/ValheimServerGUI.Tools/Models/CrashReport.cs
@@ -2,7 +2,7 @@
using System;
using System.Collections.Generic;
-namespace ValheimServerGUI.Tools
+namespace ValheimServerGUI.Tools.Models
{
public class CrashReport
{
diff --git a/ValheimServerGUI.Tools/Models/ErrorResponse.cs b/ValheimServerGUI.Tools/Models/ErrorResponse.cs
new file mode 100644
index 0000000..5b885f5
--- /dev/null
+++ b/ValheimServerGUI.Tools/Models/ErrorResponse.cs
@@ -0,0 +1,15 @@
+using Newtonsoft.Json;
+
+namespace ValheimServerGUI.Tools.Models
+{
+ public class ErrorResponse
+ {
+ public ErrorResponse(string message)
+ {
+ Message = message;
+ }
+
+ [JsonProperty("message")]
+ public string Message { get; }
+ }
+}
diff --git a/ValheimServerGUI.Tools/Models/PlayerInfoResponse.cs b/ValheimServerGUI.Tools/Models/PlayerInfoResponse.cs
new file mode 100644
index 0000000..0ddbbe7
--- /dev/null
+++ b/ValheimServerGUI.Tools/Models/PlayerInfoResponse.cs
@@ -0,0 +1,23 @@
+using Newtonsoft.Json;
+
+namespace ValheimServerGUI.Tools.Models
+{
+ public class PlayerInfoResponse
+ {
+ public PlayerInfoResponse(string platform, string id, string name)
+ {
+ Platform = platform;
+ Id = id;
+ Name = name;
+ }
+
+ [JsonProperty("id")]
+ public string Id { get; set; }
+
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("platform")]
+ public string Platform { get; set; }
+ }
+}
diff --git a/ValheimServerGUI.Tools/Models/PlayerPlatforms.cs b/ValheimServerGUI.Tools/Models/PlayerPlatforms.cs
new file mode 100644
index 0000000..b929718
--- /dev/null
+++ b/ValheimServerGUI.Tools/Models/PlayerPlatforms.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+
+namespace ValheimServerGUI.Tools.Models
+{
+ public static class PlayerPlatforms
+ {
+ public const string Steam = "Steam";
+ public const string Xbox = "Xbox";
+
+ public static readonly HashSet All = new()
+ {
+ Steam,
+ Xbox,
+ };
+
+ ///
+ /// Gets a case-corrected platform name from an input string.
+ ///
+ public static bool TryGetValidPlatform(string input, out string platform)
+ {
+ if (input == null)
+ {
+ platform = null;
+ return false;
+ }
+
+ switch (input.Trim().ToLowerInvariant())
+ {
+ case "steam":
+ platform = Steam;
+ return true;
+ case "xbox":
+ platform = Xbox;
+ return true;
+ default:
+ platform = null;
+ return false;
+ }
+ }
+ }
+}
diff --git a/ValheimServerGUI.Tools/Processes/IProcessProvider.cs b/ValheimServerGUI.Tools/Processes/IProcessProvider.cs
index dbee29a..eb20f11 100644
--- a/ValheimServerGUI.Tools/Processes/IProcessProvider.cs
+++ b/ValheimServerGUI.Tools/Processes/IProcessProvider.cs
@@ -1,14 +1,13 @@
-using System.Collections.Generic;
-using System.Diagnostics;
+using System.Diagnostics;
namespace ValheimServerGUI.Tools.Processes
{
public interface IProcessProvider
{
- public Process GetProcess(string key);
+ void AddProcess(string key, Process process);
- public void AddProcess(string key, Process process);
+ Process GetProcess(string key);
- List FindExistingProcessesByName(string name);
+ void StartIO(Process process);
}
}
diff --git a/ValheimServerGUI.Tools/Processes/ProcessExtensions.cs b/ValheimServerGUI.Tools/Processes/ProcessExtensions.cs
index 37b2cba..184100b 100644
--- a/ValheimServerGUI.Tools/Processes/ProcessExtensions.cs
+++ b/ValheimServerGUI.Tools/Processes/ProcessExtensions.cs
@@ -25,7 +25,7 @@ public static Process AddBackgroundProcess(this IProcessProvider provider, strin
provider.AddProcess(key, process);
- return process;
+ return provider.GetProcess(key);
}
///
@@ -39,7 +39,7 @@ public static Process SafelyKillProcess(this IProcessProvider provider, Process
var killProcess = provider.AddBackgroundProcess($"{KillCommand}-{process.Id}", KillCommand, $"/pid {process.Id}");
// todo: Send output to application logs
- killProcess.StartIO();
+ provider.StartIO(killProcess);
}
return process;
@@ -62,19 +62,5 @@ public static bool IsProcessRunning(this IProcessProvider provider, string key)
return !process.HasExited;
}
-
- public static void StartIO(this Process process)
- {
- process.Start();
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- }
-
- public static void SafelyWaitForExit(this Process process)
- {
- if (process == null || process.HasExited) return;
-
- process.WaitForExit();
- }
}
}
diff --git a/ValheimServerGUI.Tools/Processes/ProcessProvider.cs b/ValheimServerGUI.Tools/Processes/ProcessProvider.cs
index e0bc57d..ed0e5b4 100644
--- a/ValheimServerGUI.Tools/Processes/ProcessProvider.cs
+++ b/ValheimServerGUI.Tools/Processes/ProcessProvider.cs
@@ -1,14 +1,12 @@
using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
namespace ValheimServerGUI.Tools.Processes
{
public class ProcessProvider : IProcessProvider
{
- private readonly ConcurrentDictionary Processes = new ConcurrentDictionary();
+ private readonly ConcurrentDictionary Processes = new();
public void AddProcess(string key, Process process)
{
@@ -24,15 +22,25 @@ public void AddProcess(string key, Process process)
public Process GetProcess(string key)
{
if (!Processes.TryGetValue(key, out var process)) return null;
- if (process.HasExited) return null;
+
+ try
+ {
+ // Don't return a process if it's already exited
+ if (process.HasExited) return null;
+ }
+ catch
+ {
+ // HasExited will throw if the process hasn't started yet, so ignore that
+ }
+
return process;
}
- public List FindExistingProcessesByName(string name)
+ public void StartIO(Process process)
{
- return Process.GetProcesses()
- .Where(p => p.ProcessName == name)
- .ToList();
+ process.Start();
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
}
}
}
diff --git a/ValheimServerGUI.Tools/ValheimServerGUI.Tools.csproj b/ValheimServerGUI.Tools/ValheimServerGUI.Tools.csproj
index b2874f6..099577c 100644
--- a/ValheimServerGUI.Tools/ValheimServerGUI.Tools.csproj
+++ b/ValheimServerGUI.Tools/ValheimServerGUI.Tools.csproj
@@ -9,8 +9,8 @@
-
+
diff --git a/ValheimServerGUI/Controls/AddRemoveListField.Designer.cs b/ValheimServerGUI/Controls/AddRemoveListField.Designer.cs
new file mode 100644
index 0000000..73bae84
--- /dev/null
+++ b/ValheimServerGUI/Controls/AddRemoveListField.Designer.cs
@@ -0,0 +1,98 @@
+namespace ValheimServerGUI.Forms
+{
+ partial class AddRemoveListField
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ SelectListField = new ValheimServerGUI.Controls.SelectListField();
+ AddButton = new System.Windows.Forms.Button();
+ RemoveButton = new System.Windows.Forms.Button();
+ EditButton = new System.Windows.Forms.Button();
+ SuspendLayout();
+ //
+ // SelectListField
+ //
+ SelectListField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ SelectListField.HelpText = "";
+ SelectListField.LabelText = "Label";
+ SelectListField.Location = new System.Drawing.Point(0, 0);
+ SelectListField.Name = "SelectListField";
+ SelectListField.Size = new System.Drawing.Size(150, 104);
+ SelectListField.TabIndex = 0;
+ SelectListField.Value = null;
+ //
+ // AddButton
+ //
+ AddButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
+ AddButton.Image = Properties.Resources.Add_16x;
+ AddButton.Location = new System.Drawing.Point(124, 103);
+ AddButton.Name = "AddButton";
+ AddButton.Size = new System.Drawing.Size(23, 23);
+ AddButton.TabIndex = 3;
+ AddButton.UseVisualStyleBackColor = true;
+ //
+ // RemoveButton
+ //
+ RemoveButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
+ RemoveButton.Image = Properties.Resources.Remove_Red_16x;
+ RemoveButton.Location = new System.Drawing.Point(98, 103);
+ RemoveButton.Name = "RemoveButton";
+ RemoveButton.Size = new System.Drawing.Size(23, 23);
+ RemoveButton.TabIndex = 2;
+ RemoveButton.UseVisualStyleBackColor = true;
+ //
+ // EditButton
+ //
+ EditButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
+ EditButton.Image = Properties.Resources.Edit_16x;
+ EditButton.Location = new System.Drawing.Point(3, 103);
+ EditButton.Name = "EditButton";
+ EditButton.Size = new System.Drawing.Size(23, 23);
+ EditButton.TabIndex = 1;
+ EditButton.UseVisualStyleBackColor = true;
+ //
+ // AddRemoveListField
+ //
+ AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ Controls.Add(EditButton);
+ Controls.Add(RemoveButton);
+ Controls.Add(AddButton);
+ Controls.Add(SelectListField);
+ Name = "AddRemoveListField";
+ Size = new System.Drawing.Size(150, 129);
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private ValheimServerGUI.Controls.SelectListField SelectListField;
+ private System.Windows.Forms.Button AddButton;
+ private System.Windows.Forms.Button RemoveButton;
+ private System.Windows.Forms.Button EditButton;
+ }
+}
diff --git a/ValheimServerGUI/Controls/AddRemoveListField.cs b/ValheimServerGUI/Controls/AddRemoveListField.cs
new file mode 100644
index 0000000..b0367e9
--- /dev/null
+++ b/ValheimServerGUI/Controls/AddRemoveListField.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Windows.Forms;
+
+namespace ValheimServerGUI.Forms
+{
+ public partial class AddRemoveListField : UserControl, IFormField
+ {
+ #region IFormField implementation
+
+ public string Value
+ {
+ get => SelectListField.Value;
+ set => SelectListField.Value = value;
+ }
+
+ public string LabelText
+ {
+ get => SelectListField.LabelText;
+ set => SelectListField.LabelText = value;
+ }
+
+ [Editor("System.ComponentModel.Design.MultilineStringEditor", "System.Drawing.Design.UITypeEditor")]
+ public string HelpText
+ {
+ get => SelectListField.HelpText;
+ set => SelectListField.HelpText = value;
+ }
+
+ public event EventHandler ValueChanged;
+
+ #endregion
+
+ public event Action ItemsChanged;
+
+ ///
+ /// This behavior is called whenever the Add button is clicked.
+ /// It must return the value that will be added to the list.
+ ///
+ /// If this function is not specified, then nothing will happen when
+ /// the Add button is clicked.
+ ///
+ [Browsable(false)]
+ public Func AddFunction { get; set; }
+
+ ///
+ /// This optional behavior is called whenever the Remove button is clicked.
+ /// If specified, it must return true if the value should be removed, or false otherwise.
+ ///
+ [Browsable(false)]
+ public Func RemoveFunction { get; set; }
+
+ ///
+ /// This behavior is called whenever the Edit button is clicked.
+ /// It must return the edited string value to be placed at the
+ /// selected index in the list.
+ ///
+ /// If this function is not specified, then nothing will happen when
+ /// the Edit button is clicked.
+ ///
+ [Browsable(false)]
+ public Func EditFunction { get; set; }
+
+ public bool AllowDuplicates { get; set; }
+
+ private bool _isAddEnabled = true;
+ public bool AddEnabled
+ {
+ get => _isAddEnabled;
+ set
+ {
+ if (value == _isAddEnabled) return;
+ _isAddEnabled = value;
+ RefreshButtonState();
+ }
+ }
+
+ private bool _isEditEnabled = true;
+ public bool EditEnabled
+ {
+ get => _isAddEnabled;
+ set
+ {
+ if (value == _isEditEnabled) return;
+ _isEditEnabled = value;
+ RefreshButtonState();
+ }
+ }
+
+ private bool _isRemoveEnabled = true;
+ public bool RemoveEnabled
+ {
+ get => _isAddEnabled;
+ set
+ {
+ if (value == _isRemoveEnabled) return;
+ _isRemoveEnabled = value;
+ RefreshButtonState();
+ }
+ }
+
+ public AddRemoveListField()
+ {
+ InitializeComponent();
+
+ SelectListField.ValueChanged += SelectListField_ValueChanged;
+ SelectListField.ItemsChanged += SelectListField_ItemsChanged;
+
+ AddButton.Click += AddButton_Click;
+ EditButton.Click += EditButton_Click;
+ RemoveButton.Click += RemoveButton_Click;
+
+ RefreshButtonState();
+ }
+
+ public IEnumerable GetItems()
+ {
+ return SelectListField.GetItems();
+ }
+
+ public void SetItems(IEnumerable items)
+ {
+ SelectListField.SetItems(items);
+ }
+
+ private void SelectListField_ValueChanged(object sender, string selectedItem)
+ {
+ RefreshButtonState();
+ ValueChanged?.Invoke(sender, selectedItem);
+ }
+
+ private void SelectListField_ItemsChanged()
+ {
+ ItemsChanged?.Invoke();
+ }
+
+ private void AddButton_Click(object sender, EventArgs e)
+ {
+ if (AddFunction == null) return;
+
+ var itemToAdd = AddFunction.Invoke();
+
+ if (AllowDuplicates)
+ {
+ SelectListField.AddItem(itemToAdd);
+ }
+ else
+ {
+ SelectListField.AddDistinctItem(itemToAdd);
+ }
+ }
+
+ private void EditButton_Click(object sender, EventArgs e)
+ {
+ if (EditFunction == null) return;
+
+ var selectedItem = Value;
+ if (selectedItem == null) return;
+
+ var editedItem = EditFunction.Invoke(selectedItem);
+ SelectListField.SetItem(SelectListField.SelectedIndex, editedItem);
+ }
+
+ private void RemoveButton_Click(object sender, EventArgs e)
+ {
+ var selectedItem = Value;
+ if (selectedItem == null) return;
+
+ var doRemove = RemoveFunction?.Invoke(selectedItem) ?? true;
+ if (doRemove)
+ {
+ SelectListField.RemoveSelectedItem();
+ }
+ }
+
+ private void RefreshButtonState()
+ {
+ var selectedItem = SelectListField.Value;
+
+ AddButton.Enabled = AddEnabled;
+
+ if (selectedItem != null)
+ {
+ EditButton.Enabled = EditEnabled;
+ RemoveButton.Enabled = RemoveEnabled;
+ }
+ else
+ {
+ EditButton.Enabled = false;
+ RemoveButton.Enabled = false;
+ }
+ }
+ }
+}
diff --git a/ValheimServerGUI/Controls/AddRemoveListField.resx b/ValheimServerGUI/Controls/AddRemoveListField.resx
new file mode 100644
index 0000000..a395bff
--- /dev/null
+++ b/ValheimServerGUI/Controls/AddRemoveListField.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ValheimServerGUI/Forms/CopyButton.Designer.cs b/ValheimServerGUI/Controls/CopyButton.Designer.cs
similarity index 100%
rename from ValheimServerGUI/Forms/CopyButton.Designer.cs
rename to ValheimServerGUI/Controls/CopyButton.Designer.cs
diff --git a/ValheimServerGUI/Forms/CopyButton.cs b/ValheimServerGUI/Controls/CopyButton.cs
similarity index 100%
rename from ValheimServerGUI/Forms/CopyButton.cs
rename to ValheimServerGUI/Controls/CopyButton.cs
diff --git a/ValheimServerGUI/Forms/CopyButton.resx b/ValheimServerGUI/Controls/CopyButton.resx
similarity index 100%
rename from ValheimServerGUI/Forms/CopyButton.resx
rename to ValheimServerGUI/Controls/CopyButton.resx
diff --git a/ValheimServerGUI/Controls/EditButton.Designer.cs b/ValheimServerGUI/Controls/EditButton.Designer.cs
new file mode 100644
index 0000000..44f3d43
--- /dev/null
+++ b/ValheimServerGUI/Controls/EditButton.Designer.cs
@@ -0,0 +1,60 @@
+namespace ValheimServerGUI.Forms
+{
+ partial class EditButton
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.IconButton = new ValheimServerGUI.Controls.IconButton();
+ this.SuspendLayout();
+ //
+ // IconButton
+ //
+ this.IconButton.ConfirmImage = global::ValheimServerGUI.Properties.Resources.StatusOK_16x;
+ this.IconButton.HelpText = "Edit";
+ this.IconButton.IconClicked = null;
+ this.IconButton.Image = global::ValheimServerGUI.Properties.Resources.Edit_16x;
+ this.IconButton.Location = new System.Drawing.Point(0, 0);
+ this.IconButton.Name = "IconButton";
+ this.IconButton.Size = new System.Drawing.Size(16, 16);
+ this.IconButton.TabIndex = 0;
+ //
+ // EditButton
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.IconButton);
+ this.Name = "EditButton";
+ this.Size = new System.Drawing.Size(16, 16);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private ValheimServerGUI.Controls.IconButton IconButton;
+ }
+}
diff --git a/ValheimServerGUI/Controls/EditButton.cs b/ValheimServerGUI/Controls/EditButton.cs
new file mode 100644
index 0000000..baabce2
--- /dev/null
+++ b/ValheimServerGUI/Controls/EditButton.cs
@@ -0,0 +1,33 @@
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+
+namespace ValheimServerGUI.Forms
+{
+ public partial class EditButton : UserControl
+ {
+ [Browsable(false)]
+ public Action EditFunction { get; set; }
+
+ public string HelpText
+ {
+ get => IconButton.HelpText;
+ set => IconButton.HelpText = value;
+ }
+
+ public EditButton()
+ {
+ InitializeComponent();
+
+ IconButton.IconClicked = OnIconClicked;
+ }
+
+ private bool OnIconClicked()
+ {
+ if (EditFunction == null) return false;
+
+ EditFunction.Invoke();
+ return true;
+ }
+ }
+}
diff --git a/ValheimServerGUI/Forms/OpenButton.resx b/ValheimServerGUI/Controls/EditButton.resx
similarity index 100%
rename from ValheimServerGUI/Forms/OpenButton.resx
rename to ValheimServerGUI/Controls/EditButton.resx
diff --git a/ValheimServerGUI/Forms/OpenButton.Designer.cs b/ValheimServerGUI/Controls/OpenButton.Designer.cs
similarity index 100%
rename from ValheimServerGUI/Forms/OpenButton.Designer.cs
rename to ValheimServerGUI/Controls/OpenButton.Designer.cs
diff --git a/ValheimServerGUI/Forms/OpenButton.cs b/ValheimServerGUI/Controls/OpenButton.cs
similarity index 100%
rename from ValheimServerGUI/Forms/OpenButton.cs
rename to ValheimServerGUI/Controls/OpenButton.cs
diff --git a/ValheimServerGUI/Forms/RefreshButton.resx b/ValheimServerGUI/Controls/OpenButton.resx
similarity index 100%
rename from ValheimServerGUI/Forms/RefreshButton.resx
rename to ValheimServerGUI/Controls/OpenButton.resx
diff --git a/ValheimServerGUI/Forms/RefreshButton.Designer.cs b/ValheimServerGUI/Controls/RefreshButton.Designer.cs
similarity index 100%
rename from ValheimServerGUI/Forms/RefreshButton.Designer.cs
rename to ValheimServerGUI/Controls/RefreshButton.Designer.cs
diff --git a/ValheimServerGUI/Forms/RefreshButton.cs b/ValheimServerGUI/Controls/RefreshButton.cs
similarity index 100%
rename from ValheimServerGUI/Forms/RefreshButton.cs
rename to ValheimServerGUI/Controls/RefreshButton.cs
diff --git a/ValheimServerGUI/Controls/RefreshButton.resx b/ValheimServerGUI/Controls/RefreshButton.resx
new file mode 100644
index 0000000..f298a7b
--- /dev/null
+++ b/ValheimServerGUI/Controls/RefreshButton.resx
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ValheimServerGUI/Forms/AboutForm.cs b/ValheimServerGUI/Forms/AboutForm.cs
index c349685..9794872 100644
--- a/ValheimServerGUI/Forms/AboutForm.cs
+++ b/ValheimServerGUI/Forms/AboutForm.cs
@@ -15,7 +15,7 @@ public AboutForm()
try
{
VersionLabel.Text = $"Version: {AssemblyHelper.GetApplicationVersion()}";
- VersionLabel.Text += $"{Environment.NewLine}Build Date: {AssemblyHelper.GetApplicationBuildDate().ToUniversalTime():yyyy-MM-ddTHH:mm:ssZ}";
+ VersionLabel.Text += $"{Environment.NewLine}Build Date: {AssemblyHelper.GetApplicationBuildDate().ToUniversalTime().ToDisplayISOFormat()}";
}
catch { }
}
diff --git a/ValheimServerGUI/Forms/BugReportForm.cs b/ValheimServerGUI/Forms/BugReportForm.cs
index d1cfa72..9e15253 100644
--- a/ValheimServerGUI/Forms/BugReportForm.cs
+++ b/ValheimServerGUI/Forms/BugReportForm.cs
@@ -11,11 +11,11 @@ public partial class BugReportForm : Form
{
private readonly IRuneberryApiClient RuneberryApiClient;
- private readonly IEventLogger Logger;
+ private readonly IApplicationLogger Logger;
public BugReportForm(
IRuneberryApiClient runeberryApiClient,
- IEventLogger logger)
+ IApplicationLogger logger)
{
RuneberryApiClient = runeberryApiClient;
Logger = logger;
diff --git a/ValheimServerGUI/Forms/MainWindow.Designer.cs b/ValheimServerGUI/Forms/MainWindow.Designer.cs
index a0ea77e..0ce8c34 100644
--- a/ValheimServerGUI/Forms/MainWindow.Designer.cs
+++ b/ValheimServerGUI/Forms/MainWindow.Designer.cs
@@ -29,1203 +29,1178 @@ protected override void Dispose(bool disposing)
///
private void InitializeComponent()
{
- this.components = new System.ComponentModel.Container();
+ components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow));
- this.MenuStrip = new System.Windows.Forms.MenuStrip();
- this.MenuItemFile = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileNewWindow = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileSeparator3 = new System.Windows.Forms.ToolStripSeparator();
- this.MenuItemFileNewProfile = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileSaveProfile = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileSaveProfileAs = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileLoadProfile = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileRemoveProfile = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileSeparator2 = new System.Windows.Forms.ToolStripSeparator();
- this.MenuItemFilePreferences = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileDirectories = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileOpenSettings = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemFileSeparator1 = new System.Windows.Forms.ToolStripSeparator();
- this.MenuItemFileClose = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemHelp = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemHelpManual = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemHelpPortForwarding = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemHelpBugReport = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemHelpSeparator1 = new System.Windows.Forms.ToolStripSeparator();
- this.MenuItemHelpUpdates = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemHelpDiscord = new System.Windows.Forms.ToolStripMenuItem();
- this.MenuItemHelpAbout = new System.Windows.Forms.ToolStripMenuItem();
- this.StatusStrip = new System.Windows.Forms.StatusStrip();
- this.StatusStripLabelLeft = new System.Windows.Forms.ToolStripStatusLabel();
- this.StatusStripLabelSpacer = new System.Windows.Forms.ToolStripStatusLabel();
- this.StatusStripLabelRight = new System.Windows.Forms.ToolStripStatusLabel();
- this.Tabs = new System.Windows.Forms.TabControl();
- this.TabServerControls = new System.Windows.Forms.TabPage();
- this.CopyButtonServerPassword = new ValheimServerGUI.Forms.CopyButton();
- this.JoinOptionsGroupBox = new System.Windows.Forms.GroupBox();
- this.CommunityServerField = new ValheimServerGUI.Controls.CheckboxFormField();
- this.ServerCrossplayField = new ValheimServerGUI.Controls.CheckboxFormField();
- this.WorldSelectGroupBox = new System.Windows.Forms.GroupBox();
- this.WorldsListRefreshButton = new ValheimServerGUI.Forms.RefreshButton();
- this.WorldsFolderOpenButton = new ValheimServerGUI.Forms.OpenButton();
- this.WorldSelectNewNameField = new ValheimServerGUI.Forms.Controls.TextFormField();
- this.WorldSelectRadioNew = new ValheimServerGUI.Controls.RadioFormField();
- this.WorldSelectRadioExisting = new ValheimServerGUI.Controls.RadioFormField();
- this.WorldSelectExistingNameField = new ValheimServerGUI.Controls.DropdownFormField();
- this.ServerPortField = new ValheimServerGUI.Controls.NumericFormField();
- this.ButtonRestartServer = new System.Windows.Forms.Button();
- this.ShowPasswordField = new ValheimServerGUI.Controls.CheckboxFormField();
- this.ServerPasswordField = new ValheimServerGUI.Forms.Controls.TextFormField();
- this.ServerNameField = new ValheimServerGUI.Forms.Controls.TextFormField();
- this.ButtonStopServer = new System.Windows.Forms.Button();
- this.ButtonStartServer = new System.Windows.Forms.Button();
- this.TabAdvancedControls = new System.Windows.Forms.TabPage();
- this.SavingGroupBox = new System.Windows.Forms.GroupBox();
- this.ServerLongBackupIntervalField = new ValheimServerGUI.Controls.NumericFormField();
- this.ServerSaveIntervalField = new ValheimServerGUI.Controls.NumericFormField();
- this.ServerShortBackupIntervalField = new ValheimServerGUI.Controls.NumericFormField();
- this.ServerBackupsField = new ValheimServerGUI.Controls.NumericFormField();
- this.StartupGroupBox = new System.Windows.Forms.GroupBox();
- this.ServerAutoStartField = new ValheimServerGUI.Controls.CheckboxFormField();
- this.ServerAdditionalArgsField = new ValheimServerGUI.Forms.Controls.TextFormField();
- this.DirectoriesGroupBox = new System.Windows.Forms.GroupBox();
- this.ServerSaveDataPathOpenButton = new ValheimServerGUI.Forms.OpenButton();
- this.ServerExePathOpenButton = new ValheimServerGUI.Forms.OpenButton();
- this.ServerSaveDataFolderPathField = new ValheimServerGUI.Controls.FilenameFormField();
- this.ServerExePathField = new ValheimServerGUI.Controls.FilenameFormField();
- this.TabServerDetails = new System.Windows.Forms.TabPage();
- this.groupBox2 = new System.Windows.Forms.GroupBox();
- this.LabelSessionDuration = new ValheimServerGUI.Controls.LabelField();
- this.LabelAverageWorldSave = new ValheimServerGUI.Controls.LabelField();
- this.LabelLastWorldSave = new ValheimServerGUI.Controls.LabelField();
- this.groupBox1 = new System.Windows.Forms.GroupBox();
- this.CopyButtonInviteCode = new ValheimServerGUI.Forms.CopyButton();
- this.LabelInviteCode = new ValheimServerGUI.Controls.LabelField();
- this.CopyButtonLocalIpAddress = new ValheimServerGUI.Forms.CopyButton();
- this.CopyButtonExternalIpAddress = new ValheimServerGUI.Forms.CopyButton();
- this.CopyButtonInternalIpAddress = new ValheimServerGUI.Forms.CopyButton();
- this.label1 = new System.Windows.Forms.Label();
- this.LabelExternalIpAddress = new ValheimServerGUI.Controls.LabelField();
- this.LabelLocalIpAddress = new ValheimServerGUI.Controls.LabelField();
- this.LabelInternalIpAddress = new ValheimServerGUI.Controls.LabelField();
- this.TabPlayers = new System.Windows.Forms.TabPage();
- this.ButtonRemovePlayer = new System.Windows.Forms.Button();
- this.ButtonPlayerDetails = new System.Windows.Forms.Button();
- this.PlayersTable = new ValheimServerGUI.Controls.DataListView();
- this.ColumnPlayerStatus = new System.Windows.Forms.ColumnHeader();
- this.ColumnPlayerName = new System.Windows.Forms.ColumnHeader();
- this.ColumnPlayerUpdated = new System.Windows.Forms.ColumnHeader();
- this.ImageList = new System.Windows.Forms.ImageList(this.components);
- this.TabLogs = new System.Windows.Forms.TabPage();
- this.ButtonSaveLogs = new System.Windows.Forms.Button();
- this.LogViewSelectField = new ValheimServerGUI.Controls.DropdownFormField();
- this.LogViewer = new ValheimServerGUI.Controls.LogViewer();
- this.ButtonClearLogs = new System.Windows.Forms.Button();
- this.NotifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
- this.TrayContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
- this.TrayContextMenuServerName = new System.Windows.Forms.ToolStripMenuItem();
- this.TrayContextMenuSeparator2 = new System.Windows.Forms.ToolStripSeparator();
- this.TrayContextMenuStart = new System.Windows.Forms.ToolStripMenuItem();
- this.TrayContextMenuRestart = new System.Windows.Forms.ToolStripMenuItem();
- this.TrayContextMenuStop = new System.Windows.Forms.ToolStripMenuItem();
- this.TrayContextMenuSeparator1 = new System.Windows.Forms.ToolStripSeparator();
- this.TrayContextMenuClose = new System.Windows.Forms.ToolStripMenuItem();
- this.ServerRefreshTimer = new System.Windows.Forms.Timer(this.components);
- this.UpdateCheckTimer = new System.Windows.Forms.Timer(this.components);
- this.MenuStrip.SuspendLayout();
- this.StatusStrip.SuspendLayout();
- this.Tabs.SuspendLayout();
- this.TabServerControls.SuspendLayout();
- this.JoinOptionsGroupBox.SuspendLayout();
- this.WorldSelectGroupBox.SuspendLayout();
- this.TabAdvancedControls.SuspendLayout();
- this.SavingGroupBox.SuspendLayout();
- this.StartupGroupBox.SuspendLayout();
- this.DirectoriesGroupBox.SuspendLayout();
- this.TabServerDetails.SuspendLayout();
- this.groupBox2.SuspendLayout();
- this.groupBox1.SuspendLayout();
- this.TabPlayers.SuspendLayout();
- this.TabLogs.SuspendLayout();
- this.TrayContextMenuStrip.SuspendLayout();
- this.SuspendLayout();
+ MenuStrip = new System.Windows.Forms.MenuStrip();
+ MenuItemFile = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileNewWindow = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileSeparator3 = new System.Windows.Forms.ToolStripSeparator();
+ MenuItemFileNewProfile = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileSaveProfile = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileSaveProfileAs = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileLoadProfile = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileRemoveProfile = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+ MenuItemFilePreferences = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileDirectories = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileOpenSettings = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemFileSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ MenuItemFileClose = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemHelp = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemHelpManual = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemHelpPortForwarding = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemHelpBugReport = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemHelpSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ MenuItemHelpUpdates = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemHelpDiscord = new System.Windows.Forms.ToolStripMenuItem();
+ MenuItemHelpAbout = new System.Windows.Forms.ToolStripMenuItem();
+ StatusStrip = new System.Windows.Forms.StatusStrip();
+ StatusStripLabelLeft = new System.Windows.Forms.ToolStripStatusLabel();
+ StatusStripLabelSpacer = new System.Windows.Forms.ToolStripStatusLabel();
+ StatusStripLabelRight = new System.Windows.Forms.ToolStripStatusLabel();
+ Tabs = new System.Windows.Forms.TabControl();
+ TabServerControls = new System.Windows.Forms.TabPage();
+ CopyButtonServerPassword = new CopyButton();
+ JoinOptionsGroupBox = new System.Windows.Forms.GroupBox();
+ CommunityServerField = new ValheimServerGUI.Controls.CheckboxFormField();
+ ServerCrossplayField = new ValheimServerGUI.Controls.CheckboxFormField();
+ WorldSelectGroupBox = new System.Windows.Forms.GroupBox();
+ WorldsListRefreshButton = new RefreshButton();
+ WorldsFolderOpenButton = new OpenButton();
+ WorldSelectNewNameField = new Controls.TextFormField();
+ WorldSelectRadioNew = new ValheimServerGUI.Controls.RadioFormField();
+ WorldSelectRadioExisting = new ValheimServerGUI.Controls.RadioFormField();
+ WorldSelectExistingNameField = new ValheimServerGUI.Controls.DropdownFormField();
+ ServerPortField = new ValheimServerGUI.Controls.NumericFormField();
+ ButtonRestartServer = new System.Windows.Forms.Button();
+ ShowPasswordField = new ValheimServerGUI.Controls.CheckboxFormField();
+ ServerPasswordField = new Controls.TextFormField();
+ ServerNameField = new Controls.TextFormField();
+ ButtonStopServer = new System.Windows.Forms.Button();
+ ButtonStartServer = new System.Windows.Forms.Button();
+ TabAdvancedControls = new System.Windows.Forms.TabPage();
+ SavingGroupBox = new System.Windows.Forms.GroupBox();
+ ServerLongBackupIntervalField = new ValheimServerGUI.Controls.NumericFormField();
+ ServerSaveIntervalField = new ValheimServerGUI.Controls.NumericFormField();
+ ServerShortBackupIntervalField = new ValheimServerGUI.Controls.NumericFormField();
+ ServerBackupsField = new ValheimServerGUI.Controls.NumericFormField();
+ OtherSettingsGroupBox = new System.Windows.Forms.GroupBox();
+ ServerLogFileField = new ValheimServerGUI.Controls.CheckboxFormField();
+ ServerAutoStartField = new ValheimServerGUI.Controls.CheckboxFormField();
+ ServerAdditionalArgsField = new Controls.TextFormField();
+ DirectoriesGroupBox = new System.Windows.Forms.GroupBox();
+ ServerSaveDataPathOpenButton = new OpenButton();
+ ServerExePathOpenButton = new OpenButton();
+ ServerSaveDataFolderPathField = new ValheimServerGUI.Controls.FilenameFormField();
+ ServerExePathField = new ValheimServerGUI.Controls.FilenameFormField();
+ TabServerDetails = new System.Windows.Forms.TabPage();
+ groupBox2 = new System.Windows.Forms.GroupBox();
+ LabelSessionDuration = new ValheimServerGUI.Controls.LabelField();
+ LabelAverageWorldSave = new ValheimServerGUI.Controls.LabelField();
+ LabelLastWorldSave = new ValheimServerGUI.Controls.LabelField();
+ groupBox1 = new System.Windows.Forms.GroupBox();
+ CopyButtonInviteCode = new CopyButton();
+ LabelInviteCode = new ValheimServerGUI.Controls.LabelField();
+ CopyButtonLocalIpAddress = new CopyButton();
+ CopyButtonExternalIpAddress = new CopyButton();
+ CopyButtonInternalIpAddress = new CopyButton();
+ label1 = new System.Windows.Forms.Label();
+ LabelExternalIpAddress = new ValheimServerGUI.Controls.LabelField();
+ LabelLocalIpAddress = new ValheimServerGUI.Controls.LabelField();
+ LabelInternalIpAddress = new ValheimServerGUI.Controls.LabelField();
+ TabPlayers = new System.Windows.Forms.TabPage();
+ LinkCharacterNamesHelp = new System.Windows.Forms.LinkLabel();
+ ButtonRemovePlayer = new System.Windows.Forms.Button();
+ ButtonPlayerDetails = new System.Windows.Forms.Button();
+ PlayersTable = new ValheimServerGUI.Controls.DataListView();
+ ColumnPlayerName = new System.Windows.Forms.ColumnHeader();
+ ColumnPlayerStatus = new System.Windows.Forms.ColumnHeader();
+ ColumnPlayerUpdated = new System.Windows.Forms.ColumnHeader();
+ ImageList = new System.Windows.Forms.ImageList(components);
+ TabLogs = new System.Windows.Forms.TabPage();
+ LogsFolderOpenButton = new OpenButton();
+ ButtonSaveLogs = new System.Windows.Forms.Button();
+ LogViewSelectField = new ValheimServerGUI.Controls.DropdownFormField();
+ LogViewer = new ValheimServerGUI.Controls.LogViewer();
+ ButtonClearLogs = new System.Windows.Forms.Button();
+ NotifyIcon = new System.Windows.Forms.NotifyIcon(components);
+ TrayContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(components);
+ TrayContextMenuServerName = new System.Windows.Forms.ToolStripMenuItem();
+ TrayContextMenuSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+ TrayContextMenuStart = new System.Windows.Forms.ToolStripMenuItem();
+ TrayContextMenuRestart = new System.Windows.Forms.ToolStripMenuItem();
+ TrayContextMenuStop = new System.Windows.Forms.ToolStripMenuItem();
+ TrayContextMenuSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ TrayContextMenuClose = new System.Windows.Forms.ToolStripMenuItem();
+ ServerRefreshTimer = new System.Windows.Forms.Timer(components);
+ UpdateCheckTimer = new System.Windows.Forms.Timer(components);
+ MenuStrip.SuspendLayout();
+ StatusStrip.SuspendLayout();
+ Tabs.SuspendLayout();
+ TabServerControls.SuspendLayout();
+ JoinOptionsGroupBox.SuspendLayout();
+ WorldSelectGroupBox.SuspendLayout();
+ TabAdvancedControls.SuspendLayout();
+ SavingGroupBox.SuspendLayout();
+ OtherSettingsGroupBox.SuspendLayout();
+ DirectoriesGroupBox.SuspendLayout();
+ TabServerDetails.SuspendLayout();
+ groupBox2.SuspendLayout();
+ groupBox1.SuspendLayout();
+ TabPlayers.SuspendLayout();
+ TabLogs.SuspendLayout();
+ TrayContextMenuStrip.SuspendLayout();
+ SuspendLayout();
//
// MenuStrip
//
- this.MenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.MenuItemFile,
- this.MenuItemHelp});
- this.MenuStrip.Location = new System.Drawing.Point(0, 0);
- this.MenuStrip.Name = "MenuStrip";
- this.MenuStrip.Size = new System.Drawing.Size(484, 24);
- this.MenuStrip.TabIndex = 0;
+ MenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { MenuItemFile, MenuItemHelp });
+ MenuStrip.Location = new System.Drawing.Point(0, 0);
+ MenuStrip.Name = "MenuStrip";
+ MenuStrip.Size = new System.Drawing.Size(484, 24);
+ MenuStrip.TabIndex = 0;
//
// MenuItemFile
//
- this.MenuItemFile.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.MenuItemFileNewWindow,
- this.MenuItemFileSeparator3,
- this.MenuItemFileNewProfile,
- this.MenuItemFileSaveProfile,
- this.MenuItemFileSaveProfileAs,
- this.MenuItemFileLoadProfile,
- this.MenuItemFileRemoveProfile,
- this.MenuItemFileSeparator2,
- this.MenuItemFilePreferences,
- this.MenuItemFileDirectories,
- this.MenuItemFileOpenSettings,
- this.MenuItemFileSeparator1,
- this.MenuItemFileClose});
- this.MenuItemFile.Name = "MenuItemFile";
- this.MenuItemFile.Size = new System.Drawing.Size(37, 20);
- this.MenuItemFile.Text = "&File";
+ MenuItemFile.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { MenuItemFileNewWindow, MenuItemFileSeparator3, MenuItemFileNewProfile, MenuItemFileSaveProfile, MenuItemFileSaveProfileAs, MenuItemFileLoadProfile, MenuItemFileRemoveProfile, MenuItemFileSeparator2, MenuItemFilePreferences, MenuItemFileDirectories, MenuItemFileOpenSettings, MenuItemFileSeparator1, MenuItemFileClose });
+ MenuItemFile.Name = "MenuItemFile";
+ MenuItemFile.Size = new System.Drawing.Size(37, 20);
+ MenuItemFile.Text = "&File";
//
// MenuItemFileNewWindow
//
- this.MenuItemFileNewWindow.Image = global::ValheimServerGUI.Properties.Resources.AddImmediateWindow_16x;
- this.MenuItemFileNewWindow.Name = "MenuItemFileNewWindow";
- this.MenuItemFileNewWindow.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFileNewWindow.Text = "New &Window";
+ MenuItemFileNewWindow.Image = Properties.Resources.AddImmediateWindow_16x;
+ MenuItemFileNewWindow.Name = "MenuItemFileNewWindow";
+ MenuItemFileNewWindow.Size = new System.Drawing.Size(208, 22);
+ MenuItemFileNewWindow.Text = "New &Window";
//
// MenuItemFileSeparator3
//
- this.MenuItemFileSeparator3.Name = "MenuItemFileSeparator3";
- this.MenuItemFileSeparator3.Size = new System.Drawing.Size(205, 6);
+ MenuItemFileSeparator3.Name = "MenuItemFileSeparator3";
+ MenuItemFileSeparator3.Size = new System.Drawing.Size(205, 6);
//
// MenuItemFileNewProfile
//
- this.MenuItemFileNewProfile.Image = global::ValheimServerGUI.Properties.Resources.NewFile_16x;
- this.MenuItemFileNewProfile.Name = "MenuItemFileNewProfile";
- this.MenuItemFileNewProfile.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFileNewProfile.Text = "&New Profile";
+ MenuItemFileNewProfile.Image = Properties.Resources.NewFile_16x;
+ MenuItemFileNewProfile.Name = "MenuItemFileNewProfile";
+ MenuItemFileNewProfile.Size = new System.Drawing.Size(208, 22);
+ MenuItemFileNewProfile.Text = "&New Profile";
//
// MenuItemFileSaveProfile
//
- this.MenuItemFileSaveProfile.Image = global::ValheimServerGUI.Properties.Resources.Save_16x;
- this.MenuItemFileSaveProfile.Name = "MenuItemFileSaveProfile";
- this.MenuItemFileSaveProfile.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFileSaveProfile.Text = "&Save Profile";
+ MenuItemFileSaveProfile.Image = Properties.Resources.Save_16x;
+ MenuItemFileSaveProfile.Name = "MenuItemFileSaveProfile";
+ MenuItemFileSaveProfile.Size = new System.Drawing.Size(208, 22);
+ MenuItemFileSaveProfile.Text = "&Save Profile";
//
// MenuItemFileSaveProfileAs
//
- this.MenuItemFileSaveProfileAs.Image = global::ValheimServerGUI.Properties.Resources.Save_16x;
- this.MenuItemFileSaveProfileAs.Name = "MenuItemFileSaveProfileAs";
- this.MenuItemFileSaveProfileAs.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFileSaveProfileAs.Text = "Save Profile &As...";
+ MenuItemFileSaveProfileAs.Image = Properties.Resources.Save_16x;
+ MenuItemFileSaveProfileAs.Name = "MenuItemFileSaveProfileAs";
+ MenuItemFileSaveProfileAs.Size = new System.Drawing.Size(208, 22);
+ MenuItemFileSaveProfileAs.Text = "Save Profile &As...";
//
// MenuItemFileLoadProfile
//
- this.MenuItemFileLoadProfile.Image = global::ValheimServerGUI.Properties.Resources.OpenFile_16x;
- this.MenuItemFileLoadProfile.Name = "MenuItemFileLoadProfile";
- this.MenuItemFileLoadProfile.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFileLoadProfile.Text = "&Load Profile";
+ MenuItemFileLoadProfile.Image = Properties.Resources.OpenFile_16x;
+ MenuItemFileLoadProfile.Name = "MenuItemFileLoadProfile";
+ MenuItemFileLoadProfile.Size = new System.Drawing.Size(208, 22);
+ MenuItemFileLoadProfile.Text = "&Load Profile";
//
// MenuItemFileRemoveProfile
//
- this.MenuItemFileRemoveProfile.Image = global::ValheimServerGUI.Properties.Resources.Cancel_16x;
- this.MenuItemFileRemoveProfile.Name = "MenuItemFileRemoveProfile";
- this.MenuItemFileRemoveProfile.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFileRemoveProfile.Text = "&Remove Profile";
+ MenuItemFileRemoveProfile.Image = Properties.Resources.Cancel_16x;
+ MenuItemFileRemoveProfile.Name = "MenuItemFileRemoveProfile";
+ MenuItemFileRemoveProfile.Size = new System.Drawing.Size(208, 22);
+ MenuItemFileRemoveProfile.Text = "&Remove Profile";
//
// MenuItemFileSeparator2
//
- this.MenuItemFileSeparator2.Name = "MenuItemFileSeparator2";
- this.MenuItemFileSeparator2.Size = new System.Drawing.Size(205, 6);
+ MenuItemFileSeparator2.Name = "MenuItemFileSeparator2";
+ MenuItemFileSeparator2.Size = new System.Drawing.Size(205, 6);
//
// MenuItemFilePreferences
//
- this.MenuItemFilePreferences.Image = global::ValheimServerGUI.Properties.Resources.Settings_16x;
- this.MenuItemFilePreferences.Name = "MenuItemFilePreferences";
- this.MenuItemFilePreferences.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFilePreferences.Text = "&Preferences...";
+ MenuItemFilePreferences.Image = Properties.Resources.Settings_16x;
+ MenuItemFilePreferences.Name = "MenuItemFilePreferences";
+ MenuItemFilePreferences.Size = new System.Drawing.Size(208, 22);
+ MenuItemFilePreferences.Text = "&Preferences...";
//
// MenuItemFileDirectories
//
- this.MenuItemFileDirectories.Image = global::ValheimServerGUI.Properties.Resources.FolderInformation_16x;
- this.MenuItemFileDirectories.Name = "MenuItemFileDirectories";
- this.MenuItemFileDirectories.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFileDirectories.Text = "Set &Directories...";
+ MenuItemFileDirectories.Image = Properties.Resources.FolderInformation_16x;
+ MenuItemFileDirectories.Name = "MenuItemFileDirectories";
+ MenuItemFileDirectories.Size = new System.Drawing.Size(208, 22);
+ MenuItemFileDirectories.Text = "Set &Directories...";
//
// MenuItemFileOpenSettings
//
- this.MenuItemFileOpenSettings.Image = global::ValheimServerGUI.Properties.Resources.OpenFolder_16x;
- this.MenuItemFileOpenSettings.Name = "MenuItemFileOpenSettings";
- this.MenuItemFileOpenSettings.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFileOpenSettings.Text = "&Open Settings Directory...";
+ MenuItemFileOpenSettings.Image = Properties.Resources.OpenFolder_16x;
+ MenuItemFileOpenSettings.Name = "MenuItemFileOpenSettings";
+ MenuItemFileOpenSettings.Size = new System.Drawing.Size(208, 22);
+ MenuItemFileOpenSettings.Text = "&Open Settings Directory...";
//
// MenuItemFileSeparator1
//
- this.MenuItemFileSeparator1.Name = "MenuItemFileSeparator1";
- this.MenuItemFileSeparator1.Size = new System.Drawing.Size(205, 6);
+ MenuItemFileSeparator1.Name = "MenuItemFileSeparator1";
+ MenuItemFileSeparator1.Size = new System.Drawing.Size(205, 6);
//
// MenuItemFileClose
//
- this.MenuItemFileClose.Name = "MenuItemFileClose";
- this.MenuItemFileClose.Size = new System.Drawing.Size(208, 22);
- this.MenuItemFileClose.Text = "&Close";
+ MenuItemFileClose.Name = "MenuItemFileClose";
+ MenuItemFileClose.Size = new System.Drawing.Size(208, 22);
+ MenuItemFileClose.Text = "&Close";
//
// MenuItemHelp
//
- this.MenuItemHelp.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.MenuItemHelpManual,
- this.MenuItemHelpPortForwarding,
- this.MenuItemHelpBugReport,
- this.MenuItemHelpSeparator1,
- this.MenuItemHelpUpdates,
- this.MenuItemHelpDiscord,
- this.MenuItemHelpAbout});
- this.MenuItemHelp.Name = "MenuItemHelp";
- this.MenuItemHelp.Size = new System.Drawing.Size(44, 20);
- this.MenuItemHelp.Text = "&Help";
+ MenuItemHelp.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { MenuItemHelpManual, MenuItemHelpPortForwarding, MenuItemHelpBugReport, MenuItemHelpSeparator1, MenuItemHelpUpdates, MenuItemHelpDiscord, MenuItemHelpAbout });
+ MenuItemHelp.Name = "MenuItemHelp";
+ MenuItemHelp.Size = new System.Drawing.Size(44, 20);
+ MenuItemHelp.Text = "&Help";
//
// MenuItemHelpManual
//
- this.MenuItemHelpManual.Image = global::ValheimServerGUI.Properties.Resources.OpenWeb_16x;
- this.MenuItemHelpManual.Name = "MenuItemHelpManual";
- this.MenuItemHelpManual.Size = new System.Drawing.Size(192, 22);
- this.MenuItemHelpManual.Text = "Online &Manual";
+ MenuItemHelpManual.Image = Properties.Resources.OpenWeb_16x;
+ MenuItemHelpManual.Name = "MenuItemHelpManual";
+ MenuItemHelpManual.Size = new System.Drawing.Size(192, 22);
+ MenuItemHelpManual.Text = "Online &Manual";
//
// MenuItemHelpPortForwarding
//
- this.MenuItemHelpPortForwarding.Image = global::ValheimServerGUI.Properties.Resources.OpenWeb_16x;
- this.MenuItemHelpPortForwarding.Name = "MenuItemHelpPortForwarding";
- this.MenuItemHelpPortForwarding.Size = new System.Drawing.Size(192, 22);
- this.MenuItemHelpPortForwarding.Text = "&Port Forwarding";
+ MenuItemHelpPortForwarding.Image = Properties.Resources.OpenWeb_16x;
+ MenuItemHelpPortForwarding.Name = "MenuItemHelpPortForwarding";
+ MenuItemHelpPortForwarding.Size = new System.Drawing.Size(192, 22);
+ MenuItemHelpPortForwarding.Text = "&Port Forwarding";
//
// MenuItemHelpBugReport
//
- this.MenuItemHelpBugReport.Image = global::ValheimServerGUI.Properties.Resources.NewBug_16x;
- this.MenuItemHelpBugReport.Name = "MenuItemHelpBugReport";
- this.MenuItemHelpBugReport.Size = new System.Drawing.Size(192, 22);
- this.MenuItemHelpBugReport.Text = "Submit a &Bug Report...";
+ MenuItemHelpBugReport.Image = Properties.Resources.NewBug_16x;
+ MenuItemHelpBugReport.Name = "MenuItemHelpBugReport";
+ MenuItemHelpBugReport.Size = new System.Drawing.Size(192, 22);
+ MenuItemHelpBugReport.Text = "Submit a &Bug Report...";
//
// MenuItemHelpSeparator1
//
- this.MenuItemHelpSeparator1.Name = "MenuItemHelpSeparator1";
- this.MenuItemHelpSeparator1.Size = new System.Drawing.Size(189, 6);
+ MenuItemHelpSeparator1.Name = "MenuItemHelpSeparator1";
+ MenuItemHelpSeparator1.Size = new System.Drawing.Size(189, 6);
//
// MenuItemHelpUpdates
//
- this.MenuItemHelpUpdates.Image = global::ValheimServerGUI.Properties.Resources.UnsyncedCommits_16x_Horiz;
- this.MenuItemHelpUpdates.Name = "MenuItemHelpUpdates";
- this.MenuItemHelpUpdates.Size = new System.Drawing.Size(192, 22);
- this.MenuItemHelpUpdates.Text = "Check for &Updates";
+ MenuItemHelpUpdates.Image = Properties.Resources.UnsyncedCommits_16x_Horiz;
+ MenuItemHelpUpdates.Name = "MenuItemHelpUpdates";
+ MenuItemHelpUpdates.Size = new System.Drawing.Size(192, 22);
+ MenuItemHelpUpdates.Text = "Check for &Updates";
//
// MenuItemHelpDiscord
//
- this.MenuItemHelpDiscord.Image = global::ValheimServerGUI.Properties.Resources.DiscordLogo;
- this.MenuItemHelpDiscord.Name = "MenuItemHelpDiscord";
- this.MenuItemHelpDiscord.Size = new System.Drawing.Size(192, 22);
- this.MenuItemHelpDiscord.Text = "Get support in &Discord";
+ MenuItemHelpDiscord.Image = Properties.Resources.DiscordLogo;
+ MenuItemHelpDiscord.Name = "MenuItemHelpDiscord";
+ MenuItemHelpDiscord.Size = new System.Drawing.Size(192, 22);
+ MenuItemHelpDiscord.Text = "Get support in &Discord";
//
// MenuItemHelpAbout
//
- this.MenuItemHelpAbout.Name = "MenuItemHelpAbout";
- this.MenuItemHelpAbout.Size = new System.Drawing.Size(192, 22);
- this.MenuItemHelpAbout.Text = "&About...";
+ MenuItemHelpAbout.Name = "MenuItemHelpAbout";
+ MenuItemHelpAbout.Size = new System.Drawing.Size(192, 22);
+ MenuItemHelpAbout.Text = "&About...";
//
// StatusStrip
//
- this.StatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.StatusStripLabelLeft,
- this.StatusStripLabelSpacer,
- this.StatusStripLabelRight});
- this.StatusStrip.Location = new System.Drawing.Point(0, 310);
- this.StatusStrip.Name = "StatusStrip";
- this.StatusStrip.Size = new System.Drawing.Size(484, 22);
- this.StatusStrip.TabIndex = 2;
+ StatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { StatusStripLabelLeft, StatusStripLabelSpacer, StatusStripLabelRight });
+ StatusStrip.Location = new System.Drawing.Point(0, 310);
+ StatusStrip.Name = "StatusStrip";
+ StatusStrip.Size = new System.Drawing.Size(484, 22);
+ StatusStrip.TabIndex = 2;
//
// StatusStripLabelLeft
//
- this.StatusStripLabelLeft.Name = "StatusStripLabelLeft";
- this.StatusStripLabelLeft.Size = new System.Drawing.Size(0, 17);
+ StatusStripLabelLeft.Name = "StatusStripLabelLeft";
+ StatusStripLabelLeft.Size = new System.Drawing.Size(0, 17);
//
// StatusStripLabelSpacer
//
- this.StatusStripLabelSpacer.Name = "StatusStripLabelSpacer";
- this.StatusStripLabelSpacer.Size = new System.Drawing.Size(469, 17);
- this.StatusStripLabelSpacer.Spring = true;
+ StatusStripLabelSpacer.Name = "StatusStripLabelSpacer";
+ StatusStripLabelSpacer.Size = new System.Drawing.Size(469, 17);
+ StatusStripLabelSpacer.Spring = true;
//
// StatusStripLabelRight
//
- this.StatusStripLabelRight.Name = "StatusStripLabelRight";
- this.StatusStripLabelRight.Size = new System.Drawing.Size(0, 17);
+ StatusStripLabelRight.Name = "StatusStripLabelRight";
+ StatusStripLabelRight.Size = new System.Drawing.Size(0, 17);
//
// Tabs
//
- this.Tabs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.Tabs.Controls.Add(this.TabServerControls);
- this.Tabs.Controls.Add(this.TabAdvancedControls);
- this.Tabs.Controls.Add(this.TabServerDetails);
- this.Tabs.Controls.Add(this.TabPlayers);
- this.Tabs.Controls.Add(this.TabLogs);
- this.Tabs.Location = new System.Drawing.Point(12, 27);
- this.Tabs.Name = "Tabs";
- this.Tabs.SelectedIndex = 0;
- this.Tabs.Size = new System.Drawing.Size(460, 280);
- this.Tabs.TabIndex = 1;
+ Tabs.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ Tabs.Controls.Add(TabServerControls);
+ Tabs.Controls.Add(TabAdvancedControls);
+ Tabs.Controls.Add(TabServerDetails);
+ Tabs.Controls.Add(TabPlayers);
+ Tabs.Controls.Add(TabLogs);
+ Tabs.Location = new System.Drawing.Point(12, 27);
+ Tabs.Name = "Tabs";
+ Tabs.SelectedIndex = 0;
+ Tabs.Size = new System.Drawing.Size(460, 280);
+ Tabs.TabIndex = 1;
//
// TabServerControls
//
- this.TabServerControls.Controls.Add(this.CopyButtonServerPassword);
- this.TabServerControls.Controls.Add(this.JoinOptionsGroupBox);
- this.TabServerControls.Controls.Add(this.WorldSelectGroupBox);
- this.TabServerControls.Controls.Add(this.ServerPortField);
- this.TabServerControls.Controls.Add(this.ButtonRestartServer);
- this.TabServerControls.Controls.Add(this.ShowPasswordField);
- this.TabServerControls.Controls.Add(this.ServerPasswordField);
- this.TabServerControls.Controls.Add(this.ServerNameField);
- this.TabServerControls.Controls.Add(this.ButtonStopServer);
- this.TabServerControls.Controls.Add(this.ButtonStartServer);
- this.TabServerControls.Location = new System.Drawing.Point(4, 24);
- this.TabServerControls.Name = "TabServerControls";
- this.TabServerControls.Padding = new System.Windows.Forms.Padding(3);
- this.TabServerControls.Size = new System.Drawing.Size(452, 252);
- this.TabServerControls.TabIndex = 0;
- this.TabServerControls.Text = "Server Controls";
- this.TabServerControls.UseVisualStyleBackColor = true;
+ TabServerControls.Controls.Add(CopyButtonServerPassword);
+ TabServerControls.Controls.Add(JoinOptionsGroupBox);
+ TabServerControls.Controls.Add(WorldSelectGroupBox);
+ TabServerControls.Controls.Add(ServerPortField);
+ TabServerControls.Controls.Add(ButtonRestartServer);
+ TabServerControls.Controls.Add(ShowPasswordField);
+ TabServerControls.Controls.Add(ServerPasswordField);
+ TabServerControls.Controls.Add(ServerNameField);
+ TabServerControls.Controls.Add(ButtonStopServer);
+ TabServerControls.Controls.Add(ButtonStartServer);
+ TabServerControls.Location = new System.Drawing.Point(4, 24);
+ TabServerControls.Name = "TabServerControls";
+ TabServerControls.Padding = new System.Windows.Forms.Padding(3);
+ TabServerControls.Size = new System.Drawing.Size(452, 252);
+ TabServerControls.TabIndex = 0;
+ TabServerControls.Text = "Server Controls";
+ TabServerControls.UseVisualStyleBackColor = true;
//
// CopyButtonServerPassword
//
- this.CopyButtonServerPassword.CopyFunction = null;
- this.CopyButtonServerPassword.HelpText = "Copy password to clipboard";
- this.CopyButtonServerPassword.Location = new System.Drawing.Point(236, 69);
- this.CopyButtonServerPassword.Name = "CopyButtonServerPassword";
- this.CopyButtonServerPassword.Size = new System.Drawing.Size(16, 16);
- this.CopyButtonServerPassword.TabIndex = 3;
- this.CopyButtonServerPassword.TabStop = false;
+ CopyButtonServerPassword.CopyFunction = null;
+ CopyButtonServerPassword.HelpText = "Copy password to clipboard";
+ CopyButtonServerPassword.Location = new System.Drawing.Point(236, 69);
+ CopyButtonServerPassword.Name = "CopyButtonServerPassword";
+ CopyButtonServerPassword.Size = new System.Drawing.Size(16, 16);
+ CopyButtonServerPassword.TabIndex = 3;
+ CopyButtonServerPassword.TabStop = false;
//
// JoinOptionsGroupBox
//
- this.JoinOptionsGroupBox.Controls.Add(this.CommunityServerField);
- this.JoinOptionsGroupBox.Controls.Add(this.ServerCrossplayField);
- this.JoinOptionsGroupBox.Location = new System.Drawing.Point(249, 94);
- this.JoinOptionsGroupBox.Name = "JoinOptionsGroupBox";
- this.JoinOptionsGroupBox.Size = new System.Drawing.Size(197, 96);
- this.JoinOptionsGroupBox.TabIndex = 6;
- this.JoinOptionsGroupBox.TabStop = false;
- this.JoinOptionsGroupBox.Text = "Join Options";
+ JoinOptionsGroupBox.Controls.Add(CommunityServerField);
+ JoinOptionsGroupBox.Controls.Add(ServerCrossplayField);
+ JoinOptionsGroupBox.Location = new System.Drawing.Point(249, 94);
+ JoinOptionsGroupBox.Name = "JoinOptionsGroupBox";
+ JoinOptionsGroupBox.Size = new System.Drawing.Size(197, 96);
+ JoinOptionsGroupBox.TabIndex = 6;
+ JoinOptionsGroupBox.TabStop = false;
+ JoinOptionsGroupBox.Text = "Join Options";
//
// CommunityServerField
//
- this.CommunityServerField.HelpText = resources.GetString("CommunityServerField.HelpText");
- this.CommunityServerField.LabelText = "Community Server (Public)";
- this.CommunityServerField.Location = new System.Drawing.Point(6, 22);
- this.CommunityServerField.Name = "CommunityServerField";
- this.CommunityServerField.Size = new System.Drawing.Size(185, 17);
- this.CommunityServerField.TabIndex = 0;
- this.CommunityServerField.Value = false;
+ CommunityServerField.HelpText = resources.GetString("CommunityServerField.HelpText");
+ CommunityServerField.LabelText = "Community Server (Public)";
+ CommunityServerField.Location = new System.Drawing.Point(6, 22);
+ CommunityServerField.Name = "CommunityServerField";
+ CommunityServerField.Size = new System.Drawing.Size(185, 17);
+ CommunityServerField.TabIndex = 0;
+ CommunityServerField.Value = false;
//
// ServerCrossplayField
//
- this.ServerCrossplayField.HelpText = "Allow players on other platforms to join your game\r\n(Microsoft Store, Xbox, etc.)" +
- "\r\n\r\nYou may need to provide other players an Invite Code,\r\nwhich appears in game" +
- " and in the server logs.";
- this.ServerCrossplayField.LabelText = "Enable Crossplay";
- this.ServerCrossplayField.Location = new System.Drawing.Point(6, 45);
- this.ServerCrossplayField.Name = "ServerCrossplayField";
- this.ServerCrossplayField.Size = new System.Drawing.Size(133, 17);
- this.ServerCrossplayField.TabIndex = 1;
- this.ServerCrossplayField.Value = false;
+ ServerCrossplayField.HelpText = "Allow players on other platforms to join your game\r\n(Microsoft Store, Xbox, etc.)\r\n\r\nYou may need to provide other players an Invite Code,\r\nwhich appears in game and in the server logs.";
+ ServerCrossplayField.LabelText = "Enable Crossplay";
+ ServerCrossplayField.Location = new System.Drawing.Point(6, 45);
+ ServerCrossplayField.Name = "ServerCrossplayField";
+ ServerCrossplayField.Size = new System.Drawing.Size(133, 17);
+ ServerCrossplayField.TabIndex = 1;
+ ServerCrossplayField.Value = false;
//
// WorldSelectGroupBox
//
- this.WorldSelectGroupBox.Controls.Add(this.WorldsListRefreshButton);
- this.WorldSelectGroupBox.Controls.Add(this.WorldsFolderOpenButton);
- this.WorldSelectGroupBox.Controls.Add(this.WorldSelectNewNameField);
- this.WorldSelectGroupBox.Controls.Add(this.WorldSelectRadioNew);
- this.WorldSelectGroupBox.Controls.Add(this.WorldSelectRadioExisting);
- this.WorldSelectGroupBox.Controls.Add(this.WorldSelectExistingNameField);
- this.WorldSelectGroupBox.Location = new System.Drawing.Point(3, 94);
- this.WorldSelectGroupBox.Name = "WorldSelectGroupBox";
- this.WorldSelectGroupBox.Size = new System.Drawing.Size(240, 96);
- this.WorldSelectGroupBox.TabIndex = 5;
- this.WorldSelectGroupBox.TabStop = false;
- this.WorldSelectGroupBox.Text = "World";
+ WorldSelectGroupBox.Controls.Add(WorldsListRefreshButton);
+ WorldSelectGroupBox.Controls.Add(WorldsFolderOpenButton);
+ WorldSelectGroupBox.Controls.Add(WorldSelectNewNameField);
+ WorldSelectGroupBox.Controls.Add(WorldSelectRadioNew);
+ WorldSelectGroupBox.Controls.Add(WorldSelectRadioExisting);
+ WorldSelectGroupBox.Controls.Add(WorldSelectExistingNameField);
+ WorldSelectGroupBox.Location = new System.Drawing.Point(3, 94);
+ WorldSelectGroupBox.Name = "WorldSelectGroupBox";
+ WorldSelectGroupBox.Size = new System.Drawing.Size(240, 96);
+ WorldSelectGroupBox.TabIndex = 5;
+ WorldSelectGroupBox.TabStop = false;
+ WorldSelectGroupBox.Text = "World";
//
// WorldsListRefreshButton
//
- this.WorldsListRefreshButton.HelpText = "Refresh the worlds list";
- this.WorldsListRefreshButton.Location = new System.Drawing.Point(188, 23);
- this.WorldsListRefreshButton.Name = "WorldsListRefreshButton";
- this.WorldsListRefreshButton.RefreshFunction = null;
- this.WorldsListRefreshButton.Size = new System.Drawing.Size(16, 16);
- this.WorldsListRefreshButton.TabIndex = 2;
- this.WorldsListRefreshButton.TabStop = false;
+ WorldsListRefreshButton.HelpText = "Refresh the worlds list";
+ WorldsListRefreshButton.Location = new System.Drawing.Point(188, 23);
+ WorldsListRefreshButton.Name = "WorldsListRefreshButton";
+ WorldsListRefreshButton.RefreshFunction = null;
+ WorldsListRefreshButton.Size = new System.Drawing.Size(16, 16);
+ WorldsListRefreshButton.TabIndex = 2;
+ WorldsListRefreshButton.TabStop = false;
//
// WorldsFolderOpenButton
//
- this.WorldsFolderOpenButton.HelpText = "Open the save data folder in Explorer";
- this.WorldsFolderOpenButton.Location = new System.Drawing.Point(210, 23);
- this.WorldsFolderOpenButton.Name = "WorldsFolderOpenButton";
- this.WorldsFolderOpenButton.PathFunction = null;
- this.WorldsFolderOpenButton.Size = new System.Drawing.Size(16, 16);
- this.WorldsFolderOpenButton.TabIndex = 3;
- this.WorldsFolderOpenButton.TabStop = false;
+ WorldsFolderOpenButton.HelpText = "Open the save data folder in Explorer";
+ WorldsFolderOpenButton.Location = new System.Drawing.Point(210, 23);
+ WorldsFolderOpenButton.Name = "WorldsFolderOpenButton";
+ WorldsFolderOpenButton.PathFunction = null;
+ WorldsFolderOpenButton.Size = new System.Drawing.Size(16, 16);
+ WorldsFolderOpenButton.TabIndex = 3;
+ WorldsFolderOpenButton.TabStop = false;
//
// WorldSelectNewNameField
//
- this.WorldSelectNewNameField.HelpText = "";
- this.WorldSelectNewNameField.HideValue = false;
- this.WorldSelectNewNameField.LabelText = "New World Name";
- this.WorldSelectNewNameField.Location = new System.Drawing.Point(3, 45);
- this.WorldSelectNewNameField.MaxLength = 20;
- this.WorldSelectNewNameField.Multiline = false;
- this.WorldSelectNewNameField.Name = "WorldSelectNewNameField";
- this.WorldSelectNewNameField.Size = new System.Drawing.Size(234, 41);
- this.WorldSelectNewNameField.TabIndex = 5;
- this.WorldSelectNewNameField.Value = "";
- this.WorldSelectNewNameField.Visible = false;
+ WorldSelectNewNameField.HelpText = "";
+ WorldSelectNewNameField.HideValue = false;
+ WorldSelectNewNameField.LabelText = "New World Name";
+ WorldSelectNewNameField.Location = new System.Drawing.Point(3, 45);
+ WorldSelectNewNameField.MaxLength = 20;
+ WorldSelectNewNameField.Multiline = false;
+ WorldSelectNewNameField.Name = "WorldSelectNewNameField";
+ WorldSelectNewNameField.Size = new System.Drawing.Size(234, 41);
+ WorldSelectNewNameField.TabIndex = 5;
+ WorldSelectNewNameField.Value = "";
+ WorldSelectNewNameField.Visible = false;
//
// WorldSelectRadioNew
//
- this.WorldSelectRadioNew.GroupName = "WorldSelect";
- this.WorldSelectRadioNew.HelpText = "";
- this.WorldSelectRadioNew.LabelText = "New";
- this.WorldSelectRadioNew.Location = new System.Drawing.Point(82, 23);
- this.WorldSelectRadioNew.Name = "WorldSelectRadioNew";
- this.WorldSelectRadioNew.Size = new System.Drawing.Size(65, 17);
- this.WorldSelectRadioNew.TabIndex = 1;
- this.WorldSelectRadioNew.Value = false;
+ WorldSelectRadioNew.GroupName = "WorldSelect";
+ WorldSelectRadioNew.HelpText = "";
+ WorldSelectRadioNew.LabelText = "New";
+ WorldSelectRadioNew.Location = new System.Drawing.Point(82, 23);
+ WorldSelectRadioNew.Name = "WorldSelectRadioNew";
+ WorldSelectRadioNew.Size = new System.Drawing.Size(65, 17);
+ WorldSelectRadioNew.TabIndex = 1;
+ WorldSelectRadioNew.Value = false;
//
// WorldSelectRadioExisting
//
- this.WorldSelectRadioExisting.GroupName = "WorldSelect";
- this.WorldSelectRadioExisting.HelpText = "";
- this.WorldSelectRadioExisting.LabelText = "Existing";
- this.WorldSelectRadioExisting.Location = new System.Drawing.Point(6, 22);
- this.WorldSelectRadioExisting.Name = "WorldSelectRadioExisting";
- this.WorldSelectRadioExisting.Size = new System.Drawing.Size(83, 17);
- this.WorldSelectRadioExisting.TabIndex = 0;
- this.WorldSelectRadioExisting.Value = false;
+ WorldSelectRadioExisting.GroupName = "WorldSelect";
+ WorldSelectRadioExisting.HelpText = "";
+ WorldSelectRadioExisting.LabelText = "Existing";
+ WorldSelectRadioExisting.Location = new System.Drawing.Point(6, 22);
+ WorldSelectRadioExisting.Name = "WorldSelectRadioExisting";
+ WorldSelectRadioExisting.Size = new System.Drawing.Size(83, 17);
+ WorldSelectRadioExisting.TabIndex = 0;
+ WorldSelectRadioExisting.Value = false;
//
// WorldSelectExistingNameField
//
- this.WorldSelectExistingNameField.DataSource = ((System.Collections.Generic.IEnumerable)(resources.GetObject("WorldSelectExistingNameField.DataSource")));
- this.WorldSelectExistingNameField.DropdownEnabled = true;
- this.WorldSelectExistingNameField.EmptyText = "(no worlds)";
- this.WorldSelectExistingNameField.HelpText = "";
- this.WorldSelectExistingNameField.LabelText = "Select World";
- this.WorldSelectExistingNameField.Location = new System.Drawing.Point(6, 45);
- this.WorldSelectExistingNameField.Name = "WorldSelectExistingNameField";
- this.WorldSelectExistingNameField.Size = new System.Drawing.Size(234, 41);
- this.WorldSelectExistingNameField.TabIndex = 4;
- this.WorldSelectExistingNameField.Value = null;
- this.WorldSelectExistingNameField.Visible = false;
+ WorldSelectExistingNameField.DataSource = (System.Collections.Generic.IEnumerable)resources.GetObject("WorldSelectExistingNameField.DataSource");
+ WorldSelectExistingNameField.DropdownEnabled = true;
+ WorldSelectExistingNameField.EmptyText = "(no worlds)";
+ WorldSelectExistingNameField.HelpText = "";
+ WorldSelectExistingNameField.LabelText = "Select World";
+ WorldSelectExistingNameField.Location = new System.Drawing.Point(6, 45);
+ WorldSelectExistingNameField.Name = "WorldSelectExistingNameField";
+ WorldSelectExistingNameField.Size = new System.Drawing.Size(234, 41);
+ WorldSelectExistingNameField.TabIndex = 4;
+ WorldSelectExistingNameField.Value = null;
+ WorldSelectExistingNameField.Visible = false;
//
// ServerPortField
//
- this.ServerPortField.HelpText = "";
- this.ServerPortField.LabelText = "Port";
- this.ServerPortField.Location = new System.Drawing.Point(236, 0);
- this.ServerPortField.Maximum = 65535;
- this.ServerPortField.Minimum = 1;
- this.ServerPortField.Name = "ServerPortField";
- this.ServerPortField.Size = new System.Drawing.Size(75, 41);
- this.ServerPortField.TabIndex = 1;
- this.ServerPortField.Value = 1;
+ ServerPortField.HelpText = "";
+ ServerPortField.LabelText = "Port";
+ ServerPortField.Location = new System.Drawing.Point(236, 0);
+ ServerPortField.Maximum = 65535;
+ ServerPortField.Minimum = 1;
+ ServerPortField.Name = "ServerPortField";
+ ServerPortField.Size = new System.Drawing.Size(75, 41);
+ ServerPortField.TabIndex = 1;
+ ServerPortField.Value = 1;
//
// ButtonRestartServer
//
- this.ButtonRestartServer.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.ButtonRestartServer.Image = global::ValheimServerGUI.Properties.Resources.Restart_16x;
- this.ButtonRestartServer.Location = new System.Drawing.Point(115, 226);
- this.ButtonRestartServer.Name = "ButtonRestartServer";
- this.ButtonRestartServer.Size = new System.Drawing.Size(106, 23);
- this.ButtonRestartServer.TabIndex = 8;
- this.ButtonRestartServer.Text = "Restart Server";
- this.ButtonRestartServer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- this.ButtonRestartServer.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
- this.ButtonRestartServer.UseVisualStyleBackColor = true;
+ ButtonRestartServer.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
+ ButtonRestartServer.Image = Properties.Resources.Restart_16x;
+ ButtonRestartServer.Location = new System.Drawing.Point(115, 226);
+ ButtonRestartServer.Name = "ButtonRestartServer";
+ ButtonRestartServer.Size = new System.Drawing.Size(106, 23);
+ ButtonRestartServer.TabIndex = 8;
+ ButtonRestartServer.Text = "Restart Server";
+ ButtonRestartServer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ ButtonRestartServer.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
+ ButtonRestartServer.UseVisualStyleBackColor = true;
//
// ShowPasswordField
//
- this.ShowPasswordField.HelpText = "";
- this.ShowPasswordField.LabelText = "Show Password";
- this.ShowPasswordField.Location = new System.Drawing.Point(255, 68);
- this.ShowPasswordField.Name = "ShowPasswordField";
- this.ShowPasswordField.Size = new System.Drawing.Size(150, 17);
- this.ShowPasswordField.TabIndex = 4;
- this.ShowPasswordField.Value = false;
+ ShowPasswordField.HelpText = "";
+ ShowPasswordField.LabelText = "Show Password";
+ ShowPasswordField.Location = new System.Drawing.Point(255, 68);
+ ShowPasswordField.Name = "ShowPasswordField";
+ ShowPasswordField.Size = new System.Drawing.Size(150, 17);
+ ShowPasswordField.TabIndex = 4;
+ ShowPasswordField.Value = false;
//
// ServerPasswordField
//
- this.ServerPasswordField.HelpText = "Your server must be protected with a password. The password must be at least 5 ch" +
- "aracters \r\nand must not contain the name of the server or the world that you\'re " +
- "hosting.";
- this.ServerPasswordField.HideValue = true;
- this.ServerPasswordField.LabelText = "Server Password";
- this.ServerPasswordField.Location = new System.Drawing.Point(0, 47);
- this.ServerPasswordField.MaxLength = 64;
- this.ServerPasswordField.Multiline = false;
- this.ServerPasswordField.Name = "ServerPasswordField";
- this.ServerPasswordField.Size = new System.Drawing.Size(243, 41);
- this.ServerPasswordField.TabIndex = 2;
- this.ServerPasswordField.Value = "";
+ ServerPasswordField.HelpText = "Your server must be protected with a password. The password must be at least 5 characters \r\nand must not contain the name of the server or the world that you're hosting.";
+ ServerPasswordField.HideValue = true;
+ ServerPasswordField.LabelText = "Server Password";
+ ServerPasswordField.Location = new System.Drawing.Point(0, 47);
+ ServerPasswordField.MaxLength = 64;
+ ServerPasswordField.Multiline = false;
+ ServerPasswordField.Name = "ServerPasswordField";
+ ServerPasswordField.Size = new System.Drawing.Size(243, 41);
+ ServerPasswordField.TabIndex = 2;
+ ServerPasswordField.Value = "";
//
// ServerNameField
//
- this.ServerNameField.HelpText = "This is the name that will appear in the Community Servers list within Valheim.";
- this.ServerNameField.HideValue = false;
- this.ServerNameField.LabelText = "Server Name";
- this.ServerNameField.Location = new System.Drawing.Point(0, 0);
- this.ServerNameField.MaxLength = 64;
- this.ServerNameField.Multiline = false;
- this.ServerNameField.Name = "ServerNameField";
- this.ServerNameField.Size = new System.Drawing.Size(243, 41);
- this.ServerNameField.TabIndex = 0;
- this.ServerNameField.Value = "";
+ ServerNameField.HelpText = "This is the name that will appear in the Community Servers list within Valheim.";
+ ServerNameField.HideValue = false;
+ ServerNameField.LabelText = "Server Name";
+ ServerNameField.Location = new System.Drawing.Point(0, 0);
+ ServerNameField.MaxLength = 64;
+ ServerNameField.Multiline = false;
+ ServerNameField.Name = "ServerNameField";
+ ServerNameField.Size = new System.Drawing.Size(243, 41);
+ ServerNameField.TabIndex = 0;
+ ServerNameField.Value = "";
//
// ButtonStopServer
//
- this.ButtonStopServer.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.ButtonStopServer.Image = global::ValheimServerGUI.Properties.Resources.Stop_16x;
- this.ButtonStopServer.Location = new System.Drawing.Point(227, 226);
- this.ButtonStopServer.Name = "ButtonStopServer";
- this.ButtonStopServer.Size = new System.Drawing.Size(106, 23);
- this.ButtonStopServer.TabIndex = 9;
- this.ButtonStopServer.Text = "Stop Server";
- this.ButtonStopServer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- this.ButtonStopServer.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
- this.ButtonStopServer.UseVisualStyleBackColor = true;
+ ButtonStopServer.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
+ ButtonStopServer.Image = Properties.Resources.Stop_16x;
+ ButtonStopServer.Location = new System.Drawing.Point(227, 226);
+ ButtonStopServer.Name = "ButtonStopServer";
+ ButtonStopServer.Size = new System.Drawing.Size(106, 23);
+ ButtonStopServer.TabIndex = 9;
+ ButtonStopServer.Text = "Stop Server";
+ ButtonStopServer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ ButtonStopServer.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
+ ButtonStopServer.UseVisualStyleBackColor = true;
//
// ButtonStartServer
//
- this.ButtonStartServer.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.ButtonStartServer.Image = global::ValheimServerGUI.Properties.Resources.Run_16x;
- this.ButtonStartServer.Location = new System.Drawing.Point(3, 226);
- this.ButtonStartServer.Name = "ButtonStartServer";
- this.ButtonStartServer.Size = new System.Drawing.Size(106, 23);
- this.ButtonStartServer.TabIndex = 7;
- this.ButtonStartServer.Text = "Start Server";
- this.ButtonStartServer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- this.ButtonStartServer.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
- this.ButtonStartServer.UseVisualStyleBackColor = true;
+ ButtonStartServer.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
+ ButtonStartServer.Image = Properties.Resources.Run_16x;
+ ButtonStartServer.Location = new System.Drawing.Point(3, 226);
+ ButtonStartServer.Name = "ButtonStartServer";
+ ButtonStartServer.Size = new System.Drawing.Size(106, 23);
+ ButtonStartServer.TabIndex = 7;
+ ButtonStartServer.Text = "Start Server";
+ ButtonStartServer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ ButtonStartServer.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
+ ButtonStartServer.UseVisualStyleBackColor = true;
//
// TabAdvancedControls
//
- this.TabAdvancedControls.Controls.Add(this.SavingGroupBox);
- this.TabAdvancedControls.Controls.Add(this.StartupGroupBox);
- this.TabAdvancedControls.Controls.Add(this.DirectoriesGroupBox);
- this.TabAdvancedControls.Location = new System.Drawing.Point(4, 24);
- this.TabAdvancedControls.Name = "TabAdvancedControls";
- this.TabAdvancedControls.Padding = new System.Windows.Forms.Padding(3);
- this.TabAdvancedControls.Size = new System.Drawing.Size(452, 252);
- this.TabAdvancedControls.TabIndex = 5;
- this.TabAdvancedControls.Text = "Advanced Controls";
- this.TabAdvancedControls.UseVisualStyleBackColor = true;
+ TabAdvancedControls.Controls.Add(SavingGroupBox);
+ TabAdvancedControls.Controls.Add(OtherSettingsGroupBox);
+ TabAdvancedControls.Controls.Add(DirectoriesGroupBox);
+ TabAdvancedControls.Location = new System.Drawing.Point(4, 24);
+ TabAdvancedControls.Name = "TabAdvancedControls";
+ TabAdvancedControls.Padding = new System.Windows.Forms.Padding(3);
+ TabAdvancedControls.Size = new System.Drawing.Size(452, 252);
+ TabAdvancedControls.TabIndex = 5;
+ TabAdvancedControls.Text = "Advanced Controls";
+ TabAdvancedControls.UseVisualStyleBackColor = true;
//
// SavingGroupBox
//
- this.SavingGroupBox.Controls.Add(this.ServerLongBackupIntervalField);
- this.SavingGroupBox.Controls.Add(this.ServerSaveIntervalField);
- this.SavingGroupBox.Controls.Add(this.ServerShortBackupIntervalField);
- this.SavingGroupBox.Controls.Add(this.ServerBackupsField);
- this.SavingGroupBox.Location = new System.Drawing.Point(319, 6);
- this.SavingGroupBox.Name = "SavingGroupBox";
- this.SavingGroupBox.Size = new System.Drawing.Size(127, 240);
- this.SavingGroupBox.TabIndex = 2;
- this.SavingGroupBox.TabStop = false;
- this.SavingGroupBox.Text = "Saving && Backups";
+ SavingGroupBox.Controls.Add(ServerLongBackupIntervalField);
+ SavingGroupBox.Controls.Add(ServerSaveIntervalField);
+ SavingGroupBox.Controls.Add(ServerShortBackupIntervalField);
+ SavingGroupBox.Controls.Add(ServerBackupsField);
+ SavingGroupBox.Location = new System.Drawing.Point(319, 6);
+ SavingGroupBox.Name = "SavingGroupBox";
+ SavingGroupBox.Size = new System.Drawing.Size(127, 240);
+ SavingGroupBox.TabIndex = 2;
+ SavingGroupBox.TabStop = false;
+ SavingGroupBox.Text = "Saving && Backups";
//
// ServerLongBackupIntervalField
//
- this.ServerLongBackupIntervalField.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerLongBackupIntervalField.HelpText = "How often to create additional backups of the world\r\nsave data, in seconds. This " +
- "interval must be longer than\r\nthe short backup interval.";
- this.ServerLongBackupIntervalField.LabelText = "Long Backup";
- this.ServerLongBackupIntervalField.Location = new System.Drawing.Point(6, 163);
- this.ServerLongBackupIntervalField.Maximum = 2592000;
- this.ServerLongBackupIntervalField.Minimum = 300;
- this.ServerLongBackupIntervalField.Name = "ServerLongBackupIntervalField";
- this.ServerLongBackupIntervalField.Size = new System.Drawing.Size(115, 41);
- this.ServerLongBackupIntervalField.TabIndex = 3;
- this.ServerLongBackupIntervalField.Value = 300;
+ ServerLongBackupIntervalField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ServerLongBackupIntervalField.HelpText = "How often to create additional backups of the world\r\nsave data, in seconds. This interval must be longer than\r\nthe short backup interval.";
+ ServerLongBackupIntervalField.LabelText = "Long Backup";
+ ServerLongBackupIntervalField.Location = new System.Drawing.Point(6, 163);
+ ServerLongBackupIntervalField.Maximum = 2592000;
+ ServerLongBackupIntervalField.Minimum = 300;
+ ServerLongBackupIntervalField.Name = "ServerLongBackupIntervalField";
+ ServerLongBackupIntervalField.Size = new System.Drawing.Size(115, 41);
+ ServerLongBackupIntervalField.TabIndex = 3;
+ ServerLongBackupIntervalField.Value = 300;
//
// ServerSaveIntervalField
//
- this.ServerSaveIntervalField.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerSaveIntervalField.HelpText = "How often the world is saved, in seconds.";
- this.ServerSaveIntervalField.LabelText = "Save Interval";
- this.ServerSaveIntervalField.Location = new System.Drawing.Point(6, 22);
- this.ServerSaveIntervalField.Maximum = 86400;
- this.ServerSaveIntervalField.Minimum = 60;
- this.ServerSaveIntervalField.Name = "ServerSaveIntervalField";
- this.ServerSaveIntervalField.Size = new System.Drawing.Size(115, 41);
- this.ServerSaveIntervalField.TabIndex = 0;
- this.ServerSaveIntervalField.Value = 60;
+ ServerSaveIntervalField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ServerSaveIntervalField.HelpText = "How often the world is saved, in seconds.";
+ ServerSaveIntervalField.LabelText = "Save Interval";
+ ServerSaveIntervalField.Location = new System.Drawing.Point(6, 22);
+ ServerSaveIntervalField.Maximum = 86400;
+ ServerSaveIntervalField.Minimum = 60;
+ ServerSaveIntervalField.Name = "ServerSaveIntervalField";
+ ServerSaveIntervalField.Size = new System.Drawing.Size(115, 41);
+ ServerSaveIntervalField.TabIndex = 0;
+ ServerSaveIntervalField.Value = 60;
//
// ServerShortBackupIntervalField
//
- this.ServerShortBackupIntervalField.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerShortBackupIntervalField.HelpText = "How often to create a rolling backup of the world\r\nsave data, in seconds.";
- this.ServerShortBackupIntervalField.LabelText = "Short Backup";
- this.ServerShortBackupIntervalField.Location = new System.Drawing.Point(6, 116);
- this.ServerShortBackupIntervalField.Maximum = 2592000;
- this.ServerShortBackupIntervalField.Minimum = 300;
- this.ServerShortBackupIntervalField.Name = "ServerShortBackupIntervalField";
- this.ServerShortBackupIntervalField.Size = new System.Drawing.Size(115, 41);
- this.ServerShortBackupIntervalField.TabIndex = 2;
- this.ServerShortBackupIntervalField.Value = 300;
+ ServerShortBackupIntervalField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ServerShortBackupIntervalField.HelpText = "How often to create a rolling backup of the world\r\nsave data, in seconds.";
+ ServerShortBackupIntervalField.LabelText = "Short Backup";
+ ServerShortBackupIntervalField.Location = new System.Drawing.Point(6, 116);
+ ServerShortBackupIntervalField.Maximum = 2592000;
+ ServerShortBackupIntervalField.Minimum = 300;
+ ServerShortBackupIntervalField.Name = "ServerShortBackupIntervalField";
+ ServerShortBackupIntervalField.Size = new System.Drawing.Size(115, 41);
+ ServerShortBackupIntervalField.TabIndex = 2;
+ ServerShortBackupIntervalField.Value = 300;
//
// ServerBackupsField
//
- this.ServerBackupsField.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerBackupsField.HelpText = "Number of world data backups to maintain. One rolling backup\r\nis created on the s" +
- "hort backup interval, and subsequent backups are\r\ncreated on the long backup int" +
- "erval.";
- this.ServerBackupsField.LabelText = "Backups";
- this.ServerBackupsField.Location = new System.Drawing.Point(6, 69);
- this.ServerBackupsField.Maximum = 1000;
- this.ServerBackupsField.Minimum = 1;
- this.ServerBackupsField.Name = "ServerBackupsField";
- this.ServerBackupsField.Size = new System.Drawing.Size(115, 41);
- this.ServerBackupsField.TabIndex = 1;
- this.ServerBackupsField.Value = 1;
- //
- // StartupGroupBox
- //
- this.StartupGroupBox.Controls.Add(this.ServerAutoStartField);
- this.StartupGroupBox.Controls.Add(this.ServerAdditionalArgsField);
- this.StartupGroupBox.Location = new System.Drawing.Point(6, 141);
- this.StartupGroupBox.Name = "StartupGroupBox";
- this.StartupGroupBox.Size = new System.Drawing.Size(307, 105);
- this.StartupGroupBox.TabIndex = 1;
- this.StartupGroupBox.TabStop = false;
- this.StartupGroupBox.Text = "Startup";
+ ServerBackupsField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ServerBackupsField.HelpText = "Number of world data backups to maintain. One rolling backup\r\nis created on the short backup interval, and subsequent backups are\r\ncreated on the long backup interval.";
+ ServerBackupsField.LabelText = "Backups";
+ ServerBackupsField.Location = new System.Drawing.Point(6, 69);
+ ServerBackupsField.Maximum = 1000;
+ ServerBackupsField.Minimum = 1;
+ ServerBackupsField.Name = "ServerBackupsField";
+ ServerBackupsField.Size = new System.Drawing.Size(115, 41);
+ ServerBackupsField.TabIndex = 1;
+ ServerBackupsField.Value = 1;
+ //
+ // OtherSettingsGroupBox
+ //
+ OtherSettingsGroupBox.Controls.Add(ServerLogFileField);
+ OtherSettingsGroupBox.Controls.Add(ServerAutoStartField);
+ OtherSettingsGroupBox.Controls.Add(ServerAdditionalArgsField);
+ OtherSettingsGroupBox.Location = new System.Drawing.Point(6, 131);
+ OtherSettingsGroupBox.Name = "OtherSettingsGroupBox";
+ OtherSettingsGroupBox.Size = new System.Drawing.Size(307, 115);
+ OtherSettingsGroupBox.TabIndex = 1;
+ OtherSettingsGroupBox.TabStop = false;
+ OtherSettingsGroupBox.Text = "Other Settings";
+ //
+ // ServerLogFileField
+ //
+ ServerLogFileField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ServerLogFileField.HelpText = "If enabled, this server's logs will be written to a daily rolling\r\nlog file on disk. Logs older than 30 days will be deleted\r\nautomatically.\r\n";
+ ServerLogFileField.LabelText = "Write server logs to file";
+ ServerLogFileField.Location = new System.Drawing.Point(6, 45);
+ ServerLogFileField.Name = "ServerLogFileField";
+ ServerLogFileField.Size = new System.Drawing.Size(286, 17);
+ ServerLogFileField.TabIndex = 1;
+ ServerLogFileField.Value = false;
//
// ServerAutoStartField
//
- this.ServerAutoStartField.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerAutoStartField.HelpText = resources.GetString("ServerAutoStartField.HelpText");
- this.ServerAutoStartField.LabelText = "Start this server when ValheimServerGUI starts";
- this.ServerAutoStartField.Location = new System.Drawing.Point(6, 22);
- this.ServerAutoStartField.Name = "ServerAutoStartField";
- this.ServerAutoStartField.Size = new System.Drawing.Size(286, 17);
- this.ServerAutoStartField.TabIndex = 0;
- this.ServerAutoStartField.Value = false;
+ ServerAutoStartField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ServerAutoStartField.HelpText = resources.GetString("ServerAutoStartField.HelpText");
+ ServerAutoStartField.LabelText = "Start this server when ValheimServerGUI starts";
+ ServerAutoStartField.Location = new System.Drawing.Point(6, 22);
+ ServerAutoStartField.Name = "ServerAutoStartField";
+ ServerAutoStartField.Size = new System.Drawing.Size(286, 17);
+ ServerAutoStartField.TabIndex = 0;
+ ServerAutoStartField.Value = false;
//
// ServerAdditionalArgsField
//
- this.ServerAdditionalArgsField.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerAdditionalArgsField.HelpText = "Add any additional args you want to pass to the server run\r\ncommand here. These w" +
- "ill be appended to the end of the\r\ncommand generated by ValheimServerGUI.";
- this.ServerAdditionalArgsField.HideValue = false;
- this.ServerAdditionalArgsField.LabelText = "Additional Command Line Args";
- this.ServerAdditionalArgsField.Location = new System.Drawing.Point(6, 45);
- this.ServerAdditionalArgsField.MaxLength = 32767;
- this.ServerAdditionalArgsField.Multiline = false;
- this.ServerAdditionalArgsField.Name = "ServerAdditionalArgsField";
- this.ServerAdditionalArgsField.Size = new System.Drawing.Size(295, 41);
- this.ServerAdditionalArgsField.TabIndex = 1;
- this.ServerAdditionalArgsField.Value = "";
+ ServerAdditionalArgsField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ServerAdditionalArgsField.HelpText = "Add any additional args you want to pass to the server run\r\ncommand here. These will be appended to the end of the\r\ncommand generated by ValheimServerGUI.";
+ ServerAdditionalArgsField.HideValue = false;
+ ServerAdditionalArgsField.LabelText = "Additional Command Line Args";
+ ServerAdditionalArgsField.Location = new System.Drawing.Point(6, 68);
+ ServerAdditionalArgsField.MaxLength = 32767;
+ ServerAdditionalArgsField.Multiline = false;
+ ServerAdditionalArgsField.Name = "ServerAdditionalArgsField";
+ ServerAdditionalArgsField.Size = new System.Drawing.Size(295, 41);
+ ServerAdditionalArgsField.TabIndex = 2;
+ ServerAdditionalArgsField.Value = "";
//
// DirectoriesGroupBox
//
- this.DirectoriesGroupBox.Controls.Add(this.ServerSaveDataPathOpenButton);
- this.DirectoriesGroupBox.Controls.Add(this.ServerExePathOpenButton);
- this.DirectoriesGroupBox.Controls.Add(this.ServerSaveDataFolderPathField);
- this.DirectoriesGroupBox.Controls.Add(this.ServerExePathField);
- this.DirectoriesGroupBox.Location = new System.Drawing.Point(6, 6);
- this.DirectoriesGroupBox.Name = "DirectoriesGroupBox";
- this.DirectoriesGroupBox.Size = new System.Drawing.Size(307, 129);
- this.DirectoriesGroupBox.TabIndex = 0;
- this.DirectoriesGroupBox.TabStop = false;
- this.DirectoriesGroupBox.Text = "Directory Overrides (for just this Profile)";
+ DirectoriesGroupBox.Controls.Add(ServerSaveDataPathOpenButton);
+ DirectoriesGroupBox.Controls.Add(ServerExePathOpenButton);
+ DirectoriesGroupBox.Controls.Add(ServerSaveDataFolderPathField);
+ DirectoriesGroupBox.Controls.Add(ServerExePathField);
+ DirectoriesGroupBox.Location = new System.Drawing.Point(6, 6);
+ DirectoriesGroupBox.Name = "DirectoriesGroupBox";
+ DirectoriesGroupBox.Size = new System.Drawing.Size(307, 119);
+ DirectoriesGroupBox.TabIndex = 0;
+ DirectoriesGroupBox.TabStop = false;
+ DirectoriesGroupBox.Text = "Directory Overrides (for just this Profile)";
//
// ServerSaveDataPathOpenButton
//
- this.ServerSaveDataPathOpenButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerSaveDataPathOpenButton.HelpText = "Open this folder in Explorer";
- this.ServerSaveDataPathOpenButton.Location = new System.Drawing.Point(285, 90);
- this.ServerSaveDataPathOpenButton.Name = "ServerSaveDataPathOpenButton";
- this.ServerSaveDataPathOpenButton.PathFunction = null;
- this.ServerSaveDataPathOpenButton.Size = new System.Drawing.Size(16, 16);
- this.ServerSaveDataPathOpenButton.TabIndex = 3;
- this.ServerSaveDataPathOpenButton.TabStop = false;
+ ServerSaveDataPathOpenButton.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
+ ServerSaveDataPathOpenButton.HelpText = "Open this folder in Explorer";
+ ServerSaveDataPathOpenButton.Location = new System.Drawing.Point(285, 90);
+ ServerSaveDataPathOpenButton.Name = "ServerSaveDataPathOpenButton";
+ ServerSaveDataPathOpenButton.PathFunction = null;
+ ServerSaveDataPathOpenButton.Size = new System.Drawing.Size(16, 16);
+ ServerSaveDataPathOpenButton.TabIndex = 3;
+ ServerSaveDataPathOpenButton.TabStop = false;
//
// ServerExePathOpenButton
//
- this.ServerExePathOpenButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerExePathOpenButton.HelpText = "Open this folder in Explorer";
- this.ServerExePathOpenButton.Location = new System.Drawing.Point(285, 43);
- this.ServerExePathOpenButton.Name = "ServerExePathOpenButton";
- this.ServerExePathOpenButton.PathFunction = null;
- this.ServerExePathOpenButton.Size = new System.Drawing.Size(16, 16);
- this.ServerExePathOpenButton.TabIndex = 1;
- this.ServerExePathOpenButton.TabStop = false;
+ ServerExePathOpenButton.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
+ ServerExePathOpenButton.HelpText = "Open this folder in Explorer";
+ ServerExePathOpenButton.Location = new System.Drawing.Point(285, 43);
+ ServerExePathOpenButton.Name = "ServerExePathOpenButton";
+ ServerExePathOpenButton.PathFunction = null;
+ ServerExePathOpenButton.Size = new System.Drawing.Size(16, 16);
+ ServerExePathOpenButton.TabIndex = 1;
+ ServerExePathOpenButton.TabStop = false;
//
// ServerSaveDataFolderPathField
//
- this.ServerSaveDataFolderPathField.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerSaveDataFolderPathField.FileSelectMode = ValheimServerGUI.Controls.FileSelectMode.Directory;
- this.ServerSaveDataFolderPathField.HelpText = resources.GetString("ServerSaveDataFolderPathField.HelpText");
- this.ServerSaveDataFolderPathField.InitialPath = null;
- this.ServerSaveDataFolderPathField.LabelText = "Valheim Save Data Folder";
- this.ServerSaveDataFolderPathField.Location = new System.Drawing.Point(6, 69);
- this.ServerSaveDataFolderPathField.MultiFileSeparator = "; ";
- this.ServerSaveDataFolderPathField.Name = "ServerSaveDataFolderPathField";
- this.ServerSaveDataFolderPathField.ReadOnly = false;
- this.ServerSaveDataFolderPathField.Size = new System.Drawing.Size(286, 41);
- this.ServerSaveDataFolderPathField.TabIndex = 2;
- this.ServerSaveDataFolderPathField.Value = "";
+ ServerSaveDataFolderPathField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ServerSaveDataFolderPathField.FileSelectMode = ValheimServerGUI.Controls.FileSelectMode.Directory;
+ ServerSaveDataFolderPathField.HelpText = resources.GetString("ServerSaveDataFolderPathField.HelpText");
+ ServerSaveDataFolderPathField.InitialPath = null;
+ ServerSaveDataFolderPathField.LabelText = "Valheim Save Data Folder";
+ ServerSaveDataFolderPathField.Location = new System.Drawing.Point(6, 69);
+ ServerSaveDataFolderPathField.MultiFileSeparator = "; ";
+ ServerSaveDataFolderPathField.Name = "ServerSaveDataFolderPathField";
+ ServerSaveDataFolderPathField.ReadOnly = false;
+ ServerSaveDataFolderPathField.Size = new System.Drawing.Size(286, 41);
+ ServerSaveDataFolderPathField.TabIndex = 2;
+ ServerSaveDataFolderPathField.Value = "";
//
// ServerExePathField
//
- this.ServerExePathField.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.ServerExePathField.FileSelectMode = ValheimServerGUI.Controls.FileSelectMode.SingleFile;
- this.ServerExePathField.HelpText = resources.GetString("ServerExePathField.HelpText");
- this.ServerExePathField.InitialPath = null;
- this.ServerExePathField.LabelText = "Valheim Dedicated Server .exe";
- this.ServerExePathField.Location = new System.Drawing.Point(6, 22);
- this.ServerExePathField.MultiFileSeparator = "; ";
- this.ServerExePathField.Name = "ServerExePathField";
- this.ServerExePathField.ReadOnly = false;
- this.ServerExePathField.Size = new System.Drawing.Size(286, 41);
- this.ServerExePathField.TabIndex = 0;
- this.ServerExePathField.Value = "";
+ ServerExePathField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ ServerExePathField.FileSelectMode = ValheimServerGUI.Controls.FileSelectMode.SingleFile;
+ ServerExePathField.HelpText = resources.GetString("ServerExePathField.HelpText");
+ ServerExePathField.InitialPath = null;
+ ServerExePathField.LabelText = "Valheim Dedicated Server .exe";
+ ServerExePathField.Location = new System.Drawing.Point(6, 22);
+ ServerExePathField.MultiFileSeparator = "; ";
+ ServerExePathField.Name = "ServerExePathField";
+ ServerExePathField.ReadOnly = false;
+ ServerExePathField.Size = new System.Drawing.Size(286, 41);
+ ServerExePathField.TabIndex = 0;
+ ServerExePathField.Value = "";
//
// TabServerDetails
//
- this.TabServerDetails.Controls.Add(this.groupBox2);
- this.TabServerDetails.Controls.Add(this.groupBox1);
- this.TabServerDetails.Location = new System.Drawing.Point(4, 24);
- this.TabServerDetails.Name = "TabServerDetails";
- this.TabServerDetails.Size = new System.Drawing.Size(452, 252);
- this.TabServerDetails.TabIndex = 4;
- this.TabServerDetails.Text = "Server Details";
- this.TabServerDetails.UseVisualStyleBackColor = true;
+ TabServerDetails.Controls.Add(groupBox2);
+ TabServerDetails.Controls.Add(groupBox1);
+ TabServerDetails.Location = new System.Drawing.Point(4, 24);
+ TabServerDetails.Name = "TabServerDetails";
+ TabServerDetails.Size = new System.Drawing.Size(452, 252);
+ TabServerDetails.TabIndex = 4;
+ TabServerDetails.Text = "Server Details";
+ TabServerDetails.UseVisualStyleBackColor = true;
//
// groupBox2
//
- this.groupBox2.Controls.Add(this.LabelSessionDuration);
- this.groupBox2.Controls.Add(this.LabelAverageWorldSave);
- this.groupBox2.Controls.Add(this.LabelLastWorldSave);
- this.groupBox2.Location = new System.Drawing.Point(3, 143);
- this.groupBox2.Name = "groupBox2";
- this.groupBox2.Size = new System.Drawing.Size(307, 100);
- this.groupBox2.TabIndex = 1;
- this.groupBox2.TabStop = false;
- this.groupBox2.Text = "Statistics";
+ groupBox2.Controls.Add(LabelSessionDuration);
+ groupBox2.Controls.Add(LabelAverageWorldSave);
+ groupBox2.Controls.Add(LabelLastWorldSave);
+ groupBox2.Location = new System.Drawing.Point(3, 143);
+ groupBox2.Name = "groupBox2";
+ groupBox2.Size = new System.Drawing.Size(307, 100);
+ groupBox2.TabIndex = 1;
+ groupBox2.TabStop = false;
+ groupBox2.Text = "Statistics";
//
// LabelSessionDuration
//
- this.LabelSessionDuration.HelpText = "";
- this.LabelSessionDuration.LabelSplitRatio = 0.5D;
- this.LabelSessionDuration.LabelText = "Server Uptime:";
- this.LabelSessionDuration.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.LabelSessionDuration.Location = new System.Drawing.Point(7, 23);
- this.LabelSessionDuration.Name = "LabelSessionDuration";
- this.LabelSessionDuration.Size = new System.Drawing.Size(241, 15);
- this.LabelSessionDuration.TabIndex = 0;
- this.LabelSessionDuration.TabStop = false;
- this.LabelSessionDuration.Value = "";
- this.LabelSessionDuration.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ LabelSessionDuration.HelpText = "";
+ LabelSessionDuration.LabelSplitRatio = 0.5D;
+ LabelSessionDuration.LabelText = "Server Uptime:";
+ LabelSessionDuration.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ LabelSessionDuration.Location = new System.Drawing.Point(7, 23);
+ LabelSessionDuration.Name = "LabelSessionDuration";
+ LabelSessionDuration.Size = new System.Drawing.Size(241, 15);
+ LabelSessionDuration.TabIndex = 0;
+ LabelSessionDuration.TabStop = false;
+ LabelSessionDuration.Value = "";
+ LabelSessionDuration.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// LabelAverageWorldSave
//
- this.LabelAverageWorldSave.HelpText = "The average amount of time it has taken to save\r\nyour game world, over the past 1" +
- "0 saves.";
- this.LabelAverageWorldSave.LabelSplitRatio = 0.455D;
- this.LabelAverageWorldSave.LabelText = "Avg. World Save:";
- this.LabelAverageWorldSave.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.LabelAverageWorldSave.Location = new System.Drawing.Point(6, 65);
- this.LabelAverageWorldSave.Name = "LabelAverageWorldSave";
- this.LabelAverageWorldSave.Size = new System.Drawing.Size(264, 15);
- this.LabelAverageWorldSave.TabIndex = 2;
- this.LabelAverageWorldSave.TabStop = false;
- this.LabelAverageWorldSave.Value = "";
- this.LabelAverageWorldSave.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ LabelAverageWorldSave.HelpText = "The average amount of time it has taken to save\r\nyour game world, over the past 10 saves.";
+ LabelAverageWorldSave.LabelSplitRatio = 0.455D;
+ LabelAverageWorldSave.LabelText = "Avg. World Save:";
+ LabelAverageWorldSave.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ LabelAverageWorldSave.Location = new System.Drawing.Point(6, 65);
+ LabelAverageWorldSave.Name = "LabelAverageWorldSave";
+ LabelAverageWorldSave.Size = new System.Drawing.Size(264, 15);
+ LabelAverageWorldSave.TabIndex = 2;
+ LabelAverageWorldSave.TabStop = false;
+ LabelAverageWorldSave.Value = "";
+ LabelAverageWorldSave.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// LabelLastWorldSave
//
- this.LabelLastWorldSave.HelpText = "";
- this.LabelLastWorldSave.LabelSplitRatio = 0.405D;
- this.LabelLastWorldSave.LabelText = "Last World Save:";
- this.LabelLastWorldSave.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.LabelLastWorldSave.Location = new System.Drawing.Point(6, 44);
- this.LabelLastWorldSave.Name = "LabelLastWorldSave";
- this.LabelLastWorldSave.Size = new System.Drawing.Size(295, 15);
- this.LabelLastWorldSave.TabIndex = 1;
- this.LabelLastWorldSave.TabStop = false;
- this.LabelLastWorldSave.Value = "";
- this.LabelLastWorldSave.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ LabelLastWorldSave.HelpText = "";
+ LabelLastWorldSave.LabelSplitRatio = 0.405D;
+ LabelLastWorldSave.LabelText = "Last World Save:";
+ LabelLastWorldSave.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ LabelLastWorldSave.Location = new System.Drawing.Point(6, 44);
+ LabelLastWorldSave.Name = "LabelLastWorldSave";
+ LabelLastWorldSave.Size = new System.Drawing.Size(295, 15);
+ LabelLastWorldSave.TabIndex = 1;
+ LabelLastWorldSave.TabStop = false;
+ LabelLastWorldSave.Value = "";
+ LabelLastWorldSave.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// groupBox1
//
- this.groupBox1.Controls.Add(this.CopyButtonInviteCode);
- this.groupBox1.Controls.Add(this.LabelInviteCode);
- this.groupBox1.Controls.Add(this.CopyButtonLocalIpAddress);
- this.groupBox1.Controls.Add(this.CopyButtonExternalIpAddress);
- this.groupBox1.Controls.Add(this.CopyButtonInternalIpAddress);
- this.groupBox1.Controls.Add(this.label1);
- this.groupBox1.Controls.Add(this.LabelExternalIpAddress);
- this.groupBox1.Controls.Add(this.LabelLocalIpAddress);
- this.groupBox1.Controls.Add(this.LabelInternalIpAddress);
- this.groupBox1.Location = new System.Drawing.Point(3, 3);
- this.groupBox1.Name = "groupBox1";
- this.groupBox1.Size = new System.Drawing.Size(307, 134);
- this.groupBox1.TabIndex = 0;
- this.groupBox1.TabStop = false;
- this.groupBox1.Text = "Connection Details";
+ groupBox1.Controls.Add(CopyButtonInviteCode);
+ groupBox1.Controls.Add(LabelInviteCode);
+ groupBox1.Controls.Add(CopyButtonLocalIpAddress);
+ groupBox1.Controls.Add(CopyButtonExternalIpAddress);
+ groupBox1.Controls.Add(CopyButtonInternalIpAddress);
+ groupBox1.Controls.Add(label1);
+ groupBox1.Controls.Add(LabelExternalIpAddress);
+ groupBox1.Controls.Add(LabelLocalIpAddress);
+ groupBox1.Controls.Add(LabelInternalIpAddress);
+ groupBox1.Location = new System.Drawing.Point(3, 3);
+ groupBox1.Name = "groupBox1";
+ groupBox1.Size = new System.Drawing.Size(307, 134);
+ groupBox1.TabIndex = 0;
+ groupBox1.TabStop = false;
+ groupBox1.Text = "Connection Details";
//
// CopyButtonInviteCode
//
- this.CopyButtonInviteCode.CopyFunction = null;
- this.CopyButtonInviteCode.HelpText = "Copy invite code to clipboard";
- this.CopyButtonInviteCode.Location = new System.Drawing.Point(276, 85);
- this.CopyButtonInviteCode.Name = "CopyButtonInviteCode";
- this.CopyButtonInviteCode.Size = new System.Drawing.Size(16, 16);
- this.CopyButtonInviteCode.TabIndex = 7;
- this.CopyButtonInviteCode.TabStop = false;
+ CopyButtonInviteCode.CopyFunction = null;
+ CopyButtonInviteCode.HelpText = "Copy invite code to clipboard";
+ CopyButtonInviteCode.Location = new System.Drawing.Point(276, 85);
+ CopyButtonInviteCode.Name = "CopyButtonInviteCode";
+ CopyButtonInviteCode.Size = new System.Drawing.Size(16, 16);
+ CopyButtonInviteCode.TabIndex = 7;
+ CopyButtonInviteCode.TabStop = false;
//
// LabelInviteCode
//
- this.LabelInviteCode.HelpText = resources.GetString("LabelInviteCode.HelpText");
- this.LabelInviteCode.LabelSplitRatio = 0.455D;
- this.LabelInviteCode.LabelText = "Invite Code:";
- this.LabelInviteCode.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.LabelInviteCode.Location = new System.Drawing.Point(6, 85);
- this.LabelInviteCode.Name = "LabelInviteCode";
- this.LabelInviteCode.Size = new System.Drawing.Size(264, 15);
- this.LabelInviteCode.TabIndex = 6;
- this.LabelInviteCode.TabStop = false;
- this.LabelInviteCode.Value = "N/A";
- this.LabelInviteCode.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ LabelInviteCode.HelpText = resources.GetString("LabelInviteCode.HelpText");
+ LabelInviteCode.LabelSplitRatio = 0.455D;
+ LabelInviteCode.LabelText = "Invite Code:";
+ LabelInviteCode.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ LabelInviteCode.Location = new System.Drawing.Point(6, 85);
+ LabelInviteCode.Name = "LabelInviteCode";
+ LabelInviteCode.Size = new System.Drawing.Size(264, 15);
+ LabelInviteCode.TabIndex = 6;
+ LabelInviteCode.TabStop = false;
+ LabelInviteCode.Value = "N/A";
+ LabelInviteCode.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// CopyButtonLocalIpAddress
//
- this.CopyButtonLocalIpAddress.CopyFunction = null;
- this.CopyButtonLocalIpAddress.HelpText = "Copy local IP address to clipboard";
- this.CopyButtonLocalIpAddress.Location = new System.Drawing.Point(276, 63);
- this.CopyButtonLocalIpAddress.Name = "CopyButtonLocalIpAddress";
- this.CopyButtonLocalIpAddress.Size = new System.Drawing.Size(16, 16);
- this.CopyButtonLocalIpAddress.TabIndex = 5;
- this.CopyButtonLocalIpAddress.TabStop = false;
+ CopyButtonLocalIpAddress.CopyFunction = null;
+ CopyButtonLocalIpAddress.HelpText = "Copy local IP address to clipboard";
+ CopyButtonLocalIpAddress.Location = new System.Drawing.Point(276, 63);
+ CopyButtonLocalIpAddress.Name = "CopyButtonLocalIpAddress";
+ CopyButtonLocalIpAddress.Size = new System.Drawing.Size(16, 16);
+ CopyButtonLocalIpAddress.TabIndex = 5;
+ CopyButtonLocalIpAddress.TabStop = false;
//
// CopyButtonExternalIpAddress
//
- this.CopyButtonExternalIpAddress.CopyFunction = null;
- this.CopyButtonExternalIpAddress.HelpText = "Copy external IP address to clipboard";
- this.CopyButtonExternalIpAddress.Location = new System.Drawing.Point(276, 22);
- this.CopyButtonExternalIpAddress.Name = "CopyButtonExternalIpAddress";
- this.CopyButtonExternalIpAddress.Size = new System.Drawing.Size(16, 16);
- this.CopyButtonExternalIpAddress.TabIndex = 1;
- this.CopyButtonExternalIpAddress.TabStop = false;
+ CopyButtonExternalIpAddress.CopyFunction = null;
+ CopyButtonExternalIpAddress.HelpText = "Copy external IP address to clipboard";
+ CopyButtonExternalIpAddress.Location = new System.Drawing.Point(276, 22);
+ CopyButtonExternalIpAddress.Name = "CopyButtonExternalIpAddress";
+ CopyButtonExternalIpAddress.Size = new System.Drawing.Size(16, 16);
+ CopyButtonExternalIpAddress.TabIndex = 1;
+ CopyButtonExternalIpAddress.TabStop = false;
//
// CopyButtonInternalIpAddress
//
- this.CopyButtonInternalIpAddress.CopyFunction = null;
- this.CopyButtonInternalIpAddress.HelpText = "Copy internal IP address to clipboard";
- this.CopyButtonInternalIpAddress.Location = new System.Drawing.Point(276, 43);
- this.CopyButtonInternalIpAddress.Name = "CopyButtonInternalIpAddress";
- this.CopyButtonInternalIpAddress.Size = new System.Drawing.Size(16, 16);
- this.CopyButtonInternalIpAddress.TabIndex = 3;
- this.CopyButtonInternalIpAddress.TabStop = false;
+ CopyButtonInternalIpAddress.CopyFunction = null;
+ CopyButtonInternalIpAddress.HelpText = "Copy internal IP address to clipboard";
+ CopyButtonInternalIpAddress.Location = new System.Drawing.Point(276, 43);
+ CopyButtonInternalIpAddress.Name = "CopyButtonInternalIpAddress";
+ CopyButtonInternalIpAddress.Size = new System.Drawing.Size(16, 16);
+ CopyButtonInternalIpAddress.TabIndex = 3;
+ CopyButtonInternalIpAddress.TabStop = false;
//
// label1
//
- this.label1.AutoSize = true;
- this.label1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point);
- this.label1.Location = new System.Drawing.Point(6, 110);
- this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(261, 15);
- this.label1.TabIndex = 8;
- this.label1.Text = "Trouble connecting? See Help > Port Forwarding.\r\n";
+ label1.AutoSize = true;
+ label1.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point);
+ label1.Location = new System.Drawing.Point(6, 110);
+ label1.Name = "label1";
+ label1.Size = new System.Drawing.Size(261, 15);
+ label1.TabIndex = 8;
+ label1.Text = "Trouble connecting? See Help > Port Forwarding.\r\n";
//
// LabelExternalIpAddress
//
- this.LabelExternalIpAddress.HelpText = "This is the address that players from outside your home network will use to\r\nconn" +
- "ect to your server. Give this address to your friends for standard online play.\r" +
- "\n";
- this.LabelExternalIpAddress.LabelSplitRatio = 0.455D;
- this.LabelExternalIpAddress.LabelText = "External IP Address:";
- this.LabelExternalIpAddress.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.LabelExternalIpAddress.Location = new System.Drawing.Point(6, 22);
- this.LabelExternalIpAddress.Name = "LabelExternalIpAddress";
- this.LabelExternalIpAddress.Size = new System.Drawing.Size(264, 15);
- this.LabelExternalIpAddress.TabIndex = 0;
- this.LabelExternalIpAddress.TabStop = false;
- this.LabelExternalIpAddress.Value = "Loading...";
- this.LabelExternalIpAddress.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ LabelExternalIpAddress.HelpText = "This is the address that players from outside your home network will use to\r\nconnect to your server. Give this address to your friends for standard online play.\r\n";
+ LabelExternalIpAddress.LabelSplitRatio = 0.455D;
+ LabelExternalIpAddress.LabelText = "External IP Address:";
+ LabelExternalIpAddress.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ LabelExternalIpAddress.Location = new System.Drawing.Point(6, 22);
+ LabelExternalIpAddress.Name = "LabelExternalIpAddress";
+ LabelExternalIpAddress.Size = new System.Drawing.Size(264, 15);
+ LabelExternalIpAddress.TabIndex = 0;
+ LabelExternalIpAddress.TabStop = false;
+ LabelExternalIpAddress.Value = "Loading...";
+ LabelExternalIpAddress.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// LabelLocalIpAddress
//
- this.LabelLocalIpAddress.HelpText = resources.GetString("LabelLocalIpAddress.HelpText");
- this.LabelLocalIpAddress.LabelSplitRatio = 0.455D;
- this.LabelLocalIpAddress.LabelText = "Local IP Address:";
- this.LabelLocalIpAddress.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.LabelLocalIpAddress.Location = new System.Drawing.Point(6, 64);
- this.LabelLocalIpAddress.Name = "LabelLocalIpAddress";
- this.LabelLocalIpAddress.Size = new System.Drawing.Size(264, 15);
- this.LabelLocalIpAddress.TabIndex = 4;
- this.LabelLocalIpAddress.TabStop = false;
- this.LabelLocalIpAddress.Value = "127.0.0.1";
- this.LabelLocalIpAddress.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ LabelLocalIpAddress.HelpText = resources.GetString("LabelLocalIpAddress.HelpText");
+ LabelLocalIpAddress.LabelSplitRatio = 0.455D;
+ LabelLocalIpAddress.LabelText = "Local IP Address:";
+ LabelLocalIpAddress.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ LabelLocalIpAddress.Location = new System.Drawing.Point(6, 64);
+ LabelLocalIpAddress.Name = "LabelLocalIpAddress";
+ LabelLocalIpAddress.Size = new System.Drawing.Size(264, 15);
+ LabelLocalIpAddress.TabIndex = 4;
+ LabelLocalIpAddress.TabStop = false;
+ LabelLocalIpAddress.Value = "127.0.0.1";
+ LabelLocalIpAddress.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// LabelInternalIpAddress
//
- this.LabelInternalIpAddress.HelpText = resources.GetString("LabelInternalIpAddress.HelpText");
- this.LabelInternalIpAddress.LabelSplitRatio = 0.455D;
- this.LabelInternalIpAddress.LabelText = "Internal IP Address:";
- this.LabelInternalIpAddress.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.LabelInternalIpAddress.Location = new System.Drawing.Point(6, 43);
- this.LabelInternalIpAddress.Name = "LabelInternalIpAddress";
- this.LabelInternalIpAddress.Size = new System.Drawing.Size(264, 15);
- this.LabelInternalIpAddress.TabIndex = 2;
- this.LabelInternalIpAddress.TabStop = false;
- this.LabelInternalIpAddress.Value = "Loading...";
- this.LabelInternalIpAddress.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ LabelInternalIpAddress.HelpText = resources.GetString("LabelInternalIpAddress.HelpText");
+ LabelInternalIpAddress.LabelSplitRatio = 0.455D;
+ LabelInternalIpAddress.LabelText = "Internal IP Address:";
+ LabelInternalIpAddress.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ LabelInternalIpAddress.Location = new System.Drawing.Point(6, 43);
+ LabelInternalIpAddress.Name = "LabelInternalIpAddress";
+ LabelInternalIpAddress.Size = new System.Drawing.Size(264, 15);
+ LabelInternalIpAddress.TabIndex = 2;
+ LabelInternalIpAddress.TabStop = false;
+ LabelInternalIpAddress.Value = "Loading...";
+ LabelInternalIpAddress.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// TabPlayers
//
- this.TabPlayers.Controls.Add(this.ButtonRemovePlayer);
- this.TabPlayers.Controls.Add(this.ButtonPlayerDetails);
- this.TabPlayers.Controls.Add(this.PlayersTable);
- this.TabPlayers.Location = new System.Drawing.Point(4, 24);
- this.TabPlayers.Name = "TabPlayers";
- this.TabPlayers.Size = new System.Drawing.Size(452, 252);
- this.TabPlayers.TabIndex = 3;
- this.TabPlayers.Text = "Players";
- this.TabPlayers.UseVisualStyleBackColor = true;
+ TabPlayers.Controls.Add(LinkCharacterNamesHelp);
+ TabPlayers.Controls.Add(ButtonRemovePlayer);
+ TabPlayers.Controls.Add(ButtonPlayerDetails);
+ TabPlayers.Controls.Add(PlayersTable);
+ TabPlayers.Location = new System.Drawing.Point(4, 24);
+ TabPlayers.Name = "TabPlayers";
+ TabPlayers.Size = new System.Drawing.Size(452, 252);
+ TabPlayers.TabIndex = 3;
+ TabPlayers.Text = "Players";
+ TabPlayers.UseVisualStyleBackColor = true;
+ //
+ // LinkCharacterNamesHelp
+ //
+ LinkCharacterNamesHelp.AutoSize = true;
+ LinkCharacterNamesHelp.Location = new System.Drawing.Point(224, 7);
+ LinkCharacterNamesHelp.Name = "LinkCharacterNamesHelp";
+ LinkCharacterNamesHelp.Size = new System.Drawing.Size(196, 15);
+ LinkCharacterNamesHelp.TabIndex = 3;
+ LinkCharacterNamesHelp.TabStop = true;
+ LinkCharacterNamesHelp.Text = "Character names wrong? Click here.";
//
// ButtonRemovePlayer
//
- this.ButtonRemovePlayer.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.ButtonRemovePlayer.Enabled = false;
- this.ButtonRemovePlayer.Image = global::ValheimServerGUI.Properties.Resources.Cancel_16x;
- this.ButtonRemovePlayer.Location = new System.Drawing.Point(426, 3);
- this.ButtonRemovePlayer.Name = "ButtonRemovePlayer";
- this.ButtonRemovePlayer.Size = new System.Drawing.Size(23, 23);
- this.ButtonRemovePlayer.TabIndex = 1;
- this.ButtonRemovePlayer.UseVisualStyleBackColor = true;
+ ButtonRemovePlayer.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
+ ButtonRemovePlayer.Enabled = false;
+ ButtonRemovePlayer.Image = Properties.Resources.Cancel_16x;
+ ButtonRemovePlayer.Location = new System.Drawing.Point(426, 3);
+ ButtonRemovePlayer.Name = "ButtonRemovePlayer";
+ ButtonRemovePlayer.Size = new System.Drawing.Size(23, 23);
+ ButtonRemovePlayer.TabIndex = 1;
+ ButtonRemovePlayer.UseVisualStyleBackColor = true;
//
// ButtonPlayerDetails
//
- this.ButtonPlayerDetails.Enabled = false;
- this.ButtonPlayerDetails.Location = new System.Drawing.Point(3, 3);
- this.ButtonPlayerDetails.Name = "ButtonPlayerDetails";
- this.ButtonPlayerDetails.Size = new System.Drawing.Size(92, 23);
- this.ButtonPlayerDetails.TabIndex = 0;
- this.ButtonPlayerDetails.Text = "Player Info...";
- this.ButtonPlayerDetails.UseVisualStyleBackColor = true;
+ ButtonPlayerDetails.Enabled = false;
+ ButtonPlayerDetails.Location = new System.Drawing.Point(3, 3);
+ ButtonPlayerDetails.Name = "ButtonPlayerDetails";
+ ButtonPlayerDetails.Size = new System.Drawing.Size(132, 23);
+ ButtonPlayerDetails.TabIndex = 0;
+ ButtonPlayerDetails.Text = "View Player Details...";
+ ButtonPlayerDetails.UseVisualStyleBackColor = true;
//
// PlayersTable
//
- this.PlayersTable.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.PlayersTable.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
- this.ColumnPlayerStatus,
- this.ColumnPlayerName,
- this.ColumnPlayerUpdated});
- this.PlayersTable.Icons = this.ImageList;
- this.PlayersTable.Location = new System.Drawing.Point(3, 32);
- this.PlayersTable.Name = "PlayersTable";
- this.PlayersTable.Size = new System.Drawing.Size(446, 217);
- this.PlayersTable.TabIndex = 2;
+ PlayersTable.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ PlayersTable.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { ColumnPlayerName, ColumnPlayerStatus, ColumnPlayerUpdated });
+ PlayersTable.Icons = ImageList;
+ PlayersTable.Location = new System.Drawing.Point(3, 32);
+ PlayersTable.Name = "PlayersTable";
+ PlayersTable.Size = new System.Drawing.Size(446, 217);
+ PlayersTable.TabIndex = 2;
//
- // ColumnPlayerStatus
+ // ColumnPlayerName
//
- this.ColumnPlayerStatus.DisplayIndex = 1;
- this.ColumnPlayerStatus.Text = "Status";
- this.ColumnPlayerStatus.Width = 120;
+ ColumnPlayerName.Text = "Player (Character)";
+ ColumnPlayerName.Width = 240;
//
- // ColumnPlayerName
+ // ColumnPlayerStatus
//
- this.ColumnPlayerName.DisplayIndex = 0;
- this.ColumnPlayerName.Text = "Character Name";
- this.ColumnPlayerName.Width = 160;
+ ColumnPlayerStatus.Text = "Status";
+ ColumnPlayerStatus.Width = 80;
//
// ColumnPlayerUpdated
//
- this.ColumnPlayerUpdated.Text = "Since";
- this.ColumnPlayerUpdated.Width = 160;
+ ColumnPlayerUpdated.Text = "Since";
+ ColumnPlayerUpdated.Width = 120;
//
// ImageList
//
- this.ImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
- this.ImageList.ImageSize = new System.Drawing.Size(16, 16);
- this.ImageList.TransparentColor = System.Drawing.Color.Transparent;
+ ImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
+ ImageList.ImageSize = new System.Drawing.Size(16, 16);
+ ImageList.TransparentColor = System.Drawing.Color.Transparent;
//
// TabLogs
//
- this.TabLogs.Controls.Add(this.ButtonSaveLogs);
- this.TabLogs.Controls.Add(this.LogViewSelectField);
- this.TabLogs.Controls.Add(this.LogViewer);
- this.TabLogs.Controls.Add(this.ButtonClearLogs);
- this.TabLogs.Location = new System.Drawing.Point(4, 24);
- this.TabLogs.Name = "TabLogs";
- this.TabLogs.Size = new System.Drawing.Size(452, 252);
- this.TabLogs.TabIndex = 2;
- this.TabLogs.Text = "Logs";
- this.TabLogs.UseVisualStyleBackColor = true;
+ TabLogs.Controls.Add(LogsFolderOpenButton);
+ TabLogs.Controls.Add(ButtonSaveLogs);
+ TabLogs.Controls.Add(LogViewSelectField);
+ TabLogs.Controls.Add(LogViewer);
+ TabLogs.Controls.Add(ButtonClearLogs);
+ TabLogs.Location = new System.Drawing.Point(4, 24);
+ TabLogs.Name = "TabLogs";
+ TabLogs.Size = new System.Drawing.Size(452, 252);
+ TabLogs.TabIndex = 2;
+ TabLogs.Text = "Logs";
+ TabLogs.UseVisualStyleBackColor = true;
+ //
+ // LogsFolderOpenButton
+ //
+ LogsFolderOpenButton.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
+ LogsFolderOpenButton.HelpText = "Open the logs folder in Explorer";
+ LogsFolderOpenButton.Location = new System.Drawing.Point(258, 25);
+ LogsFolderOpenButton.Name = "LogsFolderOpenButton";
+ LogsFolderOpenButton.PathFunction = null;
+ LogsFolderOpenButton.Size = new System.Drawing.Size(16, 16);
+ LogsFolderOpenButton.TabIndex = 1;
//
// ButtonSaveLogs
//
- this.ButtonSaveLogs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.ButtonSaveLogs.Location = new System.Drawing.Point(280, 22);
- this.ButtonSaveLogs.Name = "ButtonSaveLogs";
- this.ButtonSaveLogs.Size = new System.Drawing.Size(88, 23);
- this.ButtonSaveLogs.TabIndex = 1;
- this.ButtonSaveLogs.Text = "Save Logs...";
- this.ButtonSaveLogs.UseVisualStyleBackColor = true;
+ ButtonSaveLogs.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
+ ButtonSaveLogs.Location = new System.Drawing.Point(280, 22);
+ ButtonSaveLogs.Name = "ButtonSaveLogs";
+ ButtonSaveLogs.Size = new System.Drawing.Size(88, 23);
+ ButtonSaveLogs.TabIndex = 2;
+ ButtonSaveLogs.Text = "Save Logs...";
+ ButtonSaveLogs.UseVisualStyleBackColor = true;
//
// LogViewSelectField
//
- this.LogViewSelectField.DropdownEnabled = true;
- this.LogViewSelectField.EmptyText = "";
- this.LogViewSelectField.HelpText = "";
- this.LogViewSelectField.LabelText = "View logs for...";
- this.LogViewSelectField.Location = new System.Drawing.Point(-4, 4);
- this.LogViewSelectField.Name = "LogViewSelectField";
- this.LogViewSelectField.Size = new System.Drawing.Size(150, 41);
- this.LogViewSelectField.TabIndex = 0;
- this.LogViewSelectField.Value = null;
+ LogViewSelectField.DataSource = (System.Collections.Generic.IEnumerable)resources.GetObject("LogViewSelectField.DataSource");
+ LogViewSelectField.DropdownEnabled = true;
+ LogViewSelectField.EmptyText = "";
+ LogViewSelectField.HelpText = "";
+ LogViewSelectField.LabelText = "View logs for...";
+ LogViewSelectField.Location = new System.Drawing.Point(-4, 4);
+ LogViewSelectField.Name = "LogViewSelectField";
+ LogViewSelectField.Size = new System.Drawing.Size(150, 41);
+ LogViewSelectField.TabIndex = 0;
+ LogViewSelectField.Value = null;
//
// LogViewer
//
- this.LogViewer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
- | System.Windows.Forms.AnchorStyles.Left)
- | System.Windows.Forms.AnchorStyles.Right)));
- this.LogViewer.Location = new System.Drawing.Point(3, 51);
- this.LogViewer.LogView = "DefaultLogView";
- this.LogViewer.Name = "LogViewer";
- this.LogViewer.Size = new System.Drawing.Size(446, 198);
- this.LogViewer.TabIndex = 3;
- this.LogViewer.TabStop = false;
- this.LogViewer.TimestampFormat = "HH:mm:ss.fff";
+ LogViewer.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ LogViewer.Location = new System.Drawing.Point(3, 51);
+ LogViewer.LogView = "DefaultLogView";
+ LogViewer.Name = "LogViewer";
+ LogViewer.Size = new System.Drawing.Size(446, 198);
+ LogViewer.TabIndex = 4;
+ LogViewer.TabStop = false;
//
// ButtonClearLogs
//
- this.ButtonClearLogs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
- this.ButtonClearLogs.Location = new System.Drawing.Point(374, 22);
- this.ButtonClearLogs.Name = "ButtonClearLogs";
- this.ButtonClearLogs.Size = new System.Drawing.Size(75, 23);
- this.ButtonClearLogs.TabIndex = 2;
- this.ButtonClearLogs.Text = "Clear Logs";
- this.ButtonClearLogs.UseVisualStyleBackColor = true;
+ ButtonClearLogs.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
+ ButtonClearLogs.Location = new System.Drawing.Point(374, 22);
+ ButtonClearLogs.Name = "ButtonClearLogs";
+ ButtonClearLogs.Size = new System.Drawing.Size(75, 23);
+ ButtonClearLogs.TabIndex = 3;
+ ButtonClearLogs.Text = "Clear Logs";
+ ButtonClearLogs.UseVisualStyleBackColor = true;
//
// NotifyIcon
//
- this.NotifyIcon.ContextMenuStrip = this.TrayContextMenuStrip;
- this.NotifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("NotifyIcon.Icon")));
- this.NotifyIcon.Text = "ValheimServerGUI";
+ NotifyIcon.ContextMenuStrip = TrayContextMenuStrip;
+ NotifyIcon.Icon = (System.Drawing.Icon)resources.GetObject("NotifyIcon.Icon");
+ NotifyIcon.Text = "ValheimServerGUI";
//
// TrayContextMenuStrip
//
- this.TrayContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
- this.TrayContextMenuServerName,
- this.TrayContextMenuSeparator2,
- this.TrayContextMenuStart,
- this.TrayContextMenuRestart,
- this.TrayContextMenuStop,
- this.TrayContextMenuSeparator1,
- this.TrayContextMenuClose});
- this.TrayContextMenuStrip.Name = "TrayContextMenuStrip";
- this.TrayContextMenuStrip.Size = new System.Drawing.Size(146, 126);
+ TrayContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { TrayContextMenuServerName, TrayContextMenuSeparator2, TrayContextMenuStart, TrayContextMenuRestart, TrayContextMenuStop, TrayContextMenuSeparator1, TrayContextMenuClose });
+ TrayContextMenuStrip.Name = "TrayContextMenuStrip";
+ TrayContextMenuStrip.Size = new System.Drawing.Size(146, 126);
//
// TrayContextMenuServerName
//
- this.TrayContextMenuServerName.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
- this.TrayContextMenuServerName.Name = "TrayContextMenuServerName";
- this.TrayContextMenuServerName.Size = new System.Drawing.Size(145, 22);
- this.TrayContextMenuServerName.Text = "ServerName";
+ TrayContextMenuServerName.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
+ TrayContextMenuServerName.Name = "TrayContextMenuServerName";
+ TrayContextMenuServerName.Size = new System.Drawing.Size(145, 22);
+ TrayContextMenuServerName.Text = "ServerName";
//
// TrayContextMenuSeparator2
//
- this.TrayContextMenuSeparator2.Name = "TrayContextMenuSeparator2";
- this.TrayContextMenuSeparator2.Size = new System.Drawing.Size(142, 6);
+ TrayContextMenuSeparator2.Name = "TrayContextMenuSeparator2";
+ TrayContextMenuSeparator2.Size = new System.Drawing.Size(142, 6);
//
// TrayContextMenuStart
//
- this.TrayContextMenuStart.Enabled = false;
- this.TrayContextMenuStart.Image = global::ValheimServerGUI.Properties.Resources.Run_16x;
- this.TrayContextMenuStart.Name = "TrayContextMenuStart";
- this.TrayContextMenuStart.Size = new System.Drawing.Size(145, 22);
- this.TrayContextMenuStart.Text = "Start Server";
+ TrayContextMenuStart.Enabled = false;
+ TrayContextMenuStart.Image = Properties.Resources.Run_16x;
+ TrayContextMenuStart.Name = "TrayContextMenuStart";
+ TrayContextMenuStart.Size = new System.Drawing.Size(145, 22);
+ TrayContextMenuStart.Text = "Start Server";
//
// TrayContextMenuRestart
//
- this.TrayContextMenuRestart.Enabled = false;
- this.TrayContextMenuRestart.Image = global::ValheimServerGUI.Properties.Resources.Restart_16x;
- this.TrayContextMenuRestart.Name = "TrayContextMenuRestart";
- this.TrayContextMenuRestart.Size = new System.Drawing.Size(145, 22);
- this.TrayContextMenuRestart.Text = "Restart Server";
+ TrayContextMenuRestart.Enabled = false;
+ TrayContextMenuRestart.Image = Properties.Resources.Restart_16x;
+ TrayContextMenuRestart.Name = "TrayContextMenuRestart";
+ TrayContextMenuRestart.Size = new System.Drawing.Size(145, 22);
+ TrayContextMenuRestart.Text = "Restart Server";
//
// TrayContextMenuStop
//
- this.TrayContextMenuStop.Enabled = false;
- this.TrayContextMenuStop.Image = global::ValheimServerGUI.Properties.Resources.Stop_16x;
- this.TrayContextMenuStop.Name = "TrayContextMenuStop";
- this.TrayContextMenuStop.Size = new System.Drawing.Size(145, 22);
- this.TrayContextMenuStop.Text = "Stop Server";
+ TrayContextMenuStop.Enabled = false;
+ TrayContextMenuStop.Image = Properties.Resources.Stop_16x;
+ TrayContextMenuStop.Name = "TrayContextMenuStop";
+ TrayContextMenuStop.Size = new System.Drawing.Size(145, 22);
+ TrayContextMenuStop.Text = "Stop Server";
//
// TrayContextMenuSeparator1
//
- this.TrayContextMenuSeparator1.Name = "TrayContextMenuSeparator1";
- this.TrayContextMenuSeparator1.Size = new System.Drawing.Size(142, 6);
+ TrayContextMenuSeparator1.Name = "TrayContextMenuSeparator1";
+ TrayContextMenuSeparator1.Size = new System.Drawing.Size(142, 6);
//
// TrayContextMenuClose
//
- this.TrayContextMenuClose.Name = "TrayContextMenuClose";
- this.TrayContextMenuClose.Size = new System.Drawing.Size(145, 22);
- this.TrayContextMenuClose.Text = "Close";
+ TrayContextMenuClose.Name = "TrayContextMenuClose";
+ TrayContextMenuClose.Size = new System.Drawing.Size(145, 22);
+ TrayContextMenuClose.Text = "Close";
//
// ServerRefreshTimer
//
- this.ServerRefreshTimer.Enabled = true;
- this.ServerRefreshTimer.Interval = 1000;
+ ServerRefreshTimer.Enabled = true;
+ ServerRefreshTimer.Interval = 1000;
//
// UpdateCheckTimer
//
- this.UpdateCheckTimer.Enabled = true;
- this.UpdateCheckTimer.Interval = 60000;
+ UpdateCheckTimer.Enabled = true;
+ UpdateCheckTimer.Interval = 60000;
//
// MainWindow
//
- this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(484, 332);
- this.Controls.Add(this.Tabs);
- this.Controls.Add(this.StatusStrip);
- this.Controls.Add(this.MenuStrip);
- this.MainMenuStrip = this.MenuStrip;
- this.MaximizeBox = false;
- this.MinimumSize = new System.Drawing.Size(500, 371);
- this.Name = "MainWindow";
- this.Text = "ApplicationTitle";
- this.MenuStrip.ResumeLayout(false);
- this.MenuStrip.PerformLayout();
- this.StatusStrip.ResumeLayout(false);
- this.StatusStrip.PerformLayout();
- this.Tabs.ResumeLayout(false);
- this.TabServerControls.ResumeLayout(false);
- this.JoinOptionsGroupBox.ResumeLayout(false);
- this.WorldSelectGroupBox.ResumeLayout(false);
- this.TabAdvancedControls.ResumeLayout(false);
- this.SavingGroupBox.ResumeLayout(false);
- this.StartupGroupBox.ResumeLayout(false);
- this.DirectoriesGroupBox.ResumeLayout(false);
- this.TabServerDetails.ResumeLayout(false);
- this.groupBox2.ResumeLayout(false);
- this.groupBox1.ResumeLayout(false);
- this.groupBox1.PerformLayout();
- this.TabPlayers.ResumeLayout(false);
- this.TabLogs.ResumeLayout(false);
- this.TrayContextMenuStrip.ResumeLayout(false);
- this.ResumeLayout(false);
- this.PerformLayout();
-
+ AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ ClientSize = new System.Drawing.Size(484, 332);
+ Controls.Add(Tabs);
+ Controls.Add(StatusStrip);
+ Controls.Add(MenuStrip);
+ MainMenuStrip = MenuStrip;
+ MaximizeBox = false;
+ MinimumSize = new System.Drawing.Size(500, 371);
+ Name = "MainWindow";
+ Text = "ApplicationTitle";
+ MenuStrip.ResumeLayout(false);
+ MenuStrip.PerformLayout();
+ StatusStrip.ResumeLayout(false);
+ StatusStrip.PerformLayout();
+ Tabs.ResumeLayout(false);
+ TabServerControls.ResumeLayout(false);
+ JoinOptionsGroupBox.ResumeLayout(false);
+ WorldSelectGroupBox.ResumeLayout(false);
+ TabAdvancedControls.ResumeLayout(false);
+ SavingGroupBox.ResumeLayout(false);
+ OtherSettingsGroupBox.ResumeLayout(false);
+ DirectoriesGroupBox.ResumeLayout(false);
+ TabServerDetails.ResumeLayout(false);
+ groupBox2.ResumeLayout(false);
+ groupBox1.ResumeLayout(false);
+ groupBox1.PerformLayout();
+ TabPlayers.ResumeLayout(false);
+ TabPlayers.PerformLayout();
+ TabLogs.ResumeLayout(false);
+ TrayContextMenuStrip.ResumeLayout(false);
+ ResumeLayout(false);
+ PerformLayout();
}
#endregion
@@ -1319,7 +1294,7 @@ private void InitializeComponent()
private Controls.TextFormField ServerAdditionalArgsField;
private System.Windows.Forms.ToolStripMenuItem MenuItemFileSaveProfileAs;
private System.Windows.Forms.ToolStripMenuItem MenuItemFileOpenSettings;
- private System.Windows.Forms.GroupBox StartupGroupBox;
+ private System.Windows.Forms.GroupBox OtherSettingsGroupBox;
private ValheimServerGUI.Controls.CheckboxFormField ServerAutoStartField;
private System.Windows.Forms.ToolStripMenuItem MenuItemHelpDiscord;
private System.Windows.Forms.GroupBox SavingGroupBox;
@@ -1330,5 +1305,8 @@ private void InitializeComponent()
private OpenButton ServerExePathOpenButton;
private OpenButton WorldsFolderOpenButton;
private RefreshButton WorldsListRefreshButton;
+ private ValheimServerGUI.Controls.CheckboxFormField ServerLogFileField;
+ private OpenButton LogsFolderOpenButton;
+ private System.Windows.Forms.LinkLabel LinkCharacterNamesHelp;
}
}
\ No newline at end of file
diff --git a/ValheimServerGUI/Forms/MainWindow.cs b/ValheimServerGUI/Forms/MainWindow.cs
index 90e79c2..a250b09 100644
--- a/ValheimServerGUI/Forms/MainWindow.cs
+++ b/ValheimServerGUI/Forms/MainWindow.cs
@@ -1,4 +1,3 @@
-using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -12,7 +11,7 @@
using ValheimServerGUI.Properties;
using ValheimServerGUI.Tools;
using ValheimServerGUI.Tools.Logging;
-using ValheimServerGUI.Tools.Processes;
+using ValheimServerGUI.Tools.Models;
namespace ValheimServerGUI.Forms
{
@@ -48,8 +47,6 @@ public string CurrentProfile
public bool StartServerAutomatically { get; set; }
private static readonly string NL = Environment.NewLine;
- private const string LogViewServer = "Server";
- private const string LogViewApplication = "Application";
private const string IpLoadingText = "Loading...";
private readonly Stopwatch ServerUptimeTimer = new();
@@ -67,11 +64,9 @@ public string CurrentProfile
private readonly IServerPreferencesProvider ServerPrefsProvider;
private readonly IPlayerDataRepository PlayerDataProvider;
private readonly ValheimServer Server;
- private readonly IEventLogger Logger;
+ private readonly IApplicationLogger Logger;
private readonly IIpAddressProvider IpAddressProvider;
private readonly ISoftwareUpdateProvider SoftwareUpdateProvider;
- private readonly IProcessProvider ProcessProvider;
- private readonly IStartupArgsProvider StartupArgsProvider;
public MainWindow(
IFormProvider formProvider,
@@ -79,11 +74,9 @@ public MainWindow(
IServerPreferencesProvider serverPrefsProvider,
IPlayerDataRepository playerDataProvider,
ValheimServer server,
- IEventLogger appLogger,
+ IApplicationLogger appLogger,
IIpAddressProvider ipAddressProvider,
- ISoftwareUpdateProvider softwareUpdateProvider,
- IProcessProvider processProvider,
- IStartupArgsProvider startupArgsProvider)
+ ISoftwareUpdateProvider softwareUpdateProvider)
{
#if DEBUG
if (SimulateConstructorException) throw new InvalidOperationException("Intentional exception thrown for testing");
@@ -96,8 +89,6 @@ public MainWindow(
Logger = appLogger;
IpAddressProvider = ipAddressProvider;
SoftwareUpdateProvider = softwareUpdateProvider;
- ProcessProvider = processProvider;
- StartupArgsProvider = startupArgsProvider;
InitializeComponent(); // WinForms generated code, always first
this.AddApplicationIcon();
@@ -116,8 +107,6 @@ private void InitializeImages()
private void InitializeServices()
{
- Logger.LogReceived += this.BuildEventHandler(OnApplicationLogReceived);
- Server.LogReceived += this.BuildEventHandler(OnServerLogReceived);
Server.StatusChanged += this.BuildEventHandler(OnServerStatusChanged);
Server.WorldSaved += this.BuildEventHandler(OnWorldSaved);
Server.InviteCodeReady += this.BuildEventHandler(OnInviteCodeReady);
@@ -176,7 +165,9 @@ private void InitializeFormEvents()
ButtonStopServer.Click += this.BuildEventHandler(ButtonStopServer_Click);
ButtonClearLogs.Click += ButtonClearLogs_Click;
ButtonSaveLogs.Click += ButtonSaveLogs_Click;
+ LogsFolderOpenButton.PathFunction = () => Resources.LogsFolderPath;
ButtonPlayerDetails.Click += ButtonPlayerDetails_Click;
+ LinkCharacterNamesHelp.Click += LinkCharacterNamesHelp_Click;
ButtonRemovePlayer.Click += ButtonRemovePlayer_Click;
CopyButtonServerPassword.CopyFunction = () => ServerPasswordField.Value;
WorldsListRefreshButton.RefreshFunction = WorldsListRefreshButton_Click;
@@ -201,8 +192,16 @@ private void InitializeFormEvents()
private void InitializeFormFields()
{
- LogViewSelectField.DataSource = new[] { LogViewServer, LogViewApplication };
- LogViewSelectField.Value = LogViewServer;
+ // Write message backlog to application log view...
+ foreach (var message in Logger.LogBuffer)
+ {
+ LogViewer.AddLogToView(message, LogViews.Application);
+ }
+ // ...then write all new messages to that log view.
+ Logger.LogReceived += this.BuildActionHandler(OnApplicationLogReceived);
+
+ LogViewSelectField.DataSource = new[] { LogViews.Server, LogViews.Application };
+ LogViewSelectField.Value = LogViews.Server;
ServerExePathField.ConfigureFileDialog(dialog => dialog.Filter = "Applications (*.exe)|*.exe");
RefreshFormFields();
@@ -249,7 +248,7 @@ private void InitializePlayerData()
{
PlayersTable.AddRowBinding(row =>
{
- row.AddCellBinding(ColumnPlayerName.Index, p => p.PlayerName ?? $"(...{p.SteamId[^4..]})");
+ row.AddCellBinding(ColumnPlayerName.Index, GetPlayerDisplayName);
row.AddCellBinding(ColumnPlayerStatus.Index, p => p.PlayerStatus);
row.AddCellBinding(ColumnPlayerUpdated.Index, p => new TimeAgo(p.LastStatusChange));
});
@@ -274,7 +273,7 @@ protected override void OnShown(EventArgs e)
CheckFilePaths();
NotifyIcon.Visible = true;
- Logger.LogInformation("Valheim Server GUI v{version} - Loaded OK", AssemblyHelper.GetApplicationVersion());
+ Logger.Information("Valheim Server GUI v{version} - Loaded OK", AssemblyHelper.GetApplicationVersion());
}
private void OnProfileChanged(string _)
@@ -504,16 +503,27 @@ private void ButtonSaveLogs_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(LogViewer.GetCurrentViewText()))
{
- Logger.LogWarning("No logs to save!");
+ Logger.Warning("No logs to save!");
return;
}
+ string initialDirectory;
+ try
+ {
+ initialDirectory = PathExtensions.GetDirectoryInfo(Resources.LogsFolderPath).FullName;
+ }
+ catch
+ {
+ initialDirectory = null;
+ }
+
var dialog = new SaveFileDialog
{
- FileName = $"{LogViewer.LogView}Logs-{DateTime.Now:u}.txt",
+ FileName = $"{PathExtensions.GetValidFileName(LogViewer.LogView, true)}.txt",
Filter = "Text Files (*.txt)|*.txt",
CheckPathExists = true,
RestoreDirectory = true,
+ InitialDirectory = initialDirectory,
};
var result = dialog.ShowDialog();
@@ -527,7 +537,7 @@ private void ButtonSaveLogs_Click(object sender, EventArgs e)
}
catch (Exception exception)
{
- Logger.LogError(exception, $"Failed to write log file: {dialog.FileName}");
+ Logger.Error(exception, "Failed to write log file: {fileName}", dialog.FileName);
}
}
}
@@ -541,6 +551,11 @@ private void ButtonPlayerDetails_Click(object sender, EventArgs e)
form.ShowDialog();
}
+ private void LinkCharacterNamesHelp_Click(object sender, EventArgs e)
+ {
+ OpenHelper.OpenWebAddress(Resources.UrlHelpCharacterNames);
+ }
+
private void ButtonRemovePlayer_Click(object sender, EventArgs e)
{
if (PlayersTable.TryGetSelectedRow(out var row))
@@ -657,14 +672,14 @@ private void WorldsListRefreshButton_Click()
#region Service Events
- private void OnApplicationLogReceived(EventLogContext logEvent)
+ private void OnApplicationLogReceived(string message)
{
- AddLog(logEvent.Message, LogViewApplication);
+ LogViewer.AddLogToView(message, LogViews.Application);
}
- private void OnServerLogReceived(EventLogContext logEvent)
+ private void OnServerLogReceived(string message)
{
- AddLog(logEvent.Message, LogViewServer);
+ LogViewer.AddLogToView(message, LogViews.Server);
}
private void OnServerStatusChanged(ServerStatus status)
@@ -825,11 +840,6 @@ private void ShowDirectoriesForm()
#region View Setters
- private void AddLog(string message, string viewName)
- {
- LogViewer.AddLogToView(message, viewName);
- }
-
private void ClearCurrentLogView()
{
LogViewer.ClearLogView(LogViewer.LogView);
@@ -852,33 +862,33 @@ private void SetPlayerStatus(PlayerInfo player)
{
var playerRows = PlayersTable
.GetRowsWithType()
- .Where(p => p.Entity.SteamId == player.SteamId);
+ .Where(r => r.Entity.Platform == player.Platform && r.Entity.PlayerId == player.PlayerId);
var playerRow = playerRows.FirstOrDefault(p => p.Entity.Key == player.Key) ?? PlayersTable.AddRowFromEntity(player);
if (playerRow == null) return;
- // Update styles based on player status
- var imageIndex = -1;
+ // Update styles based on player status and platform
+ var platformImageIndex = -1;
var color = PlayersTable.ForeColor;
- switch (player.PlayerStatus)
+ switch (player.Platform)
{
- case PlayerStatus.Online:
- imageIndex = GetImageIndex(nameof(Resources.StatusOK_16x));
+ case PlayerPlatforms.Steam:
+ platformImageIndex = GetImageIndex(nameof(Resources.Steam_16x));
break;
- case PlayerStatus.Joining:
- imageIndex = GetImageIndex(nameof(Resources.UnsyncedCommits_16x_Horiz));
- break;
- case PlayerStatus.Leaving:
- imageIndex = GetImageIndex(nameof(Resources.UnsyncedCommits_16x_Horiz));
+ case PlayerPlatforms.Xbox:
+ platformImageIndex = GetImageIndex(nameof(Resources.XboxLive_16x));
break;
+ }
+
+ switch (player.PlayerStatus)
+ {
case PlayerStatus.Offline:
- imageIndex = GetImageIndex(nameof(Resources.StatusNotStarted_16x));
color = Color.Gray;
break;
}
- playerRow.ImageIndex = imageIndex;
+ playerRow.ImageIndex = platformImageIndex;
playerRow.ForeColor = color;
}
@@ -928,6 +938,7 @@ private void RefreshFormStateForServer()
ServerAdditionalArgsField.Enabled = allowServerChanges;
ServerExePathField.Enabled = allowServerChanges;
ServerSaveDataFolderPathField.Enabled = allowServerChanges;
+ ServerLogFileField.Enabled = allowServerChanges;
MenuItemFileNewProfile.Enabled = allowServerChanges;
MenuItemFileLoadProfile.Enabled = allowServerChanges;
@@ -1008,7 +1019,7 @@ private void RefreshServerDetails()
{
var elapsed = ServerUptimeTimer.Elapsed;
var days = elapsed.Days;
- var timestr = elapsed.ToString(@"hh\:mm\:ss");
+ var timestr = elapsed.ToServerElapsedFormat();
if (days == 1) timestr = $"1 day + {timestr}";
else if (days > 1) timestr = $"{days} days + {timestr}";
@@ -1035,7 +1046,7 @@ private void RefreshWorldSelect()
// Show no worlds if something goes wrong
WorldSelectExistingNameField.DataSource = null;
WorldSelectExistingNameField.DropdownEnabled = false;
- Logger.LogError("Error refreshing world select: {message}", e.Message);
+ Logger.Error("Error refreshing world select: {message}", e.Message);
}
}
@@ -1084,6 +1095,7 @@ private ServerPreferences GetPrefsFromFormState()
prefs.AdditionalArgs = ServerAdditionalArgsField.Value;
prefs.ServerExePath = ServerExePathField.Value;
prefs.SaveDataFolderPath = ServerSaveDataFolderPathField.Value;
+ prefs.WriteServerLogsToFile = ServerLogFileField.Value;
return prefs;
}
@@ -1112,6 +1124,8 @@ private ValheimServerOptions GetServerOptionsFromFormState()
SaveDataFolderPath = !string.IsNullOrWhiteSpace(serverPrefs.SaveDataFolderPath)
? serverPrefs.SaveDataFolderPath
: userPrefs.SaveDataFolderPath,
+ LogToFile = serverPrefs.WriteServerLogsToFile,
+ LogMessageHandler = this.BuildActionHandler(OnServerLogReceived),
};
return options;
@@ -1122,7 +1136,7 @@ private ServerPreferences SetFormStateFromPrefs(string profileName)
var prefs = ServerPrefsProvider.LoadPreferences(profileName);
if (prefs == null)
{
- Logger.LogWarning("Unable to set form state: no server profile exists with name '{name}'", profileName);
+ Logger.Warning("Unable to set form state: no server profile exists with name '{name}'", profileName);
return prefs;
}
@@ -1134,7 +1148,7 @@ private void SetFormStateFromPrefs(ServerPreferences prefs)
{
if (prefs == null)
{
- Logger.LogWarning($"Unable to set form state: {nameof(prefs)} cannot be null");
+ Logger.Warning($"Unable to set form state: {nameof(prefs)} cannot be null");
return;
}
@@ -1154,6 +1168,7 @@ private void SetFormStateFromPrefs(ServerPreferences prefs)
ServerAdditionalArgsField.Value = prefs.AdditionalArgs;
ServerExePathField.Value = prefs.ServerExePath;
ServerSaveDataFolderPathField.Value = prefs.SaveDataFolderPath;
+ ServerLogFileField.Value = prefs.WriteServerLogsToFile;
RefreshWorldSelect();
var worldName = prefs.WorldName;
@@ -1185,7 +1200,7 @@ private void StartServer(bool isManualStart)
}
else
{
- Logger.LogError("Error starting server: {message}", message);
+ Logger.Error("Error starting server: {message}", message);
}
};
@@ -1361,6 +1376,19 @@ private int GetImageIndex(string key)
return ImageList.Images.IndexOfKey(key);
}
+ private string GetPlayerDisplayName(PlayerInfo player)
+ {
+ // Show the last 4 digits of the player's platform ID if their name is not yet known
+ var name = player.PlayerName ?? $"[...{player.PlayerId[^4..]}]";
+
+ if (!string.IsNullOrWhiteSpace(player.LastStatusCharacter))
+ {
+ name += $" ({player.LastStatusCharacter})";
+ }
+
+ return name;
+ }
+
#endregion
}
}
diff --git a/ValheimServerGUI/Forms/MainWindow.resx b/ValheimServerGUI/Forms/MainWindow.resx
index 5f85055..aee98a5 100644
--- a/ValheimServerGUI/Forms/MainWindow.resx
+++ b/ValheimServerGUI/Forms/MainWindow.resx
@@ -1,4 +1,64 @@
-
+
+
+
@@ -124,6 +184,14 @@ it yourself if you're hosting your server on another machine on your home networ
235, 17
+
+
+ AAEAAAD/////AQAAAAAAAAAEAQAAAH9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5
+ c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVi
+ bGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24GAAAI
+ CAkCAAAAAAAAAAAAAAARAgAAAAAAAAAL
+
+
339, 17
diff --git a/ValheimServerGUI/Forms/PlayerDetailsForm.Designer.cs b/ValheimServerGUI/Forms/PlayerDetailsForm.Designer.cs
index 645c69c..1fb1b7f 100644
--- a/ValheimServerGUI/Forms/PlayerDetailsForm.Designer.cs
+++ b/ValheimServerGUI/Forms/PlayerDetailsForm.Designer.cs
@@ -30,148 +30,192 @@ protected override void Dispose(bool disposing)
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PlayerDetailsForm));
- this.PlayerNameField = new ValheimServerGUI.Controls.LabelField();
- this.ButtonOK = new System.Windows.Forms.Button();
- this.ButtonRefresh = new System.Windows.Forms.Button();
- this.SteamIdField = new ValheimServerGUI.Controls.LabelField();
- this.ZdoIdField = new ValheimServerGUI.Controls.LabelField();
- this.OnlineStatusField = new ValheimServerGUI.Controls.LabelField();
- this.StatusChangedField = new ValheimServerGUI.Controls.LabelField();
- this.SteamIdWarningIcon = new System.Windows.Forms.PictureBox();
- this.SteamIdCopyButton = new ValheimServerGUI.Forms.CopyButton();
- ((System.ComponentModel.ISupportInitialize)(this.SteamIdWarningIcon)).BeginInit();
- this.SuspendLayout();
+ PlayerNameField = new ValheimServerGUI.Controls.LabelField();
+ ButtonOK = new System.Windows.Forms.Button();
+ ButtonRefresh = new System.Windows.Forms.Button();
+ PlatformIdField = new ValheimServerGUI.Controls.LabelField();
+ ZdoIdField = new ValheimServerGUI.Controls.LabelField();
+ OnlineStatusField = new ValheimServerGUI.Controls.LabelField();
+ StatusChangedField = new ValheimServerGUI.Controls.LabelField();
+ SteamIdCopyButton = new CopyButton();
+ CharacterListField = new AddRemoveListField();
+ PlatformIcon = new System.Windows.Forms.PictureBox();
+ CurrentCharacterNameField = new ValheimServerGUI.Controls.LabelField();
+ PlayerNameEditButton = new EditButton();
+ ((System.ComponentModel.ISupportInitialize)PlatformIcon).BeginInit();
+ SuspendLayout();
//
// PlayerNameField
//
- this.PlayerNameField.HelpText = resources.GetString("PlayerNameField.HelpText");
- this.PlayerNameField.LabelSplitRatio = 0.5D;
- this.PlayerNameField.LabelText = "Character Name:";
- this.PlayerNameField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.PlayerNameField.Location = new System.Drawing.Point(12, 12);
- this.PlayerNameField.Name = "PlayerNameField";
- this.PlayerNameField.Size = new System.Drawing.Size(240, 15);
- this.PlayerNameField.TabIndex = 0;
- this.PlayerNameField.Value = "";
- this.PlayerNameField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ PlayerNameField.HelpText = "The player's Steam/Xbox username. This will be determined\r\nautomatically, but in case it doesn't work, you may edit the\r\nplayer's name manually.";
+ PlayerNameField.LabelSplitRatio = 0.5D;
+ PlayerNameField.LabelText = "Player Name:";
+ PlayerNameField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ PlayerNameField.Location = new System.Drawing.Point(12, 12);
+ PlayerNameField.Name = "PlayerNameField";
+ PlayerNameField.Size = new System.Drawing.Size(240, 15);
+ PlayerNameField.TabIndex = 0;
+ PlayerNameField.Value = "";
+ PlayerNameField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// ButtonOK
//
- this.ButtonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.ButtonOK.Location = new System.Drawing.Point(202, 120);
- this.ButtonOK.Name = "ButtonOK";
- this.ButtonOK.Size = new System.Drawing.Size(75, 23);
- this.ButtonOK.TabIndex = 7;
- this.ButtonOK.Text = "OK";
- this.ButtonOK.UseVisualStyleBackColor = true;
+ ButtonOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
+ ButtonOK.Location = new System.Drawing.Point(199, 277);
+ ButtonOK.Name = "ButtonOK";
+ ButtonOK.Size = new System.Drawing.Size(75, 23);
+ ButtonOK.TabIndex = 7;
+ ButtonOK.Text = "OK";
+ ButtonOK.UseVisualStyleBackColor = true;
//
// ButtonRefresh
//
- this.ButtonRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.ButtonRefresh.Image = global::ValheimServerGUI.Properties.Resources.Restart_16x;
- this.ButtonRefresh.Location = new System.Drawing.Point(173, 120);
- this.ButtonRefresh.Name = "ButtonRefresh";
- this.ButtonRefresh.Size = new System.Drawing.Size(23, 23);
- this.ButtonRefresh.TabIndex = 6;
- this.ButtonRefresh.UseVisualStyleBackColor = true;
- //
- // SteamIdField
- //
- this.SteamIdField.HelpText = "The ID associated with the player\'s Steam account. You can use this ID to ban or " +
- "block players, or add players as admins.";
- this.SteamIdField.LabelSplitRatio = 0.5D;
- this.SteamIdField.LabelText = "Steam ID:";
- this.SteamIdField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.SteamIdField.Location = new System.Drawing.Point(12, 33);
- this.SteamIdField.Name = "SteamIdField";
- this.SteamIdField.Size = new System.Drawing.Size(240, 15);
- this.SteamIdField.TabIndex = 1;
- this.SteamIdField.Value = "";
- this.SteamIdField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ ButtonRefresh.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
+ ButtonRefresh.Image = Properties.Resources.Restart_16x;
+ ButtonRefresh.Location = new System.Drawing.Point(170, 277);
+ ButtonRefresh.Name = "ButtonRefresh";
+ ButtonRefresh.Size = new System.Drawing.Size(23, 23);
+ ButtonRefresh.TabIndex = 6;
+ ButtonRefresh.UseVisualStyleBackColor = true;
+ //
+ // PlatformIdField
+ //
+ PlatformIdField.HelpText = "The ID associated with the player's Steam or Xbox account.\r\nYou can use this ID to allow or ban players, or add players as admins.";
+ PlatformIdField.LabelSplitRatio = 0.5D;
+ PlatformIdField.LabelText = "Platform ID:";
+ PlatformIdField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ PlatformIdField.Location = new System.Drawing.Point(12, 33);
+ PlatformIdField.Name = "PlatformIdField";
+ PlatformIdField.Size = new System.Drawing.Size(240, 15);
+ PlatformIdField.TabIndex = 1;
+ PlatformIdField.Value = "";
+ PlatformIdField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// ZdoIdField
//
- this.ZdoIdField.HelpText = "The player\'s object ID in game. This changes with each game session.";
- this.ZdoIdField.LabelSplitRatio = 0.5D;
- this.ZdoIdField.LabelText = "ZDOID:";
- this.ZdoIdField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.ZdoIdField.Location = new System.Drawing.Point(12, 54);
- this.ZdoIdField.Name = "ZdoIdField";
- this.ZdoIdField.Size = new System.Drawing.Size(240, 15);
- this.ZdoIdField.TabIndex = 3;
- this.ZdoIdField.Value = "";
- this.ZdoIdField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ ZdoIdField.HelpText = "The player's object ID in game. This changes with each game session.";
+ ZdoIdField.LabelSplitRatio = 0.5D;
+ ZdoIdField.LabelText = "ZDOID:";
+ ZdoIdField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ ZdoIdField.Location = new System.Drawing.Point(12, 54);
+ ZdoIdField.Name = "ZdoIdField";
+ ZdoIdField.Size = new System.Drawing.Size(240, 15);
+ ZdoIdField.TabIndex = 3;
+ ZdoIdField.Value = "";
+ ZdoIdField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// OnlineStatusField
//
- this.OnlineStatusField.HelpText = "Possible statuses are: Online, Offline, Joining, or Leaving";
- this.OnlineStatusField.LabelSplitRatio = 0.5D;
- this.OnlineStatusField.LabelText = "Online Status:";
- this.OnlineStatusField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.OnlineStatusField.Location = new System.Drawing.Point(12, 75);
- this.OnlineStatusField.Name = "OnlineStatusField";
- this.OnlineStatusField.Size = new System.Drawing.Size(240, 15);
- this.OnlineStatusField.TabIndex = 4;
- this.OnlineStatusField.Value = "";
- this.OnlineStatusField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ OnlineStatusField.HelpText = "Possible statuses are: Online, Offline, Joining, or Leaving";
+ OnlineStatusField.LabelSplitRatio = 0.5D;
+ OnlineStatusField.LabelText = "Online Status:";
+ OnlineStatusField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ OnlineStatusField.Location = new System.Drawing.Point(12, 96);
+ OnlineStatusField.Name = "OnlineStatusField";
+ OnlineStatusField.Size = new System.Drawing.Size(240, 15);
+ OnlineStatusField.TabIndex = 4;
+ OnlineStatusField.Value = "";
+ OnlineStatusField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// StatusChangedField
//
- this.StatusChangedField.HelpText = "";
- this.StatusChangedField.LabelSplitRatio = 0.5D;
- this.StatusChangedField.LabelText = "Status Changed:";
- this.StatusChangedField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
- this.StatusChangedField.Location = new System.Drawing.Point(12, 96);
- this.StatusChangedField.Name = "StatusChangedField";
- this.StatusChangedField.Size = new System.Drawing.Size(240, 15);
- this.StatusChangedField.TabIndex = 5;
- this.StatusChangedField.Value = "";
- this.StatusChangedField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
- //
- // SteamIdWarningIcon
- //
- this.SteamIdWarningIcon.Image = global::ValheimServerGUI.Properties.Resources.StatusWarning_16x;
- this.SteamIdWarningIcon.Location = new System.Drawing.Point(258, 12);
- this.SteamIdWarningIcon.Name = "SteamIdWarningIcon";
- this.SteamIdWarningIcon.Size = new System.Drawing.Size(16, 16);
- this.SteamIdWarningIcon.TabIndex = 7;
- this.SteamIdWarningIcon.TabStop = false;
- this.SteamIdWarningIcon.Visible = false;
+ StatusChangedField.HelpText = "";
+ StatusChangedField.LabelSplitRatio = 0.5D;
+ StatusChangedField.LabelText = "Status Changed:";
+ StatusChangedField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ StatusChangedField.Location = new System.Drawing.Point(12, 117);
+ StatusChangedField.Name = "StatusChangedField";
+ StatusChangedField.Size = new System.Drawing.Size(240, 15);
+ StatusChangedField.TabIndex = 5;
+ StatusChangedField.Value = "";
+ StatusChangedField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
//
// SteamIdCopyButton
//
- this.SteamIdCopyButton.CopyFunction = null;
- this.SteamIdCopyButton.Location = new System.Drawing.Point(258, 34);
- this.SteamIdCopyButton.Name = "SteamIdCopyButton";
- this.SteamIdCopyButton.Size = new System.Drawing.Size(16, 16);
- this.SteamIdCopyButton.TabIndex = 2;
- this.SteamIdCopyButton.TabStop = false;
- this.SteamIdCopyButton.HelpText = "Copy Steam ID to clipboard";
+ SteamIdCopyButton.CopyFunction = null;
+ SteamIdCopyButton.HelpText = "Copy Steam ID to clipboard";
+ SteamIdCopyButton.Location = new System.Drawing.Point(258, 34);
+ SteamIdCopyButton.Name = "SteamIdCopyButton";
+ SteamIdCopyButton.Size = new System.Drawing.Size(16, 16);
+ SteamIdCopyButton.TabIndex = 2;
+ SteamIdCopyButton.TabStop = false;
+ //
+ // CharacterListField
+ //
+ CharacterListField.AddEnabled = true;
+ CharacterListField.AddFunction = null;
+ CharacterListField.AllowDuplicates = false;
+ CharacterListField.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ CharacterListField.EditEnabled = true;
+ CharacterListField.EditFunction = null;
+ CharacterListField.HelpText = resources.GetString("CharacterListField.HelpText");
+ CharacterListField.LabelText = "Known Characters";
+ CharacterListField.Location = new System.Drawing.Point(12, 138);
+ CharacterListField.Name = "CharacterListField";
+ CharacterListField.RemoveEnabled = true;
+ CharacterListField.RemoveFunction = null;
+ CharacterListField.Size = new System.Drawing.Size(265, 133);
+ CharacterListField.TabIndex = 8;
+ CharacterListField.Value = null;
+ //
+ // PlatformIcon
+ //
+ PlatformIcon.ErrorImage = null;
+ PlatformIcon.InitialImage = null;
+ PlatformIcon.Location = new System.Drawing.Point(38, 11);
+ PlatformIcon.Name = "PlatformIcon";
+ PlatformIcon.Size = new System.Drawing.Size(16, 16);
+ PlatformIcon.TabIndex = 9;
+ PlatformIcon.TabStop = false;
+ //
+ // CurrentCharacterNameField
+ //
+ CurrentCharacterNameField.HelpText = "The character that this player is currently playing, or\r\nif they're offline, the last character they logged in as.";
+ CurrentCharacterNameField.LabelSplitRatio = 0.5D;
+ CurrentCharacterNameField.LabelText = "Latest Character:";
+ CurrentCharacterNameField.LabelTextAlign = System.Drawing.ContentAlignment.TopRight;
+ CurrentCharacterNameField.Location = new System.Drawing.Point(12, 75);
+ CurrentCharacterNameField.Name = "CurrentCharacterNameField";
+ CurrentCharacterNameField.Size = new System.Drawing.Size(240, 15);
+ CurrentCharacterNameField.TabIndex = 10;
+ CurrentCharacterNameField.Value = "";
+ CurrentCharacterNameField.ValueTextAlign = System.Drawing.ContentAlignment.TopLeft;
+ //
+ // PlayerNameEditButton
+ //
+ PlayerNameEditButton.EditFunction = null;
+ PlayerNameEditButton.HelpText = "Edit Player Name";
+ PlayerNameEditButton.Location = new System.Drawing.Point(258, 12);
+ PlayerNameEditButton.Name = "PlayerNameEditButton";
+ PlayerNameEditButton.Size = new System.Drawing.Size(16, 16);
+ PlayerNameEditButton.TabIndex = 11;
//
// PlayerDetailsForm
//
- this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(289, 155);
- this.Controls.Add(this.SteamIdCopyButton);
- this.Controls.Add(this.SteamIdWarningIcon);
- this.Controls.Add(this.StatusChangedField);
- this.Controls.Add(this.OnlineStatusField);
- this.Controls.Add(this.ZdoIdField);
- this.Controls.Add(this.SteamIdField);
- this.Controls.Add(this.ButtonRefresh);
- this.Controls.Add(this.ButtonOK);
- this.Controls.Add(this.PlayerNameField);
- this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
- this.MaximizeBox = false;
- this.MinimizeBox = false;
- this.Name = "PlayerDetailsForm";
- this.ShowInTaskbar = false;
- this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
- this.Text = "Player Info";
- ((System.ComponentModel.ISupportInitialize)(this.SteamIdWarningIcon)).EndInit();
- this.ResumeLayout(false);
-
+ AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ ClientSize = new System.Drawing.Size(289, 320);
+ Controls.Add(PlayerNameEditButton);
+ Controls.Add(CurrentCharacterNameField);
+ Controls.Add(PlatformIcon);
+ Controls.Add(CharacterListField);
+ Controls.Add(SteamIdCopyButton);
+ Controls.Add(StatusChangedField);
+ Controls.Add(OnlineStatusField);
+ Controls.Add(ZdoIdField);
+ Controls.Add(PlatformIdField);
+ Controls.Add(ButtonRefresh);
+ Controls.Add(ButtonOK);
+ Controls.Add(PlayerNameField);
+ FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ MaximizeBox = false;
+ MinimizeBox = false;
+ Name = "PlayerDetailsForm";
+ ShowInTaskbar = false;
+ StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ Text = "Player Info";
+ ((System.ComponentModel.ISupportInitialize)PlatformIcon).EndInit();
+ ResumeLayout(false);
}
#endregion
@@ -179,11 +223,14 @@ private void InitializeComponent()
private ValheimServerGUI.Controls.LabelField PlayerNameField;
private System.Windows.Forms.Button ButtonOK;
private System.Windows.Forms.Button ButtonRefresh;
- private ValheimServerGUI.Controls.LabelField SteamIdField;
+ private ValheimServerGUI.Controls.LabelField PlatformIdField;
private ValheimServerGUI.Controls.LabelField ZdoIdField;
private ValheimServerGUI.Controls.LabelField OnlineStatusField;
private ValheimServerGUI.Controls.LabelField StatusChangedField;
- private System.Windows.Forms.PictureBox SteamIdWarningIcon;
private CopyButton SteamIdCopyButton;
+ private AddRemoveListField CharacterListField;
+ private System.Windows.Forms.PictureBox PlatformIcon;
+ private ValheimServerGUI.Controls.LabelField CurrentCharacterNameField;
+ private EditButton PlayerNameEditButton;
}
}
\ No newline at end of file
diff --git a/ValheimServerGUI/Forms/PlayerDetailsForm.cs b/ValheimServerGUI/Forms/PlayerDetailsForm.cs
index b10cbc5..95eed46 100644
--- a/ValheimServerGUI/Forms/PlayerDetailsForm.cs
+++ b/ValheimServerGUI/Forms/PlayerDetailsForm.cs
@@ -1,16 +1,26 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Windows.Forms;
using ValheimServerGUI.Game;
+using ValheimServerGUI.Properties;
using ValheimServerGUI.Tools;
+using ValheimServerGUI.Tools.Models;
namespace ValheimServerGUI.Forms
{
public partial class PlayerDetailsForm : Form
{
+ //private const string CharacterMatchConfidentSuffix = " (!)";
+ private const string NotAvailable = "N/A";
+ private const string ValidatePlayerNameText = "Name must be between 0-64 characters.";
+
private readonly IPlayerDataRepository PlayerDataProvider;
private PlayerInfo Player;
+ private bool FormDirty;
+
public PlayerDetailsForm(IPlayerDataRepository playerDataProvider)
{
PlayerDataProvider = playerDataProvider;
@@ -18,39 +28,203 @@ public PlayerDetailsForm(IPlayerDataRepository playerDataProvider)
InitializeComponent();
this.AddApplicationIcon();
+ PlayerNameEditButton.EditFunction = ButtonEditPlayerName_Click;
+ SteamIdCopyButton.CopyFunction = () => Player?.PlayerId;
+
+ CharacterListField.ItemsChanged += CharacterListField_ItemsChanged;
+ CharacterListField.AddFunction = CharacterListFieldAdd_Click;
+ CharacterListField.EditFunction = CharacterListFieldEdit_Click;
+ CharacterListField.RemoveFunction = CharacterListFieldRemove_Click;
+
ButtonRefresh.Click += ButtonRefresh_Click;
ButtonOK.Click += ButtonOK_Click;
- SteamIdCopyButton.CopyFunction = () => Player?.SteamId;
+
+ FormDirty = false;
}
- private void ButtonRefresh_Click(object sender, EventArgs e)
+ public void SetPlayerData(PlayerInfo player)
{
+ // Pull fresh data from provider
+ Player = PlayerDataProvider.FindById(player.Key);
RefreshPlayerData();
+
+ FormDirty = false;
}
- private void ButtonOK_Click(object sender, EventArgs e)
+ #region Form events
+
+ protected override void OnFormClosing(FormClosingEventArgs e)
{
- Close();
+ base.OnFormClosing(e);
+
+ if (e.CloseReason != CloseReason.UserClosing) return;
+
+ if (FormDirty)
+ {
+ var result = MessageBox.Show(
+ "Save changes to player data?",
+ "Unsaved Changes",
+ MessageBoxButtons.YesNoCancel,
+ MessageBoxIcon.Warning);
+
+ switch (result)
+ {
+ case DialogResult.Yes:
+ SavePlayerData();
+ break;
+ case DialogResult.No:
+ break;
+ case DialogResult.Cancel:
+ e.Cancel = true;
+ break;
+ }
+ }
}
- public void SetPlayerData(PlayerInfo player)
+ private void ButtonEditPlayerName_Click()
+ {
+ var result = TextPromptPopout.Prompt(
+ "Edit Player Name",
+ $"Enter the player's {Player.Platform} username:",
+ Player.PlayerName,
+ ValidatePlayerNameText,
+ ValidatePlayerName);
+
+ if (result == null || result == PlayerNameField.Value) return;
+
+ PlayerNameField.Value = result;
+ FormDirty = true;
+ }
+
+ private void CharacterListField_ItemsChanged()
+ {
+ FormDirty = true;
+ }
+
+ private string CharacterListFieldAdd_Click()
+ {
+ return TextPromptPopout.Prompt(
+ "Add Character",
+ "Add a Valheim character name for this player:",
+ null,
+ ValidatePlayerNameText,
+ ValidatePlayerName);
+ }
+
+ private string CharacterListFieldEdit_Click(string selected)
+ {
+ return TextPromptPopout.Prompt(
+ "Edit Character",
+ $"Edit the name for character '{selected}'",
+ ParseCharacterName(selected),
+ ValidatePlayerNameText,
+ ValidatePlayerName);
+ }
+
+ private bool CharacterListFieldRemove_Click(string selected)
+ {
+ // todo: Do I need to check if they're currently playing this character?
+ // Will removing a character mess up logging/status updates?
+ return true;
+ }
+
+ private void ButtonRefresh_Click(object sender, EventArgs e)
{
- // Pull fresh data from provider
- Player = PlayerDataProvider.FindById(player.Key);
RefreshPlayerData();
}
- public void RefreshPlayerData()
+ private void ButtonOK_Click(object sender, EventArgs e)
+ {
+ SavePlayerData();
+ Close();
+ }
+
+ #endregion
+
+ #region Non-public methods
+
+ private void RefreshPlayerData()
{
if (Player == null) return;
- PlayerNameField.Value = Player.PlayerName ?? "(unknown)";
- SteamIdField.Value = Player.SteamId;
- ZdoIdField.Value = Player.ZdoId ?? "N/A";
+ PlayerNameField.Value = Player.PlayerName ?? NotAvailable;
+ PlatformIdField.Value = Player.PlayerId;
+ ZdoIdField.Value = Player.ZdoId ?? NotAvailable;
+ CurrentCharacterNameField.Value = Player.LastStatusCharacter ?? NotAvailable;
OnlineStatusField.Value = Player.PlayerStatus.ToString();
StatusChangedField.Value = new TimeAgo(Player.LastStatusChange).ToString();
- SteamIdWarningIcon.Visible = !Player.MatchConfident;
+ var characterNames = Player.Characters.Select(GetCharacterDisplayName);
+ CharacterListField.SetItems(characterNames);
+
+ if (Player.Platform == PlayerPlatforms.Steam)
+ {
+ PlatformIcon.Image = Resources.Steam_16x;
+ }
+ else if (Player.Platform == PlayerPlatforms.Xbox)
+ {
+ PlatformIcon.Image = Resources.XboxLive_16x;
+ }
+ }
+
+ private void SavePlayerData()
+ {
+ if (!FormDirty) return;
+
+ var newCharacters = new List();
+ foreach (var characterName in CharacterListField.GetItems())
+ {
+ var existing = Player.Characters.FirstOrDefault(c => c.CharacterName == characterName);
+ if (existing != null)
+ {
+ newCharacters.Add(existing);
+ }
+ else
+ {
+ newCharacters.Add(new()
+ {
+ CharacterName = characterName,
+ MatchConfident = true,
+ });
+ }
+ }
+
+ Player.PlayerName = PlayerNameField.Value;
+ Player.Characters = newCharacters;
+
+ PlayerDataProvider.Upsert(Player);
+
+ FormDirty = false;
+ }
+
+ private bool ValidatePlayerName(string input)
+ {
+ // This is just a precaution, not based on any specification
+ return !string.IsNullOrWhiteSpace(input) && input.Length <= 64;
+ }
+
+ private string GetCharacterDisplayName(PlayerInfo.CharacterInfo characterInfo)
+ {
+ var characterName = characterInfo.CharacterName;
+
+ //if (!characterInfo.MatchConfident)
+ //{
+ // characterName += CharacterMatchConfidentSuffix;
+ //}
+
+ return characterName;
+ }
+
+ private string ParseCharacterName(string characterName)
+ {
+ //if (characterName.EndsWith(CharacterMatchConfidentSuffix))
+ //{
+ // characterName = characterName[..CharacterMatchConfidentSuffix.Length];
+ //}
+
+ return characterName;
}
+
+ #endregion
}
}
diff --git a/ValheimServerGUI/Forms/PlayerDetailsForm.resx b/ValheimServerGUI/Forms/PlayerDetailsForm.resx
index 91083d6..eed60fe 100644
--- a/ValheimServerGUI/Forms/PlayerDetailsForm.resx
+++ b/ValheimServerGUI/Forms/PlayerDetailsForm.resx
@@ -1,4 +1,64 @@
-
+
+
+
@@ -57,13 +117,14 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- The player's Valheim character name in game.
+
+ The Valheim character names that this player is known by.
+Names are automatically added to this list when a player
+joins the server, but you may modify them manually.
-NOTE: If you see a warning icon (!) to the right, it means the app was unable to
-accurately match up this player's Character Name & Steam ID - so the Steam ID
-might be wrong. The app will attempt to resolve this issue the next time the
-player logs in. See Help > Online Manual for more details.
-
+If a name appears with a (!), it means that name may not
+be matched to the correct player (due to a Valheim server
+limitation). You may remove this name if it's incorrect, or
+select the name and click Confirm to remove the warning.
\ No newline at end of file
diff --git a/ValheimServerGUI/Forms/PreferencesForm.Designer.cs b/ValheimServerGUI/Forms/PreferencesForm.Designer.cs
index e51f898..111777a 100644
--- a/ValheimServerGUI/Forms/PreferencesForm.Designer.cs
+++ b/ValheimServerGUI/Forms/PreferencesForm.Designer.cs
@@ -30,111 +30,119 @@ protected override void Dispose(bool disposing)
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PreferencesForm));
- this.ButtonCancel = new System.Windows.Forms.Button();
- this.ButtonOK = new System.Windows.Forms.Button();
- this.ButtonDefaults = new System.Windows.Forms.Button();
- this.CheckForUpdatesField = new ValheimServerGUI.Controls.CheckboxFormField();
- this.SaveProfileOnStartField = new ValheimServerGUI.Controls.CheckboxFormField();
- this.StartWithWindowsField = new ValheimServerGUI.Controls.CheckboxFormField();
- this.StartMinimizedField = new ValheimServerGUI.Controls.CheckboxFormField();
- this.SuspendLayout();
+ ButtonCancel = new System.Windows.Forms.Button();
+ ButtonOK = new System.Windows.Forms.Button();
+ ButtonDefaults = new System.Windows.Forms.Button();
+ CheckForUpdatesField = new ValheimServerGUI.Controls.CheckboxFormField();
+ SaveProfileOnStartField = new ValheimServerGUI.Controls.CheckboxFormField();
+ StartWithWindowsField = new ValheimServerGUI.Controls.CheckboxFormField();
+ StartMinimizedField = new ValheimServerGUI.Controls.CheckboxFormField();
+ WriteLogFileField = new ValheimServerGUI.Controls.CheckboxFormField();
+ SuspendLayout();
//
// ButtonCancel
//
- this.ButtonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.ButtonCancel.Location = new System.Drawing.Point(272, 182);
- this.ButtonCancel.Name = "ButtonCancel";
- this.ButtonCancel.Size = new System.Drawing.Size(75, 23);
- this.ButtonCancel.TabIndex = 6;
- this.ButtonCancel.Text = "Cancel";
- this.ButtonCancel.UseVisualStyleBackColor = true;
- this.ButtonCancel.Click += new System.EventHandler(this.ButtonCancel_Click);
+ ButtonCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
+ ButtonCancel.Location = new System.Drawing.Point(272, 182);
+ ButtonCancel.Name = "ButtonCancel";
+ ButtonCancel.Size = new System.Drawing.Size(75, 23);
+ ButtonCancel.TabIndex = 7;
+ ButtonCancel.Text = "Cancel";
+ ButtonCancel.UseVisualStyleBackColor = true;
+ ButtonCancel.Click += ButtonCancel_Click;
//
// ButtonOK
//
- this.ButtonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
- this.ButtonOK.Location = new System.Drawing.Point(191, 182);
- this.ButtonOK.Name = "ButtonOK";
- this.ButtonOK.Size = new System.Drawing.Size(75, 23);
- this.ButtonOK.TabIndex = 5;
- this.ButtonOK.Text = "OK";
- this.ButtonOK.UseVisualStyleBackColor = true;
- this.ButtonOK.Click += new System.EventHandler(this.ButtonOK_Click);
+ ButtonOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
+ ButtonOK.Location = new System.Drawing.Point(191, 182);
+ ButtonOK.Name = "ButtonOK";
+ ButtonOK.Size = new System.Drawing.Size(75, 23);
+ ButtonOK.TabIndex = 6;
+ ButtonOK.Text = "OK";
+ ButtonOK.UseVisualStyleBackColor = true;
+ ButtonOK.Click += ButtonOK_Click;
//
// ButtonDefaults
//
- this.ButtonDefaults.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.ButtonDefaults.Location = new System.Drawing.Point(12, 182);
- this.ButtonDefaults.Name = "ButtonDefaults";
- this.ButtonDefaults.Size = new System.Drawing.Size(111, 23);
- this.ButtonDefaults.TabIndex = 4;
- this.ButtonDefaults.Text = "Restore Defaults";
- this.ButtonDefaults.UseVisualStyleBackColor = true;
- this.ButtonDefaults.Click += new System.EventHandler(this.ButtonDefaults_Click);
+ ButtonDefaults.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
+ ButtonDefaults.Location = new System.Drawing.Point(12, 182);
+ ButtonDefaults.Name = "ButtonDefaults";
+ ButtonDefaults.Size = new System.Drawing.Size(111, 23);
+ ButtonDefaults.TabIndex = 5;
+ ButtonDefaults.Text = "Restore Defaults";
+ ButtonDefaults.UseVisualStyleBackColor = true;
+ ButtonDefaults.Click += ButtonDefaults_Click;
//
// CheckForUpdatesField
//
- this.CheckForUpdatesField.HelpText = resources.GetString("CheckForUpdatesField.HelpText");
- this.CheckForUpdatesField.LabelText = "Automatically check for updates";
- this.CheckForUpdatesField.Location = new System.Drawing.Point(12, 35);
- this.CheckForUpdatesField.Name = "CheckForUpdatesField";
- this.CheckForUpdatesField.Size = new System.Drawing.Size(334, 17);
- this.CheckForUpdatesField.TabIndex = 1;
- this.CheckForUpdatesField.Value = false;
+ CheckForUpdatesField.HelpText = resources.GetString("CheckForUpdatesField.HelpText");
+ CheckForUpdatesField.LabelText = "Automatically check for updates";
+ CheckForUpdatesField.Location = new System.Drawing.Point(12, 35);
+ CheckForUpdatesField.Name = "CheckForUpdatesField";
+ CheckForUpdatesField.Size = new System.Drawing.Size(334, 17);
+ CheckForUpdatesField.TabIndex = 1;
+ CheckForUpdatesField.Value = false;
//
// SaveProfileOnStartField
//
- this.SaveProfileOnStartField.HelpText = "If enabled, any changes you made to your server profile\r\nwill be saved when you c" +
- "lick Start Server. Otherwise, you\r\nmust manually save changes with File > Save.";
- this.SaveProfileOnStartField.LabelText = "Auto save profile when starting server";
- this.SaveProfileOnStartField.Location = new System.Drawing.Point(12, 12);
- this.SaveProfileOnStartField.Name = "SaveProfileOnStartField";
- this.SaveProfileOnStartField.Size = new System.Drawing.Size(334, 17);
- this.SaveProfileOnStartField.TabIndex = 0;
- this.SaveProfileOnStartField.Value = false;
+ SaveProfileOnStartField.HelpText = "If enabled, any changes you made to your server profile\r\nwill be saved when you click Start Server. Otherwise, you\r\nmust manually save changes with File > Save.";
+ SaveProfileOnStartField.LabelText = "Auto save profile when starting server";
+ SaveProfileOnStartField.Location = new System.Drawing.Point(12, 12);
+ SaveProfileOnStartField.Name = "SaveProfileOnStartField";
+ SaveProfileOnStartField.Size = new System.Drawing.Size(334, 17);
+ SaveProfileOnStartField.TabIndex = 0;
+ SaveProfileOnStartField.Value = false;
//
// StartWithWindowsField
//
- this.StartWithWindowsField.HelpText = "To start your server(s) on Windows startup, enable this setting \r\nalong with \"Sta" +
- "rt this server when ValheimServerGUI starts\"\r\nunder Advanced Controls for each s" +
- "erver.";
- this.StartWithWindowsField.LabelText = "Start ValheimServerGUI with Windows";
- this.StartWithWindowsField.Location = new System.Drawing.Point(12, 58);
- this.StartWithWindowsField.Name = "StartWithWindowsField";
- this.StartWithWindowsField.Size = new System.Drawing.Size(334, 17);
- this.StartWithWindowsField.TabIndex = 2;
- this.StartWithWindowsField.Value = false;
+ StartWithWindowsField.HelpText = "To start your server(s) on Windows startup, enable this setting \r\nalong with \"Start this server when ValheimServerGUI starts\"\r\nunder Advanced Controls for each server.";
+ StartWithWindowsField.LabelText = "Start ValheimServerGUI with Windows";
+ StartWithWindowsField.Location = new System.Drawing.Point(12, 81);
+ StartWithWindowsField.Name = "StartWithWindowsField";
+ StartWithWindowsField.Size = new System.Drawing.Size(334, 17);
+ StartWithWindowsField.TabIndex = 3;
+ StartWithWindowsField.Value = false;
//
// StartMinimizedField
//
- this.StartMinimizedField.HelpText = "";
- this.StartMinimizedField.LabelText = "Start ValheimServerGUI minimized";
- this.StartMinimizedField.Location = new System.Drawing.Point(12, 81);
- this.StartMinimizedField.Name = "StartMinimizedField";
- this.StartMinimizedField.Size = new System.Drawing.Size(334, 17);
- this.StartMinimizedField.TabIndex = 3;
- this.StartMinimizedField.Value = false;
+ StartMinimizedField.HelpText = "";
+ StartMinimizedField.LabelText = "Start ValheimServerGUI minimized";
+ StartMinimizedField.Location = new System.Drawing.Point(12, 104);
+ StartMinimizedField.Name = "StartMinimizedField";
+ StartMinimizedField.Size = new System.Drawing.Size(334, 17);
+ StartMinimizedField.TabIndex = 4;
+ StartMinimizedField.Value = false;
+ //
+ // WriteLogFileField
+ //
+ WriteLogFileField.HelpText = resources.GetString("WriteLogFileField.HelpText");
+ WriteLogFileField.LabelText = "Write application logs to file";
+ WriteLogFileField.Location = new System.Drawing.Point(12, 58);
+ WriteLogFileField.Name = "WriteLogFileField";
+ WriteLogFileField.Size = new System.Drawing.Size(334, 17);
+ WriteLogFileField.TabIndex = 2;
+ WriteLogFileField.Value = false;
//
// PreferencesForm
//
- this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(359, 217);
- this.Controls.Add(this.StartMinimizedField);
- this.Controls.Add(this.StartWithWindowsField);
- this.Controls.Add(this.SaveProfileOnStartField);
- this.Controls.Add(this.CheckForUpdatesField);
- this.Controls.Add(this.ButtonDefaults);
- this.Controls.Add(this.ButtonOK);
- this.Controls.Add(this.ButtonCancel);
- this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
- this.MaximizeBox = false;
- this.MinimizeBox = false;
- this.Name = "PreferencesForm";
- this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
- this.Text = "Preferences";
- this.ResumeLayout(false);
-
+ AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ ClientSize = new System.Drawing.Size(359, 217);
+ Controls.Add(WriteLogFileField);
+ Controls.Add(StartMinimizedField);
+ Controls.Add(StartWithWindowsField);
+ Controls.Add(SaveProfileOnStartField);
+ Controls.Add(CheckForUpdatesField);
+ Controls.Add(ButtonDefaults);
+ Controls.Add(ButtonOK);
+ Controls.Add(ButtonCancel);
+ FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+ MaximizeBox = false;
+ MinimizeBox = false;
+ Name = "PreferencesForm";
+ StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ Text = "Preferences";
+ ResumeLayout(false);
}
#endregion
@@ -145,5 +153,6 @@ private void InitializeComponent()
private ValheimServerGUI.Controls.CheckboxFormField SaveProfileOnStartField;
private ValheimServerGUI.Controls.CheckboxFormField StartWithWindowsField;
private ValheimServerGUI.Controls.CheckboxFormField StartMinimizedField;
+ private ValheimServerGUI.Controls.CheckboxFormField WriteLogFileField;
}
}
\ No newline at end of file
diff --git a/ValheimServerGUI/Forms/PreferencesForm.cs b/ValheimServerGUI/Forms/PreferencesForm.cs
index 8a9e328..720cbe4 100644
--- a/ValheimServerGUI/Forms/PreferencesForm.cs
+++ b/ValheimServerGUI/Forms/PreferencesForm.cs
@@ -1,16 +1,16 @@
-using Microsoft.Extensions.Logging;
-using System;
+using System;
using System.Windows.Forms;
using ValheimServerGUI.Game;
using ValheimServerGUI.Properties;
using ValheimServerGUI.Tools;
+using ValheimServerGUI.Tools.Logging;
namespace ValheimServerGUI.Forms
{
public partial class PreferencesForm : Form
{
private readonly IUserPreferencesProvider UserPrefsProvider;
- private readonly ILogger Logger;
+ private readonly IApplicationLogger Logger;
public PreferencesForm()
{
@@ -18,7 +18,7 @@ public PreferencesForm()
this.AddApplicationIcon();
}
- public PreferencesForm(IUserPreferencesProvider userPrefsProvider, ILogger logger) : this()
+ public PreferencesForm(IUserPreferencesProvider userPrefsProvider, IApplicationLogger logger) : this()
{
UserPrefsProvider = userPrefsProvider;
Logger = logger;
@@ -39,6 +39,7 @@ private void InitializeFormFields()
CheckForUpdatesField.Value = prefs.CheckForUpdates;
StartWithWindowsField.Value = prefs.StartWithWindows;
StartMinimizedField.Value = prefs.StartMinimized;
+ WriteLogFileField.Value = prefs.WriteApplicationLogsToFile;
var startupInterval = TimeSpan.Parse(Resources.UpdateCheckInterval);
CheckForUpdatesField.HelpText = CheckForUpdatesField.HelpText?.Replace("{startupInterval}", $"{startupInterval.TotalHours} hours");
@@ -52,6 +53,7 @@ private void ButtonOK_Click(object sender, EventArgs e)
prefs.CheckForUpdates = CheckForUpdatesField.Value;
prefs.StartWithWindows = StartWithWindowsField.Value;
prefs.StartMinimized = StartMinimizedField.Value;
+ prefs.WriteApplicationLogsToFile = WriteLogFileField.Value;
StartupHelper.ApplyStartupSetting(prefs.StartWithWindows, Logger);
@@ -72,6 +74,7 @@ private void ButtonDefaults_Click(object sender, EventArgs e)
CheckForUpdatesField.Value = prefs.CheckForUpdates;
StartWithWindowsField.Value = prefs.StartWithWindows;
StartMinimizedField.Value = prefs.StartMinimized;
+ WriteLogFileField.Value = prefs.WriteApplicationLogsToFile;
}
}
}
diff --git a/ValheimServerGUI/Forms/PreferencesForm.resx b/ValheimServerGUI/Forms/PreferencesForm.resx
index 4b74680..519bc4c 100644
--- a/ValheimServerGUI/Forms/PreferencesForm.resx
+++ b/ValheimServerGUI/Forms/PreferencesForm.resx
@@ -63,4 +63,13 @@ when the app starts up, and again every {startupInterval}.
If disabled, you can check for updates anytime from Help > Check for updates.
+
+ If enabled, any application logs from ValheimServerGUI
+will be written to a daily rolling log file on disk. Logs older
+than 30 days will be deleted automatically.
+
+Note: this setting does not affect your server's logs.
+You can toggle server logs under the Advanced Controls
+tab for each server profile.
+
\ No newline at end of file
diff --git a/ValheimServerGUI/Forms/SplashForm.cs b/ValheimServerGUI/Forms/SplashForm.cs
index f7ef02f..ffe0ee0 100644
--- a/ValheimServerGUI/Forms/SplashForm.cs
+++ b/ValheimServerGUI/Forms/SplashForm.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.Logging;
+using Serilog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -99,7 +99,7 @@ public MainWindow CreateNewMainWindow(string startProfile, bool startServer)
mainWindow.SplashIndex = MainWindows.Count;
MainWindows.Add(mainWindow);
- Logger.LogDebug("Created {name} [{index}] for profile {name}", nameof(MainWindow), mainWindow.SplashIndex, startProfile);
+ Logger.Debug("Created {name} [{index}] for profile {name}", nameof(MainWindow), mainWindow.SplashIndex, startProfile);
return mainWindow;
}
@@ -161,7 +161,7 @@ private void OnTaskFinished(Task task)
if (!task.IsCompletedSuccessfully)
{
- Logger.LogWarning("Error encountered during startup task");
+ Logger.Warning("Error encountered during startup task");
HandleException(task.Exception, "Startup Task Exception", true);
return;
}
@@ -208,18 +208,18 @@ private void OnMainWindowClosed(object sender, FormClosedEventArgs e)
if (sender is not MainWindow mainWindow) return;
- Logger.LogDebug("Closed {name} [{index}]", nameof(MainWindow), mainWindow.SplashIndex);
+ Logger.Debug("Closed {name} [{index}]", nameof(MainWindow), mainWindow.SplashIndex);
MainWindows[mainWindow.SplashIndex] = null;
var stillOpen = MainWindows.Count(m => m != null);
if (stillOpen > 0)
{
- Logger.LogDebug("{stillOpen} windows are still open", stillOpen);
+ Logger.Debug("{stillOpen} windows are still open", stillOpen);
return;
}
- Logger.LogDebug($"All windows closed, shutting down application");
+ Logger.Debug($"All windows closed, shutting down application");
Close();
}
@@ -233,7 +233,7 @@ private void PrepareMainWindows()
var autoStartServers = allPrefs.Where(p => p != null && p.AutoStart);
if (autoStartServers.Any())
{
- Logger.LogInformation("Loading server profiles with auto-start enabled");
+ Logger.Information("Loading server profiles with auto-start enabled");
foreach (var autoStartServer in autoStartServers)
{
CreateNewMainWindow(autoStartServer.ProfileName, true);
@@ -244,14 +244,14 @@ private void PrepareMainWindows()
var lastSavedServer = allPrefs.OrderByDescending(p => p.LastSaved).FirstOrDefault();
if (lastSavedServer != null)
{
- Logger.LogInformation("Loading most recently saved profile: {name}", lastSavedServer.ProfileName);
+ Logger.Information("Loading most recently saved profile: {name}", lastSavedServer.ProfileName);
CreateNewMainWindow(lastSavedServer.ProfileName, false);
return;
}
var newPrefs = new ServerPreferences { ProfileName = Resources.DefaultServerProfileName };
ServerPrefsProvider.SavePreferences(newPrefs);
- Logger.LogInformation("User preferences not found, creating new file");
+ Logger.Information("User preferences not found, creating new file");
CreateNewMainWindow(newPrefs.ProfileName, false);
}
@@ -259,12 +259,12 @@ private void AddStartupTask(Func taskFunc, string taskName)
{
StartupTasks.Add(async () =>
{
- Logger.LogDebug("Starting startup task: {name}", taskName);
+ Logger.Debug("Starting startup task: {name}", taskName);
var sw = Stopwatch.StartNew();
await taskFunc();
- Logger.LogDebug("Finished startup task: {name} ({dur}ms)", taskName, sw.ElapsedMilliseconds);
+ Logger.Debug("Finished startup task: {name} ({dur}ms)", taskName, sw.ElapsedMilliseconds);
});
}
@@ -315,7 +315,7 @@ private bool VersionCheck()
if (dotnetVersion.Major < 6)
{
- Logger.LogWarning($"Incompatible .NET version detected: {dotnetVersion}");
+ Logger.Warning("Incompatible .NET version detected: {dotnetVersion}", dotnetVersion);
var nl = Environment.NewLine;
var result = MessageBox.Show(
@@ -339,7 +339,7 @@ private bool VersionCheck()
private void HandleException(Exception exception, string contextMessage, bool closeAfterHandle)
{
- Logger.LogError($"Encountered exception - {exception.GetType().Name}: {exception.Message}");
+ Logger.Error("Encountered exception - {typeName}: {message}", exception.GetType().Name, exception.Message);
CloseAfterExceptionHandled = closeAfterHandle;
diff --git a/ValheimServerGUI/Forms/TextPromptPopout.cs b/ValheimServerGUI/Forms/TextPromptPopout.cs
index a1a8161..ea607cd 100644
--- a/ValheimServerGUI/Forms/TextPromptPopout.cs
+++ b/ValheimServerGUI/Forms/TextPromptPopout.cs
@@ -35,6 +35,19 @@ public void SetValidation(string helpText, Func onValidate)
OnValidate = onValidate;
}
+ public static string Prompt(
+ string title,
+ string message,
+ string startingText = null,
+ string helpText = null,
+ Func onValidate = null)
+ {
+ var popout = new TextPromptPopout(title, message, startingText);
+ popout.SetValidation(helpText, onValidate);
+ popout.ShowDialog();
+ return popout.Value;
+ }
+
#region Form events
private void ButtonOK_Click(object sender, EventArgs e)
@@ -63,7 +76,7 @@ private bool ValidateInput()
string errMessage = null;
try
{
- if (!OnValidate(userInput))
+ if (OnValidate != null && !OnValidate(userInput))
{
errMessage = TextInputField.HelpText ?? "The provided string is invalid.";
}
diff --git a/ValheimServerGUI/Game/PlayerDataRepository.cs b/ValheimServerGUI/Game/PlayerDataRepository.cs
index 99d4ed3..25f8db2 100644
--- a/ValheimServerGUI/Game/PlayerDataRepository.cs
+++ b/ValheimServerGUI/Game/PlayerDataRepository.cs
@@ -1,25 +1,68 @@
-using Microsoft.Extensions.Logging;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ValheimServerGUI.Properties;
using ValheimServerGUI.Tools;
using ValheimServerGUI.Tools.Data;
+using ValheimServerGUI.Tools.Models;
namespace ValheimServerGUI.Game
{
+ public class PlayerDataQuery
+ {
+ public string Platform;
+
+ public string PlayerId;
+
+ public string PlayerName;
+
+ public string ZdoId;
+
+ public string CharacterName;
+
+ public PlayerDataQuery Or;
+
+ public override string ToString()
+ {
+ var parameters = new List();
+
+ if (!string.IsNullOrWhiteSpace(Platform)) parameters.Add($"Platform={Platform}");
+ if (!string.IsNullOrWhiteSpace(PlayerId)) parameters.Add($"PlayerId={PlayerId}");
+ if (!string.IsNullOrWhiteSpace(PlayerName)) parameters.Add($"PlayerName={PlayerName}");
+ if (!string.IsNullOrWhiteSpace(ZdoId)) parameters.Add($"ZdoId={ZdoId}");
+ if (!string.IsNullOrWhiteSpace(CharacterName)) parameters.Add($"CharacterName={CharacterName}");
+
+ var qs = string.Join("&", parameters);
+
+ if (Or != null)
+ {
+ var qs2 = Or.ToString();
+ if (!string.IsNullOrWhiteSpace(qs2))
+ {
+ qs = $"{qs}|{qs2}";
+ }
+ }
+
+ return qs;
+ }
+
+ public bool HasParameters() => !string.IsNullOrWhiteSpace(ToString());
+ }
+
public interface IPlayerDataRepository : IDataRepository
{
event EventHandler PlayerStatusChanged;
- PlayerInfo SetPlayerJoining(string steamId);
+ IEnumerable FindPlayersByQuery(PlayerDataQuery query);
+
+ PlayerInfo SetPlayerJoining(PlayerDataQuery query);
- PlayerInfo SetPlayerOnline(string name, string zdoid);
+ PlayerInfo SetPlayerOnline(string characterName, string zdoId);
- void SetPlayerLeaving(string steamOrZdoId);
+ void SetPlayerLeaving(PlayerDataQuery query);
- void SetPlayerOffline(string steamOrZdoId);
+ void SetPlayerOffline(PlayerDataQuery query);
Task LoadAsync(); // todo: find a way to automatically load data without exposing this
}
@@ -28,74 +71,127 @@ public class PlayerDataRepository : DataFileRepository, IPlayerDataR
{
public event EventHandler PlayerStatusChanged;
+ private readonly IRuneberryApiClient RuneberryApiClient;
private readonly Dictionary PlayerStatusMap = new();
private readonly Dictionary LastOfflineCache = new();
- private int JoinCount;
- public PlayerDataRepository(IDataFileRepositoryContext context)
+ public PlayerDataRepository(
+ IDataFileRepositoryContext context,
+ IRuneberryApiClient runeberryApiClient)
: base(context, Resources.PlayerListFilePath)
{
EntityUpdated += OnEntityUpdated;
+ RuneberryApiClient = runeberryApiClient;
+ RuneberryApiClient.PlayerInfoAvailable += OnPlayerInfoAvailable;
}
- public PlayerInfo SetPlayerJoining(string steamId)
+ #region IPlayerDataRepository implementation
+
+ public IEnumerable FindPlayersByQuery(PlayerDataQuery query)
{
- if (string.IsNullOrWhiteSpace(steamId)) return null;
+ var results = Data;
- // Retrieve the player w/ this SteamID who was most recently online
- var players = Data
- .Where(p => p.SteamId == steamId && p.PlayerStatus == PlayerStatus.Offline)
- .OrderByDescending(p => p.LastStatusChange);
+ if (!string.IsNullOrWhiteSpace(query.Platform))
+ {
+ results = results.Where(p => p.Platform == query.Platform);
+ }
- var player = players.FirstOrDefault();
+ if (!string.IsNullOrWhiteSpace(query.PlayerId))
+ {
+ results = results.Where(p => p.PlayerId == query.PlayerId);
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.PlayerName))
+ {
+ results = results.Where(p => p.PlayerName == query.PlayerName);
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.ZdoId))
+ {
+ results = results.Where(p => p.ZdoId == query.ZdoId);
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.CharacterName))
+ {
+ results = results.Where(p => p.Characters != null && p.Characters.Any(c => c.CharacterName == query.CharacterName));
+ }
+
+ if (query.Or != null)
+ {
+ var results2 = FindPlayersByQuery(query.Or);
+
+ results = results
+ .Concat(results2)
+ .DistinctBy(p => p.Key);
+ }
+
+ return results;
+ }
+
+ public PlayerInfo SetPlayerJoining(PlayerDataQuery query)
+ {
+ if (!query.HasParameters()) return null;
+
+ // Retrieve the player w/ this identity who was most recently online
+ var player = FindPlayersByQuery(query)
+ .Where(p => p.PlayerStatus == PlayerStatus.Offline)
+ .OrderByDescending(p => p.LastStatusChange)
+ .FirstOrDefault();
if (player == null)
{
// If we have no offline record of this player, create a new record
- player = new PlayerInfo { SteamId = steamId };
-
- Logger.LogInformation("1 player joining for SteamID {id} (new player)", steamId);
+ player = CreatePlayerFromQuery(query);
+ Logger.Information("1 new player joining as: {query}", query);
}
else
{
- Logger.LogInformation("1 player joining for SteamID {id} (existing player)", steamId);
+ Logger.Information("1 existing player joining as: {query}", query);
}
player.PlayerStatus = PlayerStatus.Joining;
player.LastStatusChange = DateTime.UtcNow;
- JoinCount++;
+ player.LastStatusCharacter = !string.IsNullOrWhiteSpace(query.CharacterName) ? query.CharacterName : null;
Upsert(player);
+ if (string.IsNullOrWhiteSpace(player.PlayerName))
+ {
+ RuneberryApiClient.RequestPlayerInfoAsync(player.Platform, player.PlayerId);
+ }
+
return player;
}
- public PlayerInfo SetPlayerOnline(string name, string zdoid)
+ public PlayerInfo SetPlayerOnline(string characterName, string zdoId)
{
- if (string.IsNullOrWhiteSpace(name)) return null;
-
PlayerInfo player = null;
var playersToSave = new List();
- var playersToRemove = new List();
- var playersWithSameName = Data
- .Where(p => p.PlayerName == name && p.PlayerStatus.IsAnyValue(PlayerStatus.Joining, PlayerStatus.Offline));
+ var playersWithCharName = Enumerable.Empty();
+ if (!string.IsNullOrWhiteSpace(characterName))
+ {
+ playersWithCharName = FindPlayersByQuery(new() { CharacterName = characterName })
+ .Where(p => p.PlayerStatus.IsAnyValue(PlayerStatus.Joining, PlayerStatus.Offline));
+ }
var joiningPlayers = Data
.Where(p => p.PlayerStatus == PlayerStatus.Joining);
- if (playersWithSameName.Count() == 1)
+ var matchConfident = true;
+
+ if (playersWithCharName.Count() == 1)
{
// One player record with this name has been seen in the past with this name, so use it
- player = playersWithSameName.Single();
- Logger.LogInformation("(PlayerOnline) Player {name} belongs to SteamID {id} (Single match by name)", name, player.SteamId);
+ player = playersWithCharName.Single();
+ Logger.Information("(PlayerOnline) Character {name} belongs to player {key} (Single match by name)", characterName, player.Key);
if (player.PlayerStatus == PlayerStatus.Offline)
{
- // If this record with this matching name was offline, then same steam player
+ // If this record with this matching name was offline, then the same player
// is logging in with a different name than the one we picked when they were joining
- var wrongJoiningPlayer = Data.Where(p => p.SteamId == player.SteamId && p.PlayerStatus == PlayerStatus.Joining).FirstOrDefault();
+ var wrongJoiningPlayer = Data.Where(p => p.Key == player.Key && p.PlayerStatus == PlayerStatus.Joining).FirstOrDefault();
- // If there was somehow no joining steamId match, just use this player anyway
+ // If there was somehow no joining player match, just use this player anyway
if (wrongJoiningPlayer != null)
{
wrongJoiningPlayer.PlayerStatus = PlayerStatus.Offline;
@@ -105,58 +201,45 @@ public PlayerInfo SetPlayerOnline(string name, string zdoid)
}
playersToSave.Add(wrongJoiningPlayer);
- Logger.LogInformation("Player {name} was not logging in after all, reverting to offline status", wrongJoiningPlayer.PlayerName);
+ Logger.Information("Player {key} was not joining after all, reverting to offline status", wrongJoiningPlayer.Key);
}
}
}
- else if (playersWithSameName.Count() > 1)
+ else if (playersWithCharName.Count() > 1)
{
// Multiple offline or joining players have been detected with the same name
- var joiningPlayersWithSameName = playersWithSameName
+ var joiningPlayersWithSameName = playersWithCharName
.Where(p => p.PlayerStatus == PlayerStatus.Joining);
if (joiningPlayersWithSameName.Count() == 1)
{
// If one of those is joining, assume that's the right player
player = joiningPlayersWithSameName.Single();
- Logger.LogInformation("(PlayerOnline) Player {name} belongs to SteamID {id} (Single joining by name)", name, player.SteamId);
+ Logger.Information("(PlayerOnline) Character {name} belongs to player {key} (Single joining by name)", characterName, player.Key);
}
else
{
// Otherwise, we cannot reliably pick which of the players by this name we should update
- Logger.LogInformation("Cannot resolve SteamID for Player {name} (Multiple joining w/ same name)", name);
+ Logger.Information("Cannot resolve identity for character {name} (Multiple joining w/ same name)", characterName);
}
}
else if (joiningPlayers.Count() == 1)
{
// No players were found joining or offline w/ this name, but there is only one joining player, so we can confirm this match
player = joiningPlayers.Single();
- Logger.LogInformation("(PlayerOnline) Player {name} belongs to SteamID {id} (Single player joining)", name, player.SteamId);
-
- if (player.PlayerName == null)
- {
- playersToRemove.Add(player.Key);
- player.PlayerName = name;
- }
- else if (player.PlayerName != name)
- {
- // Make a new record for each character that a SteamID logs in with, set the old record back to offline
- player.PlayerStatus = PlayerStatus.Offline;
- if (LastOfflineCache.TryGetValue(player.Key, out var origTimestamp))
- {
- player.LastStatusChange = origTimestamp;
- }
- playersToSave.Add(player);
-
- Logger.LogInformation("Player {name} was not logging in after all, reverting to offline status", player.PlayerName);
-
- var steamId = player.SteamId;
- player = new PlayerInfo { SteamId = steamId, PlayerName = name };
- }
+ Logger.Information("(PlayerOnline) Character {name} belongs to player {key} (Single player joining)", characterName, player.Key);
+ }
+ else if (joiningPlayers.Count() > 1)
+ {
+ // No players were found joining or offline w/ this name, and multiple players are joining at once (common case on a new server)
+ // Assume that this character belongs to the earliest joining player, but flag the match as low-confidence.
+ player = joiningPlayers.OrderBy(p => p.LastStatusChange).First();
+ matchConfident = false;
+ Logger.Information("Ambiguous identity for character {name} (Multiple players joining, no match by name, best guess: {key})", characterName, player.Key);
}
else
{
- Logger.LogInformation("Cannot resolve SteamID for Player {name} (Multiple players joining, no match by name)", name);
+ Logger.Information("Cannot resolve identity for character {name} (No players joining, no match by name)", characterName);
}
if (player != null)
@@ -164,47 +247,24 @@ public PlayerInfo SetPlayerOnline(string name, string zdoid)
// If we could actually determine which player to update, do it now
player.PlayerStatus = PlayerStatus.Online;
player.LastStatusChange = DateTime.UtcNow;
- player.MatchConfident = true;
- player.ZdoId = zdoid;
+ player.LastStatusCharacter = characterName;
+ player.ZdoId = zdoId;
+ player.AddCharacter(characterName, matchConfident);
playersToSave.Add(player);
}
- if (--JoinCount == 0)
- {
- // Once all joining players have come online, update the remaining anonymous players to an online status
- var remainingPlayers = Data.Where(p => p.PlayerStatus == PlayerStatus.Joining);
-
- if (remainingPlayers.Any())
- {
- foreach (var jp in remainingPlayers)
- {
- jp.PlayerStatus = PlayerStatus.Online;
- playersToSave.Add(jp);
- }
-
- Logger.LogInformation("(PlayerOnline) {count} anonymous player(s) entering Online status", remainingPlayers.Count());
- }
- }
-
- if (playersToRemove.Any())
- {
- RemoveBulk(playersToRemove);
- Logger.LogInformation("{count} player(s) removed", playersToSave.Count);
- }
-
if (playersToSave.Any())
{
UpsertBulk(playersToSave);
- Logger.LogInformation("{count} player(s) saved", playersToSave.Count);
+ Logger.Information("{count} player(s) saved", playersToSave.Count);
}
return player;
}
- public void SetPlayerLeaving(string steamOrZdoId)
+ public void SetPlayerLeaving(PlayerDataQuery query)
{
- var players = Data
- .Where(p => p.SteamId == steamOrZdoId || p.ZdoId == steamOrZdoId)
+ var players = FindPlayersByQuery(query)
.Where(p => p.PlayerStatus.IsAnyValue(PlayerStatus.Joining, PlayerStatus.Online))
.ToList();
@@ -219,14 +279,13 @@ public void SetPlayerLeaving(string steamOrZdoId)
UpsertBulk(players);
- Logger.LogInformation("{count} player(s) Leaving for SteamID {id}", players.Count, steamOrZdoId);
+ Logger.Information("{count} player(s) leaving as: {query}", players.Count, query);
}
}
- public void SetPlayerOffline(string steamOrZdoId)
+ public void SetPlayerOffline(PlayerDataQuery query)
{
- var players = Data
- .Where(p => p.SteamId == steamOrZdoId || p.ZdoId == steamOrZdoId)
+ var players = FindPlayersByQuery(query)
.Where(p => p.PlayerStatus != PlayerStatus.Offline)
.ToList();
@@ -241,7 +300,7 @@ public void SetPlayerOffline(string steamOrZdoId)
UpsertBulk(players);
- Logger.LogInformation("{count} player(s) Offline for SteamID {id}", players.Count, steamOrZdoId);
+ Logger.Information("{count} player(s) offline as: {query}", players.Count, query);
}
}
@@ -258,8 +317,47 @@ public override async Task LoadAsync()
}
}
+ #endregion
+
#region Non-public methods
+ private static PlayerInfo CreatePlayerFromQuery(PlayerDataQuery query, PlayerInfo player = null)
+ {
+ player ??= new PlayerInfo();
+
+ if (query.Or != null)
+ {
+ player = CreatePlayerFromQuery(query.Or, player);
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.Platform))
+ {
+ player.Platform = query.Platform;
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.PlayerId))
+ {
+ player.PlayerId = query.PlayerId;
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.PlayerName))
+ {
+ player.PlayerName = query.PlayerName;
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.ZdoId))
+ {
+ player.ZdoId = query.ZdoId;
+ }
+
+ if (!string.IsNullOrWhiteSpace(query.CharacterName))
+ {
+ player.AddCharacter(query.CharacterName);
+ }
+
+ return player;
+ }
+
private void OnEntityUpdated(object sender, PlayerInfo player)
{
bool statusChanged;
@@ -290,6 +388,34 @@ private void OnEntityUpdated(object sender, PlayerInfo player)
}
}
+ private void OnPlayerInfoAvailable(object sender, PlayerInfoResponse response)
+ {
+ if (string.IsNullOrWhiteSpace(response.Id)
+ || string.IsNullOrWhiteSpace(response.Name)
+ || string.IsNullOrWhiteSpace(response.Platform))
+ {
+ return;
+ }
+
+ var query = new PlayerDataQuery
+ {
+ Platform = response.Platform,
+ PlayerId = response.Id,
+ };
+
+ var players = FindPlayersByQuery(query);
+ foreach (var player in players)
+ {
+ if (player.PlayerName == response.Name) continue;
+
+ player.PlayerName = response.Name;
+ Logger.Information($"Player lookup successful: {player.Key}, {player.PlayerName}");
+ PlayerStatusChanged?.Invoke(this, player);
+ }
+
+ UpsertBulk(players);
+ }
+
#endregion
}
}
diff --git a/ValheimServerGUI/Game/PlayerInfo.cs b/ValheimServerGUI/Game/PlayerInfo.cs
index b4a2b58..6e1e702 100644
--- a/ValheimServerGUI/Game/PlayerInfo.cs
+++ b/ValheimServerGUI/Game/PlayerInfo.cs
@@ -1,5 +1,7 @@
using Newtonsoft.Json;
using System;
+using System.Collections.Generic;
+using System.Linq;
using ValheimServerGUI.Tools.Data;
namespace ValheimServerGUI.Game
@@ -7,26 +9,26 @@ namespace ValheimServerGUI.Game
public class PlayerInfo : IPrimaryKeyEntity
{
[JsonIgnore]
- public string Key => PlayerName == null ? SteamId : $"{SteamId}:{PlayerName}";
+ public string Key => $"{Platform}:{PlayerId}";
///
- /// The character's name as it appears within Valheim
+ /// The platform that this player is playing Valheim on.
///
- [JsonProperty("name")]
- public string PlayerName { get; set; }
+ [JsonProperty("platform")]
+ public string Platform { get; set; }
///
- /// The ID used to identify the player on Steam.
- /// The same Steam player may log in with multiple characters.
+ /// The ID used to identify the player on this platform.
+ /// The same player may log in with multiple characters.
///
- [JsonProperty("steamId")]
- public string SteamId { get; set; }
+ [JsonProperty("playerId")]
+ public string PlayerId { get; set; }
///
- /// Could we confidently match up the player's name and steamId?
+ /// The player's username on the specified platform.
///
- [JsonProperty("matchConfident")]
- public bool MatchConfident { get; set; }
+ [JsonProperty("playerName")]
+ public string PlayerName { get; set; }
///
/// The last time the player logged on to the server.
@@ -34,6 +36,15 @@ public class PlayerInfo : IPrimaryKeyEntity
[JsonProperty("lastStatusChange")]
public DateTimeOffset LastStatusChange { get; set; }
+ [JsonProperty("lastStatusCharacter")]
+ public string LastStatusCharacter { get; set; }
+
+ ///
+ /// A list of characters that this player has played in Valheim.
+ ///
+ [JsonProperty("characters")]
+ public List Characters { get; set; }
+
///
/// The player's current status on the server.
///
@@ -45,5 +56,44 @@ public class PlayerInfo : IPrimaryKeyEntity
///
[JsonIgnore]
public string ZdoId { get; set; }
+
+ public CharacterInfo AddCharacter(string characterName, bool matchConfident = true)
+ {
+ Characters ??= new();
+
+ var character = Characters.FirstOrDefault(c => c.CharacterName == characterName);
+ if (character == null)
+ {
+ character = new CharacterInfo
+ {
+ CharacterName = characterName,
+ };
+ Characters.Add(character);
+ }
+
+ character.MatchConfident = matchConfident;
+ return character;
+ }
+
+ public bool TryGetCharacter(string characterName, out CharacterInfo character)
+ {
+ character = Characters?.FirstOrDefault(c => c.CharacterName == characterName);
+ return character != null;
+ }
+
+ public class CharacterInfo
+ {
+ ///
+ /// The character's name as it appears within Valheim.
+ ///
+ [JsonProperty("characterName")]
+ public string CharacterName { get; set; }
+
+ ///
+ /// Could we confidently match up the player's name and platformId?
+ ///
+ [JsonProperty("matchConfident")]
+ public bool MatchConfident { get; set; }
+ }
}
}
diff --git a/ValheimServerGUI/Game/ServerPreferences.cs b/ValheimServerGUI/Game/ServerPreferences.cs
index c227797..497325b 100644
--- a/ValheimServerGUI/Game/ServerPreferences.cs
+++ b/ValheimServerGUI/Game/ServerPreferences.cs
@@ -37,6 +37,8 @@ public class ServerPreferences
public string SaveDataFolderPath { get; set; }
+ public bool WriteServerLogsToFile { get; set; } = true;
+
public static ServerPreferences FromFile(ServerPreferencesFile file)
{
var prefs = new ServerPreferences();
@@ -59,6 +61,7 @@ public static ServerPreferences FromFile(ServerPreferencesFile file)
prefs.AdditionalArgs = file.AdditionalArgs ?? prefs.AdditionalArgs;
prefs.ServerExePath = file.ServerExePath ?? prefs.ServerExePath;
prefs.SaveDataFolderPath = file.SaveDataFolderPath ?? prefs.SaveDataFolderPath;
+ prefs.WriteServerLogsToFile = file.WriteServerLogsToFile ?? prefs.WriteServerLogsToFile;
return prefs;
}
@@ -83,6 +86,7 @@ public ServerPreferencesFile ToFile()
AdditionalArgs = AdditionalArgs,
ServerExePath = ServerExePath,
SaveDataFolderPath = SaveDataFolderPath,
+ WriteServerLogsToFile = WriteServerLogsToFile,
};
return file;
diff --git a/ValheimServerGUI/Game/ServerPreferencesFile.cs b/ValheimServerGUI/Game/ServerPreferencesFile.cs
index 7139f3d..1efd039 100644
--- a/ValheimServerGUI/Game/ServerPreferencesFile.cs
+++ b/ValheimServerGUI/Game/ServerPreferencesFile.cs
@@ -52,5 +52,8 @@ public class ServerPreferencesFile
[JsonProperty("valheimSaveDataFolder")]
public string SaveDataFolderPath { get; set; }
+
+ [JsonProperty("writeServerLogsToFile")]
+ public bool? WriteServerLogsToFile { get; set; }
}
}
diff --git a/ValheimServerGUI/Game/ServerPreferencesProvider.cs b/ValheimServerGUI/Game/ServerPreferencesProvider.cs
index 80f10f7..4a00760 100644
--- a/ValheimServerGUI/Game/ServerPreferencesProvider.cs
+++ b/ValheimServerGUI/Game/ServerPreferencesProvider.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.Logging;
+using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -47,7 +47,7 @@ public ServerPreferences LoadPreferences(string profileName)
}
else if (prefs.Count > 1)
{
- Logger.LogWarning($"Multiple configurations found for server '{profileName}'. Returning the most recently updated one.");
+ Logger.Warning("Multiple configurations found for server '{profileName}'. Returning the most recently updated one.", profileName);
return prefs.OrderByDescending(p => p.LastSaved).First();
}
@@ -72,7 +72,7 @@ public void SavePreferences(ServerPreferences preferences)
preferences.LastSaved = DateTime.UtcNow;
UserPreferencesProvider.SavePreferences(userPrefs);
- Logger.LogInformation("Saved preferences for server profile: {profileName}", preferences.ProfileName);
+ Logger.Information("Saved preferences for server profile: {profileName}", preferences.ProfileName);
}
public void RemovePreferences(string profileName)
@@ -87,7 +87,7 @@ public void RemovePreferences(string profileName)
userPrefs.Servers.RemoveAll(p => p.ProfileName == profileName);
UserPreferencesProvider.SavePreferences(userPrefs);
- Logger.LogInformation("Removed preferences for server profile: {profileName}", profileName);
+ Logger.Information("Removed preferences for server profile: {profileName}", profileName);
}
}
diff --git a/ValheimServerGUI/Game/UserPreferences.cs b/ValheimServerGUI/Game/UserPreferences.cs
index 1142597..6f533d3 100644
--- a/ValheimServerGUI/Game/UserPreferences.cs
+++ b/ValheimServerGUI/Game/UserPreferences.cs
@@ -23,6 +23,8 @@ public class UserPreferences
public bool SaveProfileOnStart { get; set; } = true;
+ public bool WriteApplicationLogsToFile { get; set; } = true;
+
public List Servers { get; set; } = new();
public static UserPreferences FromFile(UserPreferencesFile file)
@@ -37,6 +39,7 @@ public static UserPreferences FromFile(UserPreferencesFile file)
prefs.StartWithWindows = file.StartWithWindows ?? prefs.StartWithWindows;
prefs.StartMinimized = file.StartMinimized ?? prefs.StartMinimized;
prefs.SaveProfileOnStart = file.SaveProfileOnStart ?? prefs.SaveProfileOnStart;
+ prefs.WriteApplicationLogsToFile = file.WriteApplicationLogsToFile ?? prefs.WriteApplicationLogsToFile;
if (file.Servers != null)
{
@@ -60,6 +63,7 @@ public UserPreferencesFile ToFile()
StartWithWindows = StartWithWindows,
StartMinimized = StartMinimized,
SaveProfileOnStart = SaveProfileOnStart,
+ WriteApplicationLogsToFile = WriteApplicationLogsToFile,
Servers = new(),
};
diff --git a/ValheimServerGUI/Game/UserPreferencesFile.cs b/ValheimServerGUI/Game/UserPreferencesFile.cs
index 205c2f1..aca18b8 100644
--- a/ValheimServerGUI/Game/UserPreferencesFile.cs
+++ b/ValheimServerGUI/Game/UserPreferencesFile.cs
@@ -38,6 +38,9 @@ public class UserPreferencesFile
[JsonProperty("saveProfileOnStart")]
public bool? SaveProfileOnStart { get; set; }
+ [JsonProperty("writeApplicationLogsToFile")]
+ public bool? WriteApplicationLogsToFile { get; set; }
+
[JsonProperty("servers")]
public List Servers { get; set; }
}
diff --git a/ValheimServerGUI/Game/UserPreferencesProvider.cs b/ValheimServerGUI/Game/UserPreferencesProvider.cs
index 2eafb93..0996c5e 100644
--- a/ValheimServerGUI/Game/UserPreferencesProvider.cs
+++ b/ValheimServerGUI/Game/UserPreferencesProvider.cs
@@ -1,10 +1,9 @@
-using Microsoft.Extensions.Logging;
+using Serilog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ValheimServerGUI.Properties;
-using ValheimServerGUI.Tools;
using ValheimServerGUI.Tools.Data;
namespace ValheimServerGUI.Game
@@ -65,11 +64,11 @@ private void SaveInternal(UserPreferences preferences)
{
var file = preferences.ToFile();
SaveAsync(UserPrefsFilePath, file).GetAwaiter().GetResult();
- Logger.LogInformation("User preferences saved");
+ Logger.Information("User preferences saved");
}
catch (Exception e)
{
- Logger.LogException(e, "Failed to save user preferences");
+ Logger.Error(e, "Failed to save user preferences");
return;
}
@@ -97,7 +96,7 @@ private UserPreferences LoadInternal()
}
catch (Exception e)
{
- Logger.LogException(e, "Failed to load user preferences");
+ Logger.Error(e, "Failed to load user preferences");
return UserPreferences.GetDefault();
}
}
@@ -123,7 +122,7 @@ private bool TryMigrateLegacyPrefs(out UserPreferences prefs)
try
{
- Logger.LogInformation("Migrating userprefs.txt to userprefs.json...");
+ Logger.Information("Migrating userprefs.txt to userprefs.json...");
prefs = new UserPreferences();
@@ -149,13 +148,13 @@ private bool TryMigrateLegacyPrefs(out UserPreferences prefs)
SaveInternal(prefs);
File.Delete(LegacyPath);
- Logger.LogInformation("Migration OK!");
+ Logger.Information("Migration OK!");
return true;
}
catch (Exception e)
{
- Logger.LogException(e, "Migration failed");
+ Logger.Error(e, "Migration failed");
prefs = null;
return false;
}
diff --git a/ValheimServerGUI/Game/ValheimServer.cs b/ValheimServerGUI/Game/ValheimServer.cs
index 52a64bb..ec0bcf2 100644
--- a/ValheimServerGUI/Game/ValheimServer.cs
+++ b/ValheimServerGUI/Game/ValheimServer.cs
@@ -1,19 +1,20 @@
-using Microsoft.Extensions.Logging;
-using System;
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ValheimServerGUI.Properties;
-using ValheimServerGUI.Tools;
using ValheimServerGUI.Tools.Logging;
+using ValheimServerGUI.Tools.Models;
using ValheimServerGUI.Tools.Processes;
namespace ValheimServerGUI.Game
{
public class ValheimServer : IDisposable
{
+ private delegate void LogEventHandler(string[] captures);
+
///
/// Options for the currently running server.
///
@@ -22,7 +23,7 @@ public class ValheimServer : IDisposable
///
/// Exposed for testing.
///
- public ValheimServerLogger Logger => ServerLogger;
+ public IValheimServerLogger Logger => ServerLogger;
public ServerStatus Status
{
@@ -42,7 +43,6 @@ private set
public event EventHandler StatusChanged;
public event EventHandler WorldSaved;
public event EventHandler InviteCodeReady;
- public event EventHandler LogReceived;
public bool CanStart => IsAnyStatus(ServerStatus.Stopped) && ProcessKey == null;
public bool CanStop => IsAnyStatus(ServerStatus.Starting, ServerStatus.Running) && ProcessKey != null;
@@ -50,22 +50,22 @@ private set
private readonly IProcessProvider ProcessProvider;
private readonly IPlayerDataRepository PlayerDataRepository;
- private readonly ValheimServerLogger ServerLogger;
- private readonly IEventLogger ApplicationLogger;
+ private readonly IApplicationLogger ApplicationLogger;
+
+ ///
+ /// This logger is instantiated each time a new server is started.
+ ///
+ private IValheimServerLogger ServerLogger;
public ValheimServer(
IProcessProvider processProvider,
IPlayerDataRepository playerDataRepository,
- ValheimServerLogger serverLogger,
- IEventLogger appLogger)
+ IApplicationLogger appLogger)
{
ProcessProvider = processProvider;
PlayerDataRepository = playerDataRepository;
- ServerLogger = serverLogger;
ApplicationLogger = appLogger;
- ServerLogger.LogReceived += Logger_OnServerLogReceived;
-
InitializeLogBasedActions();
InitializeStatusBasedActions();
}
@@ -74,14 +74,13 @@ public ValheimServer(
private void InitializeLogBasedActions()
{
-
LogBasedActions.Add(@"Game server connected", OnServerConnected);
LogBasedActions.Add(@"World saved \(\s*?([[\d\.]+?)\s*?ms\s*?\)\s*?$", OnWorldSaved);
LogBasedActions.Add(@"Session "".*?"" with join code (.*?) ", OnCrossplayJoinCodeAvailable);
// Connecting
LogBasedActions.Add(@"Got connection SteamID (\d+?)\D*?$", OnPlayerConnecting);
- LogBasedActions.Add(@"PlayFab socket with remote ID .*? received local Platform ID Steam_(\d+?)$", OnPlayerConnecting); // Crossplay
+ LogBasedActions.Add(@"PlayFab socket with remote ID .*? received local Platform ID (\w+?)_(\d+?)$", OnPlayerConnectingCrossplay); // Crossplay
// Connected - NOTE: ZDOID can be a negative number, account for that w/ regex!
LogBasedActions.Add(@"Got character ZDOID from (.+?) : ([\d-]+?)\D*?:(\d+?)\D*?$", OnPlayerConnected);
@@ -134,11 +133,15 @@ public void Start(IValheimServerOptions options)
{
if (!CanStart) return;
- ApplicationLogger.LogInformation("Starting server: {name}", options.Name);
+ ApplicationLogger.Information("Starting server: {name}", options.Name);
var exePath = options.GetValidatedServerExe().FullName;
var processArgs = GenerateArgs(options);
- ApplicationLogger.LogInformation(@"Server run command: ""{exePath}"" {processArgs}", exePath, processArgs);
+
+ ApplicationLogger.Information(
+ @"Server run command: ""{exePath}"" {processArgs}",
+ exePath,
+ CleanArgsForLogging(processArgs));
ProcessKey = Guid.NewGuid().ToString();
var process = ProcessProvider.AddBackgroundProcess(ProcessKey, exePath, processArgs);
@@ -152,7 +155,15 @@ public void Start(IValheimServerOptions options)
Status = ServerStatus.Stopped;
};
- process.StartIO();
+ ServerLogger = new ValheimServerLogger(options);
+ ServerLogger.LogReceived += Logger_OnServerLogReceived;
+ if (options.LogMessageHandler != null)
+ {
+ // Use this to pass messages to a UI component in the MainWindow
+ ServerLogger.LogReceived += options.LogMessageHandler;
+ }
+
+ ProcessProvider.StartIO(process);
Options = options;
IsRestarting = false;
@@ -166,7 +177,7 @@ public void Stop()
{
if (!CanStop) return;
- ApplicationLogger.LogInformation("Stopping server: {name}", Options.Name);
+ ApplicationLogger.Information("Stopping server: {name}", Options.Name);
ProcessProvider.SafelyKillProcess(ProcessKey);
@@ -182,7 +193,7 @@ public void Restart(IValheimServerOptions options = null)
{
if (!CanRestart) return;
- ApplicationLogger.LogInformation("Restarting server: {name}", Options.Name);
+ ApplicationLogger.Information("Restarting server: {name}", Options.Name);
ProcessProvider.SafelyKillProcess(ProcessKey);
@@ -202,41 +213,39 @@ public bool IsAnyStatus(params ServerStatus[] statuses)
private void Process_OnDataReceived(object obj, DataReceivedEventArgs e)
{
- ServerLogger.LogInformation(e.Data);
+ ServerLogger.Information(e.Data);
}
private void Process_OnErrorReceived(object obj, DataReceivedEventArgs e)
{
- ServerLogger.LogError(e.Data);
+ ServerLogger.Error(e.Data);
}
- private void Logger_OnServerLogReceived(object obj, EventLogContext context)
+ private void Logger_OnServerLogReceived(string message)
{
foreach (var kvp in LogBasedActions)
{
- var match = Regex.Match(context.Message, kvp.Key, RegexOptions.IgnoreCase);
+ var match = Regex.Match(message, kvp.Key, RegexOptions.IgnoreCase);
if (!match.Success) continue;
try
{
// The first capture group is the whole string, so skip that
var captures = (match.Groups as IEnumerable).Skip(1).Select(g => g.ToString()).ToArray();
- kvp.Value(this, context, captures);
+ kvp.Value(captures);
}
catch (Exception e)
{
- ApplicationLogger.LogError(e, "Error parsing server log: {message}", context.Message);
+ ApplicationLogger.Error(e, "Error parsing server log: {message}", message);
}
}
-
- LogReceived?.Invoke(obj, context);
}
#endregion
#region Log Message handlers
- private void OnServerConnected(object sender, EventLogContext context, params string[] captures)
+ private void OnServerConnected(params string[] captures)
{
// The server can reach a running state if you attempt to stop it late in the
// startup process, so avoid changing status from "Stopping" -> "Running".
@@ -246,15 +255,24 @@ private void OnServerConnected(object sender, EventLogContext context, params st
Status = ServerStatus.Running;
}
- private void OnPlayerConnecting(object sender, EventLogContext context, params string[] captures)
+ private void OnPlayerConnecting(params string[] captures)
{
var steamId = captures[0];
if (string.IsNullOrWhiteSpace(steamId)) return;
- PlayerDataRepository.SetPlayerJoining(steamId);
+ PlayerDataRepository.SetPlayerJoining(new() { Platform = PlayerPlatforms.Steam, PlayerId = steamId });
}
- private void OnPlayerConnected(object sender, EventLogContext context, params string[] captures)
+ private void OnPlayerConnectingCrossplay(params string[] captures)
+ {
+ var hasValidPlatform = PlayerPlatforms.TryGetValidPlatform(captures[0], out var platform);
+ var playerId = captures[1];
+ if (!hasValidPlatform || string.IsNullOrWhiteSpace(playerId)) return;
+
+ PlayerDataRepository.SetPlayerJoining(new() { Platform = platform, PlayerId = playerId });
+ }
+
+ private void OnPlayerConnected(params string[] captures)
{
var playerName = captures[0];
var zdoid = captures[1]; // Seems to be a unique object id for the game session
@@ -265,23 +283,41 @@ private void OnPlayerConnected(object sender, EventLogContext context, params st
PlayerDataRepository.SetPlayerOnline(playerName, zdoid);
}
- private void OnPlayerDisconnecting(object sender, EventLogContext context, params string[] captures)
+ private void OnPlayerDisconnecting(params string[] captures)
{
- var steamOrZdoId = captures[0];
- if (string.IsNullOrWhiteSpace(steamOrZdoId)) return;
+ var playerIdOrZdoId = captures[0];
+ if (string.IsNullOrWhiteSpace(playerIdOrZdoId)) return;
+
+ var query = new PlayerDataQuery
+ {
+ PlayerId = playerIdOrZdoId,
+ Or = new()
+ {
+ ZdoId = playerIdOrZdoId,
+ }
+ };
- PlayerDataRepository.SetPlayerLeaving(steamOrZdoId);
+ PlayerDataRepository.SetPlayerLeaving(query);
}
- private void OnPlayerDisconnected(object sender, EventLogContext context, params string[] captures)
+ private void OnPlayerDisconnected(params string[] captures)
{
- var steamOrZdoId = captures[0];
- if (string.IsNullOrWhiteSpace(steamOrZdoId)) return;
+ var playerIdOrZdoId = captures[0];
+ if (string.IsNullOrWhiteSpace(playerIdOrZdoId)) return;
- PlayerDataRepository.SetPlayerOffline(steamOrZdoId);
+ var query = new PlayerDataQuery
+ {
+ PlayerId = playerIdOrZdoId,
+ Or = new()
+ {
+ ZdoId = playerIdOrZdoId,
+ }
+ };
+
+ PlayerDataRepository.SetPlayerOffline(query);
}
- private void OnWorldSaved(object sender, EventLogContext context, params string[] captures)
+ private void OnWorldSaved(params string[] captures)
{
if (!decimal.TryParse(captures[0], out var timeMs))
{
@@ -291,7 +327,7 @@ private void OnWorldSaved(object sender, EventLogContext context, params string[
WorldSaved?.Invoke(this, timeMs);
}
- private void OnCrossplayJoinCodeAvailable(object sender, EventLogContext context, params string[] captures)
+ private void OnCrossplayJoinCodeAvailable(params string[] captures)
{
var inviteCode = captures[0];
if (string.IsNullOrWhiteSpace(inviteCode)) return;
@@ -335,13 +371,13 @@ private static string GenerateArgs(IValheimServerOptions options)
processArgs += options.AdditionalArgs;
}
- // TODO: can't actually enable this right now, because it stops the process from writing out logs,
- // which are essential for the app to function. Need to implement my own file logging, or find a way
- // to read logs from file as they come in.
- //if (!string.IsNullOrWhiteSpace(options.LogFile))
- //{
- // processArgs += @$" -logFile ""{options.LogFile}""";
- //}
+ return processArgs;
+ }
+
+ private static string CleanArgsForLogging(string processArgs)
+ {
+ // Don't print server password to logs
+ processArgs = Regex.Replace(processArgs, @"-password ""(.*?)""", @"-password ""*****""");
return processArgs;
}
diff --git a/ValheimServerGUI/Game/ValheimServerLogger.cs b/ValheimServerGUI/Game/ValheimServerLogger.cs
deleted file mode 100644
index 70b980d..0000000
--- a/ValheimServerGUI/Game/ValheimServerLogger.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Text.RegularExpressions;
-using ValheimServerGUI.Tools.Logging;
-
-namespace ValheimServerGUI.Game
-{
- public class ValheimServerLogger : EventLogger
- {
- private static readonly List FilteredMessages = new List
- {
- @"^\(Filename:",
- };
-
- protected override bool FilterLog(EventLogContext context)
- {
- if (string.IsNullOrWhiteSpace(context.Message)) return false;
- if (FilteredMessages.Any(f => Regex.IsMatch(context.Message, f))) return false;
-
- return true;
- }
-
- protected override string FormatLog(EventLogContext context)
- {
- // Not all log message have timestamps, but trim off any that do
- var message = Regex.Replace(context.Message, @"^\d+\/\d+\/\d+ \d+:\d+:\d+:\s+", "");
-
- return message;
- }
- }
-}
diff --git a/ValheimServerGUI/Game/ValheimServerOptions.cs b/ValheimServerGUI/Game/ValheimServerOptions.cs
index a9b59bd..b704042 100644
--- a/ValheimServerGUI/Game/ValheimServerOptions.cs
+++ b/ValheimServerGUI/Game/ValheimServerOptions.cs
@@ -30,6 +30,10 @@ public class ValheimServerOptions : IValheimServerOptions
public string SaveDataFolderPath { get; set; }
+ public bool LogToFile { get; set; }
+
+ public Action LogMessageHandler { get; set; }
+
public void Validate()
{
// Ensure all required fields exist
@@ -61,6 +65,10 @@ public void Validate()
if (SaveInterval > BackupShort || SaveInterval > BackupLong) throw new ArgumentException($"Save interval must be less than or equal to the backup intervals.");
if (BackupShort > BackupLong) throw new ArgumentException($"Short backup interval must be less than or equal to the long backup interval.");
+ // Additional args
+ // Using the native -logFile command will prevent logs from being piped to VSG, so don't allow it.
+ if (AdditionalArgs.ToLower().Contains("-logfile")) throw new ArgumentException($"ValheimServerGUI does not support the '-logFile' server argument. Instead, enable writing server logs to file under Advanced Controls.");
+
// Filepaths
this.GetValidatedServerExe();
this.GetValidatedSaveDataFolder();
@@ -94,5 +102,9 @@ public interface IValheimServerOptions
string ServerExePath { get; }
string SaveDataFolderPath { get; }
+
+ bool LogToFile { get; }
+
+ Action LogMessageHandler { get; }
}
}
diff --git a/ValheimServerGUI/Program.cs b/ValheimServerGUI/Program.cs
index afde347..57b0405 100644
--- a/ValheimServerGUI/Program.cs
+++ b/ValheimServerGUI/Program.cs
@@ -1,5 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
+using Serilog;
using System;
using System.Windows.Forms;
using ValheimServerGUI.Forms;
@@ -43,7 +43,6 @@ public static void Main(string[] args)
public static void ConfigureServices(IServiceCollection services, string[] args)
{
- var applicationLogger = new ApplicationLogger();
var startupArgsProvider = new StartupArgsProvider(args);
// Tools
@@ -52,8 +51,9 @@ public static void ConfigureServices(IServiceCollection services, string[] args)
.AddSingleton()
.AddSingleton()
.AddSingleton()
- .AddSingleton(applicationLogger)
- .AddSingleton(applicationLogger)
+ .AddSingleton()
+ .AddSingleton(sp => sp.GetRequiredService())
+ .AddSingleton(sp => sp.GetRequiredService())
.AddSingleton()
.AddSingleton()
.AddSingleton()
@@ -68,7 +68,6 @@ public static void ConfigureServices(IServiceCollection services, string[] args)
.AddSingleton()
.AddSingleton()
.AddSingleton(startupArgsProvider)
- .AddTransient()
.AddTransient();
// Forms
diff --git a/ValheimServerGUI/Properties/Resources.Designer.cs b/ValheimServerGUI/Properties/Resources.Designer.cs
index 078ae9a..d01a17b 100644
--- a/ValheimServerGUI/Properties/Resources.Designer.cs
+++ b/ValheimServerGUI/Properties/Resources.Designer.cs
@@ -60,6 +60,16 @@ internal Resources() {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap Add_16x {
+ get {
+ object obj = ResourceManager.GetObject("Add_16x", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
@@ -210,6 +220,16 @@ internal static System.Drawing.Bitmap DonateLogo {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap Edit_16x {
+ get {
+ object obj = ResourceManager.GetObject("Edit_16x", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
@@ -250,6 +270,15 @@ internal static System.Drawing.Bitmap Loading_Blue_16x {
}
}
+ ///
+ /// Looks up a localized string similar to %USERPROFILE%\AppData\LocalLow\Runeberry\ValheimServerGUI\logs.
+ ///
+ internal static string LogsFolderPath {
+ get {
+ return ResourceManager.GetString("LogsFolderPath", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
@@ -301,7 +330,7 @@ internal static System.Drawing.Bitmap OpenWeb_16x {
}
///
- /// Looks up a localized string similar to %USERPROFILE%\AppData\LocalLow\Runeberry\ValheimServerGUI\players.json.
+ /// Looks up a localized string similar to %USERPROFILE%\AppData\LocalLow\Runeberry\ValheimServerGUI\players-cache.json.
///
internal static string PlayerListFilePath {
get {
@@ -309,6 +338,16 @@ internal static string PlayerListFilePath {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap Remove_Red_16x {
+ get {
+ object obj = ResourceManager.GetObject("Remove_Red_16x", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
@@ -439,6 +478,16 @@ internal static System.Drawing.Bitmap StatusWarning_16x {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap Steam_16x {
+ get {
+ object obj = ResourceManager.GetObject("Steam_16x", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
@@ -540,6 +589,15 @@ internal static string UrlHelp {
}
}
+ ///
+ /// Looks up a localized string similar to https://github.com/runeberry/ValheimServerGUI/wiki/Frequently-Asked-Questions.
+ ///
+ internal static string UrlHelpCharacterNames {
+ get {
+ return ResourceManager.GetString("UrlHelpCharacterNames", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to https://github.com/runeberry/ValheimServerGUI/wiki/Connecting-to-your-Server.
///
@@ -612,5 +670,15 @@ internal static System.Drawing.Bitmap vsg_logo_16 {
return ((System.Drawing.Bitmap)(obj));
}
}
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap XboxLive_16x {
+ get {
+ object obj = ResourceManager.GetObject("XboxLive_16x", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
}
}
diff --git a/ValheimServerGUI/Properties/Resources.resx b/ValheimServerGUI/Properties/Resources.resx
index fbe7d9b..5fa3357 100644
--- a/ValheimServerGUI/Properties/Resources.resx
+++ b/ValheimServerGUI/Properties/Resources.resx
@@ -121,6 +121,9 @@
..\Resources\AddImmediateWindow_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\Add_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
..\Resources\ApplicationIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -170,6 +173,9 @@
..\Resources\DonateLogo.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\Edit_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
..\Resources\FolderInformation_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -182,6 +188,9 @@
..\Resources\Loading_Blue_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ %USERPROFILE%\AppData\LocalLow\Runeberry\ValheimServerGUI\logs
+
..\Resources\NewBug_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -198,7 +207,10 @@
..\Resources\OpenWeb_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
- %USERPROFILE%\AppData\LocalLow\Runeberry\ValheimServerGUI\players.json
+ %USERPROFILE%\AppData\LocalLow\Runeberry\ValheimServerGUI\players-cache.json
+
+
+ ..\Resources\Remove_Red_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
..\Resources\Restart_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -239,6 +251,9 @@
..\Resources\StatusWarning_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\Steam_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
..\Resources\Stop_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
@@ -272,6 +287,9 @@
https://github.com/runeberry/ValheimServerGUI/wiki
+
+ https://github.com/runeberry/ValheimServerGUI/wiki/Frequently-Asked-Questions
+
https://github.com/runeberry/ValheimServerGUI/wiki/Connecting-to-your-Server
@@ -297,4 +315,7 @@
..\Resources\vsg_logo_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ ..\Resources\XboxLive_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
\ No newline at end of file
diff --git a/ValheimServerGUI/Resources/Add_16x.png b/ValheimServerGUI/Resources/Add_16x.png
new file mode 100644
index 0000000..7754d65
Binary files /dev/null and b/ValheimServerGUI/Resources/Add_16x.png differ
diff --git a/ValheimServerGUI/Resources/Edit_16x.png b/ValheimServerGUI/Resources/Edit_16x.png
new file mode 100644
index 0000000..84cb0df
Binary files /dev/null and b/ValheimServerGUI/Resources/Edit_16x.png differ
diff --git a/ValheimServerGUI/Resources/Remove_Red_16x.png b/ValheimServerGUI/Resources/Remove_Red_16x.png
new file mode 100644
index 0000000..48ffa8d
Binary files /dev/null and b/ValheimServerGUI/Resources/Remove_Red_16x.png differ
diff --git a/ValheimServerGUI/Resources/Steam_16x.png b/ValheimServerGUI/Resources/Steam_16x.png
new file mode 100644
index 0000000..3925746
Binary files /dev/null and b/ValheimServerGUI/Resources/Steam_16x.png differ
diff --git a/ValheimServerGUI/Resources/XboxLive_16x.png b/ValheimServerGUI/Resources/XboxLive_16x.png
new file mode 100644
index 0000000..88be7b2
Binary files /dev/null and b/ValheimServerGUI/Resources/XboxLive_16x.png differ
diff --git a/ValheimServerGUI/Tools/AssemblyHelper.cs b/ValheimServerGUI/Tools/AssemblyHelper.cs
index e801344..678debf 100644
--- a/ValheimServerGUI/Tools/AssemblyHelper.cs
+++ b/ValheimServerGUI/Tools/AssemblyHelper.cs
@@ -6,6 +6,7 @@
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
+using ValheimServerGUI.Tools.Models;
namespace ValheimServerGUI.Tools
{
diff --git a/ValheimServerGUI/Tools/ExceptionHandler.cs b/ValheimServerGUI/Tools/ExceptionHandler.cs
index ff96fed..5a33261 100644
--- a/ValheimServerGUI/Tools/ExceptionHandler.cs
+++ b/ValheimServerGUI/Tools/ExceptionHandler.cs
@@ -4,6 +4,7 @@
using System.Windows.Forms;
using ValheimServerGUI.Forms;
using ValheimServerGUI.Tools.Logging;
+using ValheimServerGUI.Tools.Models;
namespace ValheimServerGUI.Tools
{
@@ -18,9 +19,9 @@ public class ExceptionHandler : IExceptionHandler
{
private readonly IRuneberryApiClient RuneberryApiClient;
- private readonly IEventLogger Logger;
+ private readonly IApplicationLogger Logger;
- public ExceptionHandler(IRuneberryApiClient runeberryApiClient, IEventLogger logger)
+ public ExceptionHandler(IRuneberryApiClient runeberryApiClient, IApplicationLogger logger)
{
RuneberryApiClient = runeberryApiClient;
Logger = logger;
diff --git a/ValheimServerGUI/Tools/IpAddressProvider.cs b/ValheimServerGUI/Tools/IpAddressProvider.cs
index 243e2e9..df663eb 100644
--- a/ValheimServerGUI/Tools/IpAddressProvider.cs
+++ b/ValheimServerGUI/Tools/IpAddressProvider.cs
@@ -1,5 +1,4 @@
-using Microsoft.Extensions.Logging;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net;
@@ -84,7 +83,7 @@ public Task LoadInternalIpAddressAsync()
if (!addresses.Any())
{
- Logger.LogWarning("Failed to find internal IP address: No network interfaces are UP with any IPv4 addresses");
+ Logger.Warning("Failed to find internal IP address: No network interfaces are UP with any IPv4 addresses");
return Task.CompletedTask;
}
diff --git a/ValheimServerGUI/Tools/Logging/ApplicationLogger.cs b/ValheimServerGUI/Tools/Logging/ApplicationLogger.cs
new file mode 100644
index 0000000..4bc8ae6
--- /dev/null
+++ b/ValheimServerGUI/Tools/Logging/ApplicationLogger.cs
@@ -0,0 +1,58 @@
+using Microsoft.Extensions.DependencyInjection;
+using Serilog;
+using Serilog.Events;
+using System;
+using System.Collections.Generic;
+using ValheimServerGUI.Game;
+
+namespace ValheimServerGUI.Tools.Logging
+{
+ public interface IApplicationLogger : IBaseLogger
+ {
+ }
+
+ public class ApplicationLogger : BaseLogger, IApplicationLogger
+ {
+ private readonly IServiceProvider ServiceProvider;
+ private IUserPreferencesProvider UserPrefsProvider;
+
+ private static readonly Dictionary LevelPrefixes = new()
+ {
+ { LogEventLevel.Verbose, "[VER] " },
+ { LogEventLevel.Debug, "[DBG] " },
+ { LogEventLevel.Information, "" },
+ { LogEventLevel.Warning, "[WRN] " },
+ { LogEventLevel.Error, "[ERR] " },
+ { LogEventLevel.Fatal, "[FAT] " },
+ };
+
+ public ApplicationLogger(IServiceProvider services)
+ {
+ // Dependencies are injected late to avoid creating a circular dependency
+ ServiceProvider = services;
+
+ AddModifier((evt, message) => $"{LevelPrefixes[evt.Level]}{message}");
+ }
+
+ private void OnUserPreferencesSaved(object sender, UserPreferences prefs)
+ {
+ RebuildLogger();
+ }
+
+ #region BaseLogger overrides
+
+ protected override void ConfigureLogger(LoggerConfiguration config)
+ {
+ if (UserPrefsProvider == null)
+ {
+ UserPrefsProvider = ServiceProvider.GetRequiredService();
+ UserPrefsProvider.PreferencesSaved += OnUserPreferencesSaved;
+ }
+
+ var prefs = UserPrefsProvider.LoadPreferences();
+ if (prefs.WriteApplicationLogsToFile) AddFileLogging(config, "ApplicationLogs");
+ }
+
+ #endregion
+ }
+}
diff --git a/ValheimServerGUI/Tools/Logging/BaseLogger.cs b/ValheimServerGUI/Tools/Logging/BaseLogger.cs
new file mode 100644
index 0000000..2dad13e
--- /dev/null
+++ b/ValheimServerGUI/Tools/Logging/BaseLogger.cs
@@ -0,0 +1,116 @@
+using Serilog;
+using Serilog.Events;
+using System;
+using System.Collections.Generic;
+using ValheimServerGUI.Properties;
+using ValheimServerGUI.Tools.Logging.Components;
+
+namespace ValheimServerGUI.Tools.Logging
+{
+ public interface IBaseLogger : ILogger
+ {
+ event Action LogReceived;
+
+ IEnumerable LogBuffer { get; }
+ }
+
+ ///
+ /// Preconfigured Logger for use throughout the application.
+ ///
+ public abstract class BaseLogger : IBaseLogger
+ {
+ public delegate string LogEventModifier(LogEvent logEvent, string renderedMessage);
+
+ private readonly LogBufferSink LogBufferSink = new(1000);
+ private readonly List Modifiers = new();
+ private ILogger Logger;
+
+ #region IBaseLogger implementation
+
+ public event Action LogReceived;
+
+ public IEnumerable LogBuffer => LogBufferSink.Logs;
+
+ #endregion
+
+ #region Protected methods
+
+ protected void AddModifier(LogEventModifier modifier)
+ {
+ Modifiers.Add(modifier);
+ }
+
+ ///
+ /// Implement custom logging configuration specific to your class here.
+ ///
+ protected virtual void ConfigureLogger(LoggerConfiguration config)
+ {
+ // no-op by default
+ }
+
+ ///
+ /// Set an output name for your log file, if file logging is enabled.
+ ///
+ protected virtual string LogFileName => null;
+
+ protected void RebuildLogger()
+ {
+ Logger = CreateLogger();
+ }
+
+ protected void AddFileLogging(LoggerConfiguration config, string fileName)
+ {
+ if (!string.IsNullOrWhiteSpace(fileName))
+ {
+ config.WriteToRollingFile(Resources.LogsFolderPath, fileName);
+ }
+ }
+
+ #endregion
+
+ #region Private methods
+
+ private ILogger CreateLogger()
+ {
+ var config = new LoggerConfiguration()
+#if DEBUG
+ .MinimumLevel.Verbose()
+#else
+ .MinimumLevel.Debug()
+#endif
+ .WriteTo.Sink(LogBufferSink);
+
+ ConfigureLogger(config);
+
+ return config.CreateLogger();
+ }
+
+ #endregion
+
+ #region ILogger implementation
+
+ public void Write(LogEvent logEvent)
+ {
+ var message = logEvent.RenderMessage();
+
+ foreach (var modifier in Modifiers)
+ {
+ message = modifier(logEvent, message);
+ }
+
+ message = $"{logEvent.Timestamp.ToLogPrefixFormat()} {message}";
+
+ if (Logger == null)
+ {
+ // Wait until first log is written to create logger, so all dependencies are resolved
+ Logger = CreateLogger();
+ }
+
+ Logger.Write(logEvent.Level, message);
+
+ LogReceived?.Invoke(message);
+ }
+
+ #endregion
+ }
+}
diff --git a/ValheimServerGUI/Tools/Logging/Components/LogBufferSink.cs b/ValheimServerGUI/Tools/Logging/Components/LogBufferSink.cs
new file mode 100644
index 0000000..637b165
--- /dev/null
+++ b/ValheimServerGUI/Tools/Logging/Components/LogBufferSink.cs
@@ -0,0 +1,23 @@
+using Serilog.Core;
+using Serilog.Events;
+using System.Collections.Generic;
+
+namespace ValheimServerGUI.Tools.Logging.Components
+{
+ public class LogBufferSink : ILogEventSink
+ {
+ private readonly ConcurrentBuffer Buffer;
+
+ public IEnumerable Logs => Buffer;
+
+ public LogBufferSink(int bufferSize)
+ {
+ Buffer = new(bufferSize);
+ }
+
+ public void Emit(LogEvent logEvent)
+ {
+ Buffer.Enqueue(logEvent.RenderMessage());
+ }
+ }
+}
diff --git a/ValheimServerGUI/Tools/Logging/Components/RegexFilter.cs b/ValheimServerGUI/Tools/Logging/Components/RegexFilter.cs
new file mode 100644
index 0000000..42308e8
--- /dev/null
+++ b/ValheimServerGUI/Tools/Logging/Components/RegexFilter.cs
@@ -0,0 +1,48 @@
+using Serilog;
+using Serilog.Core;
+using Serilog.Events;
+using System;
+using System.Text.RegularExpressions;
+
+namespace ValheimServerGUI.Tools.Logging.Components
+{
+ public class RegexFilter : ILogEventFilter
+ {
+ private readonly string Pattern;
+ private readonly bool Include;
+
+ public RegexFilter(string pattern, bool include)
+ {
+ if (string.IsNullOrEmpty(pattern)) throw new ArgumentNullException(nameof(pattern));
+
+ Pattern = pattern;
+ Include = include;
+ }
+
+ public bool IsEnabled(LogEvent logEvent)
+ {
+ var isMatch = Regex.IsMatch(logEvent.MessageTemplate.Text, Pattern);
+
+ return Include ? isMatch : !isMatch;
+ }
+ }
+
+ public static class RegexFilterExtensions
+ {
+ ///
+ /// Only include logs that match the specified pattern.
+ ///
+ public static LoggerConfiguration AddRegexInclusion(this LoggerConfiguration config, string pattern)
+ {
+ return config.Filter.With(new RegexFilter(pattern, true));
+ }
+
+ ///
+ /// Exclude logs that match the specified pattern.
+ ///
+ public static LoggerConfiguration AddRegexExclusion(this LoggerConfiguration config, string pattern)
+ {
+ return config.Filter.With(new RegexFilter(pattern, false));
+ }
+ }
+}
diff --git a/ValheimServerGUI/Tools/Logging/Components/RollingFileSink.cs b/ValheimServerGUI/Tools/Logging/Components/RollingFileSink.cs
new file mode 100644
index 0000000..ecb948d
--- /dev/null
+++ b/ValheimServerGUI/Tools/Logging/Components/RollingFileSink.cs
@@ -0,0 +1,32 @@
+using Serilog;
+using System;
+using System.IO;
+
+namespace ValheimServerGUI.Tools.Logging.Components
+{
+ public static class RollingFileSinkExtensions
+ {
+ private const string DefaultOutputTemplate = "{Message:lj}{NewLine}";
+
+ public static LoggerConfiguration WriteToRollingFile(
+ this LoggerConfiguration config,
+ string directory,
+ string filename)
+ {
+ filename = PathExtensions.GetValidFileName(filename);
+ directory = Environment.ExpandEnvironmentVariables(directory);
+ var filepath = Path.Join(directory, $"{filename}_.txt");
+
+ if (!Directory.Exists(directory))
+ {
+ Directory.CreateDirectory(directory);
+ }
+
+ return config.WriteTo.File(filepath,
+ rollingInterval: RollingInterval.Day,
+ retainedFileTimeLimit: TimeSpan.FromDays(30),
+ outputTemplate: DefaultOutputTemplate,
+ shared: true); // Allows multiple processes to write to same file
+ }
+ }
+}
diff --git a/ValheimServerGUI/Tools/Logging/LogViews.cs b/ValheimServerGUI/Tools/Logging/LogViews.cs
new file mode 100644
index 0000000..b802274
--- /dev/null
+++ b/ValheimServerGUI/Tools/Logging/LogViews.cs
@@ -0,0 +1,9 @@
+namespace ValheimServerGUI.Tools.Logging
+{
+ public static class LogViews
+ {
+ public const string Application = "Application";
+
+ public const string Server = "Server";
+ }
+}
diff --git a/ValheimServerGUI/Tools/Logging/ValheimServerLogger.cs b/ValheimServerGUI/Tools/Logging/ValheimServerLogger.cs
new file mode 100644
index 0000000..b607c09
--- /dev/null
+++ b/ValheimServerGUI/Tools/Logging/ValheimServerLogger.cs
@@ -0,0 +1,36 @@
+using Serilog;
+using System.Text.RegularExpressions;
+using ValheimServerGUI.Game;
+using ValheimServerGUI.Tools.Logging.Components;
+
+namespace ValheimServerGUI.Tools.Logging
+{
+ public interface IValheimServerLogger : IBaseLogger
+ {
+ }
+
+ public class ValheimServerLogger : BaseLogger, IValheimServerLogger
+ {
+ private readonly IValheimServerOptions Options;
+
+ public ValheimServerLogger(IValheimServerOptions options)
+ {
+ Options = options;
+
+ // Remove default timestamp on some logs
+ AddModifier((_, message) => Regex.Replace(message, @"^\d+\/\d+\/\d+ \d+:\d+:\d+:\s+", ""));
+ }
+
+ #region DynamicLogger overrides
+
+ protected override void ConfigureLogger(LoggerConfiguration config)
+ {
+ if (Options.LogToFile) AddFileLogging(config, $"ServerLogs-{Options.Name}");
+
+ // Ignore Unity debug logs
+ config.AddRegexExclusion(@"^\(Filename:");
+ }
+
+ #endregion
+ }
+}
diff --git a/ValheimServerGUI/Tools/PathExtensions.cs b/ValheimServerGUI/Tools/PathExtensions.cs
index a64b6d5..a738db3 100644
--- a/ValheimServerGUI/Tools/PathExtensions.cs
+++ b/ValheimServerGUI/Tools/PathExtensions.cs
@@ -45,5 +45,31 @@ public static DirectoryInfo GetDirectoryInfo(string path, bool checkExists = fal
return new DirectoryInfo(path);
}
+
+ public static string GetValidFileName(string filename, bool addTimestamp = false)
+ {
+ if (string.IsNullOrWhiteSpace(filename))
+ {
+ return "file";
+ }
+
+ if (filename.Length > 150)
+ {
+ // Max filename length is likely closer to 255, but I'm just gonna play it safe
+ filename = filename[..150];
+ }
+
+ if (addTimestamp)
+ {
+ filename = $"{filename}_{DateTime.Now.ToFilenameISOFormat()}";
+ }
+
+ foreach (var c in Path.GetInvalidFileNameChars())
+ {
+ filename = filename.Replace(c, '-');
+ }
+
+ return filename;
+ }
}
}
diff --git a/ValheimServerGUI/Tools/RuneberryApiClient.cs b/ValheimServerGUI/Tools/RuneberryApiClient.cs
index 7e92c69..076044b 100644
--- a/ValheimServerGUI/Tools/RuneberryApiClient.cs
+++ b/ValheimServerGUI/Tools/RuneberryApiClient.cs
@@ -3,11 +3,16 @@
using System.Threading.Tasks;
using ValheimServerGUI.Properties;
using ValheimServerGUI.Tools.Http;
+using ValheimServerGUI.Tools.Models;
namespace ValheimServerGUI.Tools
{
public interface IRuneberryApiClient
{
+ event EventHandler PlayerInfoAvailable;
+
+ Task RequestPlayerInfoAsync(string platform, string playerId);
+
Task SendCrashReportAsync(CrashReport report);
}
@@ -17,10 +22,29 @@ public RuneberryApiClient(IRestClientContext context) : base(context)
{
}
+ #region IRuneberryApiClient implementation
+
+ public event EventHandler PlayerInfoAvailable;
+
+ public async Task RequestPlayerInfoAsync(string platform, string playerId)
+ {
+ var response = await Get($"{Resources.UrlRuneberryApi}/player-info?platform={platform}&playerId={playerId}")
+ .WithHeader(ClientSecrets.RuneberryApiKeyHeader, ClientSecrets.RuneberryClientApiKey)
+ .SendAsync();
+
+ if (response == null)
+ {
+ Logger.Error($"Unable to get info for {platform} player with ID {playerId}");
+ return;
+ }
+
+ PlayerInfoAvailable?.Invoke(this, response);
+ }
+
public async Task SendCrashReportAsync(CrashReport report)
{
var response = await Post($"{Resources.UrlRuneberryApi}/crash-report", report)
- .WithHeader(Secrets.RuneberryApiKeyHeader, Secrets.RuneberryClientApiKey)
+ .WithHeader(ClientSecrets.RuneberryApiKeyHeader, ClientSecrets.RuneberryClientApiKey)
.SendAsync();
if (response == null || !response.IsSuccessStatusCode)
@@ -32,7 +56,7 @@ public async Task SendCrashReportAsync(CrashReport report)
if (response != null)
{
var rawResponse = await response.Content.ReadAsStringAsync();
- var exceptionResponse = JsonConvert.DeserializeObject(rawResponse);
+ var exceptionResponse = JsonConvert.DeserializeObject(rawResponse);
message = $"({(int)response.StatusCode}) {exceptionResponse.Message}";
}
else
@@ -49,10 +73,6 @@ public async Task SendCrashReportAsync(CrashReport report)
}
}
- private class ExceptionResponse
- {
- [JsonProperty("message")]
- public string Message { get; set; }
- }
+ #endregion
}
}
diff --git a/ValheimServerGUI/Tools/StartupHelper.cs b/ValheimServerGUI/Tools/StartupHelper.cs
index 5a473c4..7b0ce28 100644
--- a/ValheimServerGUI/Tools/StartupHelper.cs
+++ b/ValheimServerGUI/Tools/StartupHelper.cs
@@ -1,5 +1,5 @@
-using Microsoft.Extensions.Logging;
-using Microsoft.Win32;
+using Microsoft.Win32;
+using Serilog;
using System;
using System.Security;
using System.Windows.Forms;
@@ -33,7 +33,7 @@ public static bool ApplyStartupSetting(bool userPreference, ILogger logger)
}
else if (!startupPath.Equals(Application.ExecutablePath, StringComparison.OrdinalIgnoreCase))
{
- logger.LogInformation("ValheimServerGUI executable path has changed, removing old registry entry...");
+ logger.Information("ValheimServerGUI executable path has changed, removing old registry entry...");
if (RemoveFromStartup(Application.ProductName, logger))
{
runOnStartup = true;
@@ -42,7 +42,7 @@ public static bool ApplyStartupSetting(bool userPreference, ILogger logger)
if (runOnStartup && RunOnStartup(Application.ProductName, Application.ExecutablePath, logger))
{
- logger.LogInformation("ValheimServerGUI will now run on Windows startup");
+ logger.Information("ValheimServerGUI will now run on Windows startup");
return true;
}
}
@@ -50,7 +50,7 @@ public static bool ApplyStartupSetting(bool userPreference, ILogger logger)
{
if (RemoveFromStartup(Application.ProductName, logger))
{
- logger.LogInformation("ValheimServerGUI will no longer run on Windows startup");
+ logger.Information("ValheimServerGUI will no longer run on Windows startup");
return true;
}
}
@@ -74,11 +74,11 @@ private static bool RunOnStartup(string appTitle, string appPath, ILogger logger
}
catch (SecurityException)
{
- logger.LogWarning($"{nameof(RunOnStartup)}: No LocalMachine access (not Administrator), trying CurrentUser...");
+ logger.Warning($"{nameof(RunOnStartup)}: No LocalMachine access (not Administrator), trying CurrentUser...");
}
catch (Exception e)
{
- logger.LogException(e, $"{nameof(RunOnStartup)}: Failed to set LocalMachine registry key, trying CurrentUser...");
+ logger.Error(e, $"{nameof(RunOnStartup)}: Failed to set LocalMachine registry key, trying CurrentUser...");
}
try
@@ -88,7 +88,7 @@ private static bool RunOnStartup(string appTitle, string appPath, ILogger logger
}
catch (Exception e)
{
- logger.LogException(e, $"{nameof(RunOnStartup)}: Failed to set CurrentUser registry key");
+ logger.Error(e, $"{nameof(RunOnStartup)}: Failed to set CurrentUser registry key");
return false;
}
return true;
@@ -110,11 +110,11 @@ private static bool RemoveFromStartup(string appTitle, ILogger logger)
}
catch (SecurityException)
{
- logger.LogWarning($"{nameof(RemoveFromStartup)}: No LocalMachine access (not Administrator), trying CurrentUser...");
+ logger.Warning($"{nameof(RemoveFromStartup)}: No LocalMachine access (not Administrator), trying CurrentUser...");
}
catch (Exception e)
{
- logger.LogException(e, $"{nameof(RemoveFromStartup)}: Failed to set LocalMachine registry key, trying CurrentUser...");
+ logger.Error(e, $"{nameof(RemoveFromStartup)}: Failed to set LocalMachine registry key, trying CurrentUser...");
}
try
@@ -125,7 +125,7 @@ private static bool RemoveFromStartup(string appTitle, ILogger logger)
}
catch (Exception e)
{
- logger.LogException(e, $"{nameof(RemoveFromStartup)}: Failed to set CurrentUser registry key");
+ logger.Error(e, $"{nameof(RemoveFromStartup)}: Failed to set CurrentUser registry key");
}
return false;
@@ -147,11 +147,11 @@ private static string GetStartupPath(string appTitle, ILogger logger)
}
catch (SecurityException)
{
- logger.LogWarning($"{nameof(GetStartupPath)}: No LocalMachine access (not Administrator), trying CurrentUser...");
+ logger.Warning($"{nameof(GetStartupPath)}: No LocalMachine access (not Administrator), trying CurrentUser...");
}
catch (Exception e)
{
- logger.LogException(e, $"{nameof(GetStartupPath)}: Failed to read LocalMachine registry key, trying CurrentUser...");
+ logger.Error(e, $"{nameof(GetStartupPath)}: Failed to read LocalMachine registry key, trying CurrentUser...");
}
try
@@ -161,7 +161,7 @@ private static string GetStartupPath(string appTitle, ILogger logger)
}
catch (Exception e)
{
- logger.LogException(e, $"{nameof(GetStartupPath)}: Failed to read CurrentUser registry key");
+ logger.Error(e, $"{nameof(GetStartupPath)}: Failed to read CurrentUser registry key");
}
return null;
diff --git a/ValheimServerGUI/Tools/TimeFormats.cs b/ValheimServerGUI/Tools/TimeFormats.cs
new file mode 100644
index 0000000..b3f75dd
--- /dev/null
+++ b/ValheimServerGUI/Tools/TimeFormats.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace ValheimServerGUI.Tools
+{
+ public static class TimeFormats
+ {
+ public const string DisplayISO = "yyyy-MM-ddTHH:mm:ssZ";
+ public const string FilenameISO = "yyyy-MM-dd_HH-mm-ssZ";
+ public const string LogPrefix = "[HH:mm:ss.fff]";
+ public const string ServerElapsed = @"hh\:mm\:ss";
+
+ public static string ToDisplayISOFormat(this DateTime dateTime)
+ {
+ return dateTime.ToString(DisplayISO);
+ }
+
+ public static string ToFilenameISOFormat(this DateTime dateTime)
+ {
+ return dateTime.ToString(FilenameISO);
+ }
+
+ public static string ToLogPrefixFormat(this DateTimeOffset dateTime)
+ {
+ return dateTime.ToString(LogPrefix);
+ }
+
+ public static string ToServerElapsedFormat(this TimeSpan timeSpan)
+ {
+ return timeSpan.ToString(ServerElapsed);
+ }
+ }
+}
diff --git a/ValheimServerGUI/Tools/WinFormsExtensions.cs b/ValheimServerGUI/Tools/WinFormsExtensions.cs
index 348d0d5..de318c9 100644
--- a/ValheimServerGUI/Tools/WinFormsExtensions.cs
+++ b/ValheimServerGUI/Tools/WinFormsExtensions.cs
@@ -4,7 +4,6 @@
using System.Globalization;
using System.Linq;
using System.Resources;
-using System.Threading.Tasks;
using System.Windows.Forms;
using ValheimServerGUI.Properties;
@@ -14,6 +13,18 @@ public static class WinFormsExtensions
{
#region Control extensions
+ public static Action BuildActionHandler(this Control control, Action action)
+ {
+ var eventHandler = control.BuildEventHandler(action);
+ return (args) => eventHandler(null, args);
+ }
+
+ public static Action BuildActionHandler(this Control control, Action action)
+ {
+ var eventHandler = control.BuildEventHandler(action);
+ return () => eventHandler(null, null);
+ }
+
public static EventHandler BuildEventHandler(this Control control, Action action)
{
return (sender, args) =>
@@ -22,7 +33,7 @@ public static EventHandler BuildEventHandler(this Control control,
if (control.InvokeRequired)
{
- control.Invoke(new Action(action), new object[] { args });
+ control.BeginInvoke(action, new object[] { args });
return;
}
@@ -40,7 +51,7 @@ public static EventHandler BuildEventHandler(this Control control, Action action
// See here: https://stackoverflow.com/questions/519233/writing-to-a-textbox-from-another-thread
if (control.InvokeRequired)
{
- control.Invoke(action);
+ control.BeginInvoke(action);
return;
}
@@ -48,47 +59,48 @@ public static EventHandler BuildEventHandler(this Control control, Action action
};
}
- public static EventHandler BuildEventHandlerAsync(this Control control, Func taskFunc, int taskDelay = 0)
- {
- return async (sender, args) =>
- {
- if (taskDelay > 0) await Task.Delay(taskDelay);
-
- await Task.Run(() =>
- {
- if (control.IsDisposed) return;
-
- if (control.InvokeRequired)
- {
- control.Invoke(new Func(taskFunc), new object[] { args });
- return;
- }
-
- taskFunc(args);
- });
- };
- }
-
- public static EventHandler BuildEventHandlerAsync(this Control control, Func taskFunc, int taskDelay = 0)
- {
- return async (sender, args) =>
- {
- if (taskDelay > 0) await Task.Delay(taskDelay);
-
- await Task.Run(() =>
- {
- if (control.IsDisposed) return;
-
- if (control.InvokeRequired)
- {
- control.Invoke(new Func(taskFunc));
- return;
- }
-
- taskFunc();
- });
- };
- }
+ // (jb, 3/25/23) Commenting out these extensions because I'm not using them.
+ //public static EventHandler BuildEventHandlerAsync(this Control control, Func taskFunc, int taskDelay = 0)
+ //{
+ // return async (sender, args) =>
+ // {
+ // if (taskDelay > 0) await Task.Delay(taskDelay);
+
+ // await Task.Run(() =>
+ // {
+ // if (control.IsDisposed) return;
+
+ // if (control.InvokeRequired)
+ // {
+ // control.BeginInvoke(new Func(taskFunc), new object[] { args });
+ // return;
+ // }
+
+ // taskFunc(args);
+ // });
+ // };
+ //}
+
+ //public static EventHandler BuildEventHandlerAsync(this Control control, Func taskFunc, int taskDelay = 0)
+ //{
+ // return async (sender, args) =>
+ // {
+ // if (taskDelay > 0) await Task.Delay(taskDelay);
+
+ // await Task.Run(() =>
+ // {
+ // if (control.IsDisposed) return;
+
+ // if (control.InvokeRequired)
+ // {
+ // control.BeginInvoke(new Func(taskFunc));
+ // return;
+ // }
+
+ // taskFunc();
+ // });
+ // };
+ //}
///
/// (jb, 5/9/21) For some reason, you cannot set a Form's icon from a Resource in the Designer, so I've been setting it
diff --git a/ValheimServerGUI/ValheimServerGUI.csproj b/ValheimServerGUI/ValheimServerGUI.csproj
index d26c2fd..910666b 100644
--- a/ValheimServerGUI/ValheimServerGUI.csproj
+++ b/ValheimServerGUI/ValheimServerGUI.csproj
@@ -10,7 +10,7 @@
A simple user interface for running Valheim Dedicated Server on Windows.
2022
GNU GPLv3
- 2.1.0
+ 2.2.0-rc.2
build$([System.DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"))
@@ -33,15 +33,16 @@
-
+
+
-
-
-
-
+
+
+
+