using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; //using RazzLogging; using RazzTools; namespace ValheimServerWarden { /// <summary> /// Interaction logic for ServerDetailsWindow.xaml /// </summary> public partial class ServerDetailsWindow : Window { //public event EventHandler<ServerEventArgs> Starting; //public event EventHandler<ServerEventArgs> Stopping; public event EventHandler<ServerEventArgs> EditedServer; public event EventHandler<ServerEventArgs> ShowLog; private ValheimServer _server; private string _steamPath; private System.Timers.Timer resourceTimer; public ValheimServer Server { get { return this._server; } } public ServerDetailsWindow(ValheimServer server) { InitializeComponent(); this._server = server; txtServerLog.Document.Blocks.Clear(); foreach (var installmethod in Enum.GetValues(typeof(ValheimServer.ServerInstallMethod))) { cmbServerType.Items.Add(installmethod); } resourceTimer = new(); resourceTimer.Interval = 10000; resourceTimer.AutoReset = true; resourceTimer.Elapsed += ResourceTimer_Elapsed; if (Server.Status == ValheimServer.ServerStatus.Running) { UpdateServerResourcesUsed(); resourceTimer.Enabled = true; } RefreshControls(); attachServerEventHandlers(); ServerToControls(); _steamPath = null; try { string filePath = @"Program Files (x86)\Steam\steam.exe"; DriveInfo[] drives = DriveInfo.GetDrives(); foreach (DriveInfo drive in drives) { string testpath = $@"{drive.Name}{filePath}"; if (File.Exists(testpath)) { _steamPath = testpath; RefreshControls(); break; } } } catch (Exception ex) { Debug.WriteLine("Error searching for Steam path"); Debug.WriteLine(ex); } LoadLists(); foreach (var entry in Server.LogEntries) { if (txtServerLog.Document.Blocks.Count > 0) { txtServerLog.Document.Blocks.InsertBefore(txtServerLog.Document.Blocks.FirstBlock, (Paragraph)entry); } else { txtServerLog.Document.Blocks.Add((Paragraph)entry); } } cmbPriority.Items.Add(ProcessPriorityClass.Normal); cmbPriority.Items.Add(ProcessPriorityClass.AboveNormal); cmbPriority.Items.Add(ProcessPriorityClass.High); } public void RefreshControls() { this.Dispatcher.Invoke(() => { try { Title = $"{this.Server.DisplayName}"; lblPlayerCount.Content = this.Server.PlayerCount; dgPlayers.ItemsSource = this.Server.Players; dgPlayers.Items.Refresh(); ValheimServer.ServerStatus status = this.Server.Status; lblStatus.Content = status; if (Server.StartTime.Equals(new DateTime())) { lblStartTime.Content = "N/A"; } else { lblStartTime.Content = Server.StartTime.ToString(); } btnStart.Visibility = Visibility.Collapsed; btnStop.Visibility = Visibility.Collapsed; btnWorking.Visibility = Visibility.Collapsed; btnuModInstall.IsEnabled = false; btnuModUpdate.IsEnabled = false; menuConnectPlay.Visibility = Visibility.Collapsed; menuConnectCheckExternal.Visibility = Visibility.Collapsed; if (status == ValheimServer.ServerStatus.Running) { btnStop.Visibility = Visibility.Visible; if (_steamPath != null) { menuConnectPlay.Visibility = Visibility.Visible; } menuConnectCheckExternal.Visibility = Visibility.Visible; menuSteamCmdUpdate.Visibility = Visibility.Collapsed; } else if (status == ValheimServer.ServerStatus.Stopped) { btnStart.Visibility = Visibility.Visible; menuSteamCmdUpdate.Visibility = Visibility.Visible; btnuModInstall.IsEnabled = true; btnuModUpdate.IsEnabled = true; } else { btnWorking.Visibility = Visibility.Visible; if (status == ValheimServer.ServerStatus.Starting) { btnWorking.ToolTip = "Starting..."; } else if (status == ValheimServer.ServerStatus.Stopping) { btnWorking.ToolTip = "Stopping..."; } else if (status == ValheimServer.ServerStatus.Updating) { btnWorking.ToolTip = "Updating..."; } menuSteamCmdUpdate.Visibility = Visibility.Collapsed; } //btnLog.IsEnabled = (File.Exists(Server.LogRawName)); btnLog.Visibility = (File.Exists(Server.LogRawName)) ? Visibility.Visible : Visibility.Collapsed; if (Properties.Settings.Default.SteamCMDPath != null && Properties.Settings.Default.SteamCMDPath.Length > 0 && File.Exists(Properties.Settings.Default.SteamCMDPath) && Server.InstallMethod == ValheimServer.ServerInstallMethod.SteamCMD) { btnSteamCmd.Visibility = Visibility.Visible; chkUpdateOnRestart.Visibility = Visibility.Visible; gridAutoUpdate.Visibility = Visibility.Visible; } else { btnSteamCmd.Visibility = Visibility.Collapsed; chkUpdateOnRestart.Visibility = Visibility.Collapsed; gridAutoUpdate.Visibility = Visibility.Collapsed; } if (uMod.AgentInstalled) { tabuMod.Visibility = Visibility.Visible; } else { tabuMod.Visibility = Visibility.Collapsed; } } catch (Exception ex) { LogMessage($"Error refreshing controls: {ex.Message}", LogEntryType.Error); } }); } private void RefreshControls(object sender, EventArgs e) { RefreshControls(); } private void RefreshControls(object sender, ServerStoppedEventArgs e) { RefreshControls(); } private void RefreshControls(object sender, PlayerEventArgs e) { RefreshControls(); } private void RefreshControls(object sender, ServerErrorEventArgs e) { RefreshControls(); } private void attachServerEventHandlers() { Server.LoggedMessage += ((object sender, LoggedMessageEventArgs e) => { this.Dispatcher.Invoke(() => { LogMessage(e.LogEntry); }); }); Server.Stopped += ((sender, e) => { RefreshControls(); UpdateServerResourcesUsed(); resourceTimer.Enabled = false; }); Server.PlayerConnected += RefreshControls; Server.PlayerDisconnected += RefreshControls; Server.PlayerDied += RefreshControls; Server.FailedPassword += RefreshControls; Server.Starting += RefreshControls; Server.Stopping += RefreshControls; Server.Started += ((sender, e) => { RefreshControls(); UpdateServerResourcesUsed(); resourceTimer.Enabled = true; }); Server.StartFailed += RefreshControls; Server.StopFailed += RefreshControls; Server.Updated += ((object sender, UpdatedEventArgs e) => { RefreshControls(); ServerToControls(); }); } private void ResourceTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { UpdateServerResourcesUsed(); } private void ServerToControls() { try { txtName.Text = Server.Name; txtPort.Text = Server.Port.ToString(); txtWorld.Text = Server.World; txtPassword.Text = Server.Password; txtSaveDir.Text = Server.SaveDir; chkPublic.IsChecked = Server.Public; if (Server.InstallPath != null) { txtServerDir.Text = Server.InstallPath; } else if (Properties.Settings.Default.ServerFilePath != null) { txtServerDir.Text = Properties.Settings.Default.ServerFilePath; } cmbServerType.SelectedIndex = (int)Server.InstallMethod; chkAutostart.IsChecked = Server.Autostart; chkRawLog.IsChecked = Server.RawLog; if (Server.RestartHours > 0) { chkAutoRestart.IsChecked = true; txtRestartInterval.Text = Server.RestartHours.ToString(); txtRestartInterval.IsEnabled = true; } else { chkAutoRestart.IsChecked = false; txtRestartInterval.IsEnabled = false; } chkUpdateOnRestart.IsChecked = Server.UpdateOnRestart; if (Server.UpdateCheckMinutes > 0) { chkAutoUpdate.IsChecked = true; txtUpdateCheckInterval.Text = Server.UpdateCheckMinutes.ToString(); txtUpdateCheckInterval.IsEnabled = true; } cmbPriority.SelectedItem = Server.ProcessPriority; chkuModUpdate.IsChecked = Server.AutoUpdateuMod; } catch (Exception ex) { LogMessage($"Error reading server settings: {ex.Message}", LogEntryType.Error); } } private void UpdateServerResourcesUsed() { this.Dispatcher.Invoke(() => { lblMemory.Content = Server.MemoryUsed.ToString("N0") + " MB"; }); } private void LoadLists() { try { string savedir; if (Server.SaveDir.Length > 0) { savedir = Server.SaveDir; } else { savedir = ValheimServer.DefaultSaveDir; } txtAdminList.Text = ""; txtBannedList.Text = ""; txtPermittedList.Text = ""; if (File.Exists(savedir+"\\adminlist.txt")) { txtAdminList.Text = File.ReadAllText(savedir + "\\adminlist.txt"); } if (File.Exists(savedir + "\\bannedlist.txt")) { txtBannedList.Text = File.ReadAllText(savedir + "\\bannedlist.txt"); } if (File.Exists(savedir + "\\permittedlist.txt")) { txtPermittedList.Text = File.ReadAllText(savedir + "\\permittedlist.txt"); } } catch (Exception ex) { LogMessage($"Error loading admin/banned/permitted list: {ex.Message}"); } } private void btnStart_Click(object sender, RoutedEventArgs e) { //btnStart.IsEnabled = false; //btnStart.Content = FindResource("StartGrey"); //OnStarting(new ServerEventArgs(this.Server)); Server.Start(); } /*private void OnStarting(ServerEventArgs args) { EventHandler<ServerEventArgs> handler = Starting; if (null != handler) handler(this, args); } private void OnStopping(ServerEventArgs args) { EventHandler<ServerEventArgs> handler = Stopping; if (null != handler) handler(this, args); }*/ private void OnShowLog(ServerEventArgs args) { EventHandler<ServerEventArgs> handler = ShowLog; if (null != handler) handler(this, args); } private void OnEditedServer(ServerEventArgs args) { EventHandler<ServerEventArgs> handler = EditedServer; if (null != handler) handler(this, args); } private void btnStop_Click(object sender, RoutedEventArgs e) { //btnStop.IsEnabled = false; //btnStop.Content = FindResource("StopGrey"); //OnStopping(new ServerEventArgs(this.Server)); Server.Stop(); } private void btnLog_Click(object sender, RoutedEventArgs e) { OnShowLog(new ServerEventArgs(this.Server)); } private void btnSave_Click(object sender, RoutedEventArgs e) { if (txtName.Text.Length > 0) { Server.Name = txtName.Text; Title = Server.DisplayName; } else { txtName.Text = Server.Name; } int port; if (int.TryParse(txtPort.Text, out port)) { Server.Port = port; } else { txtPort.Text = Server.Port.ToString(); } if (txtWorld.Text.Length > 0) { Server.World = txtWorld.Text; } else { txtWorld.Text = Server.World; } if (txtPassword.Text.Length == 0) { LogMessage("Warning: Servers must have passwords unless modded to remove that requirement."); } else if (txtPassword.Text.Length >= 5) { if (!Server.World.Contains(txtPassword.Text)) { Server.Password = txtPassword.Text; } else { var mmb = new ModernMessageBox(this); mmb.Show("Passwords must be at least 5 characters, and cannot be contained in your world name.", "Invalid Password", MessageBoxButton.OK, MessageBoxImage.Warning); txtPassword.Text = Server.Password; } } else { var mmb = new ModernMessageBox(this); mmb.Show("Passwords must be at least 5 characters, and cannot be contained in your world name.", "Invalid Password", MessageBoxButton.OK, MessageBoxImage.Warning); txtPassword.Text = Server.Password; } Server.Password = txtPassword.Text; Server.SaveDir = txtSaveDir.Text; Server.Public = chkPublic.IsChecked.GetValueOrDefault(); Server.InstallPath = txtServerDir.Text; Server.InstallMethod = (ValheimServer.ServerInstallMethod)cmbServerType.SelectedIndex; Server.Autostart = chkAutostart.IsChecked.GetValueOrDefault(); Server.RawLog = chkRawLog.IsChecked.GetValueOrDefault(); Server.ProcessPriority = (ProcessPriorityClass)cmbPriority.SelectedItem; int restartHours = Server.RestartHours; if (chkAutoRestart.IsChecked.GetValueOrDefault()) { int.TryParse(txtRestartInterval.Text, out restartHours); } else { restartHours = 0; } if (restartHours > -1) { Server.RestartHours = restartHours; } if (restartHours == 0) { txtRestartInterval.Text = ""; chkAutoRestart.IsChecked = false; } Server.UpdateOnRestart = chkUpdateOnRestart.IsChecked.GetValueOrDefault(); int updateCheckMinutes = Server.UpdateCheckMinutes; if (chkAutoUpdate.IsChecked.GetValueOrDefault()) { int.TryParse(txtUpdateCheckInterval.Text, out updateCheckMinutes); } else { updateCheckMinutes = 0; } if (updateCheckMinutes > -1) { Server.UpdateCheckMinutes = updateCheckMinutes; } if (updateCheckMinutes == 0) { txtUpdateCheckInterval.Text = ""; chkAutoUpdate.IsChecked = false; } OnEditedServer(new ServerEventArgs(this.Server)); RefreshControls(); if (Server.Running) { var mmb = new ModernMessageBox(this); mmb.Show("You must restart the server for the server name, port, world, password, save folder, or public status to change.", "Server Restart", MessageBoxButton.OK, MessageBoxImage.Information); } LoadLists(); } private void btnSaveDir_Click(object sender, RoutedEventArgs e) { string saveDirPath = txtSaveDir.Text; System.Windows.Forms.FolderBrowserDialog openFolderDialog = new System.Windows.Forms.FolderBrowserDialog(); openFolderDialog.SelectedPath = saveDirPath; openFolderDialog.UseDescriptionForTitle = true; openFolderDialog.Description = "Select save folder"; System.Windows.Forms.DialogResult result = openFolderDialog.ShowDialog(); if (result == System.Windows.Forms.DialogResult.OK) { string folderName = openFolderDialog.SelectedPath; if (folderName.Equals(saveDirPath)) { return; } /*if (!Directory.Exists($@"{folderName}\worlds")) { var mmb = new ModernMessageBox(this); mmb.Show("Please select the folder where your Valheim save files are located. This folder should contain a \"worlds\" folder.", "Invalid Folder", MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK); return; }*/ txtSaveDir.Text = folderName; } RefreshControls(); } private void menuSaveDirReset_Click(object sender, RoutedEventArgs e) { txtSaveDir.Text = ""; } private void dgPlayers_ContextMenuOpening(object sender, ContextMenuEventArgs e) { menuCopySteamId.IsEnabled = (dgPlayers.SelectedIndex != -1); } private void menuCopySteamId_Click(object sender, RoutedEventArgs e) { Player player = (Player)dgPlayers.SelectedItem; Clipboard.SetText(player.SteamID); } private void btnConnect_Click(object sender, RoutedEventArgs e) { menuConnect.IsOpen = true; } private void menuConnectLink_Click(object sender, RoutedEventArgs e) { // also test steam://run/892970//%2Bconnect%20{_externalIP}%3A{this.Server.Port} Clipboard.SetText($"steam://connect/{ValheimServer.ExternalIP}:{this.Server.Port + 1}"); } private void chkAutoRestart_Checked(object sender, RoutedEventArgs e) { txtRestartInterval.IsEnabled = chkAutoRestart.IsChecked.GetValueOrDefault(); if (chkAutoRestart.IsChecked.GetValueOrDefault() && txtRestartInterval.Text == "") { txtRestartInterval.Text = "4"; } } private void btnDiscordWebhook_Click(object sender, RoutedEventArgs e) { var webhookWin = new DiscordWebhookWindow(this.Server); webhookWin.ShowDialog(); } private void menuConnectCheckExternal_Click(object sender, RoutedEventArgs e) { //Process.Start("cmd", $"/C start https://southnode.net/form_get.php?ip={_externalIP}"); Process.Start("cmd", $"/C start https://geekstrom.de/valheim/check/?host={WebUtility.UrlEncode($"{ValheimServer.ExternalIP}:{Server.Port + 1}")}"); } private void btnSteamCmd_Click(object sender, RoutedEventArgs e) { btnSteamCmd.ContextMenu.IsOpen = true; } private void menuSteamCmdUpdate_Click(object sender, RoutedEventArgs e) { if (!Server.Running) { Server.Update(); } else { var mmb = new ModernMessageBox(this); mmb.Show("Please stop the server before updating.", "Stop Server to Update", MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK); } } public void LogMessage(string msg) { LogMessage(msg, LogEntryType.Normal); } public void LogMessage(string msg, LogEntryType lt) { LogMessage(new LogEntry(msg, lt)); } public void LogMessage(LogEntry entry) { try { this.Dispatcher.Invoke(() => { if (txtServerLog.Document.Blocks.Count > 0) { txtServerLog.Document.Blocks.InsertBefore(txtServerLog.Document.Blocks.FirstBlock, (Paragraph)entry); } else { txtServerLog.Document.Blocks.Add((Paragraph)entry); } }); } catch (Exception ex) { Debug.WriteLine($"Error logging message: {ex.Message}"); } } private void Window_ContentRendered(object sender, EventArgs e) { /*tabsServer.SelectedIndex = 1; UpdateLayout(); SizeToContent = SizeToContent.Manual; tabsServer.SelectedIndex = 0;*/ } private void btnServerDir_Click(object sender, RoutedEventArgs e) { var openFolderDialog = new System.Windows.Forms.FolderBrowserDialog(); if (txtServerDir.Text != "") { var serverpath = new FileInfo(txtServerDir.Text).Directory.FullName; if (Directory.Exists(serverpath)) { openFolderDialog.SelectedPath = serverpath; } } openFolderDialog.UseDescriptionForTitle = true; openFolderDialog.Description = "Server installation folder"; var result = openFolderDialog.ShowDialog(); if (result == System.Windows.Forms.DialogResult.OK) { var folderName = openFolderDialog.SelectedPath; /*if (folderName.Equals(serverpath)) { return; }*/ if (!File.Exists($@"{folderName}\{ValheimServer.ExecutableName}") && cmbServerType.SelectedIndex == (int)ValheimServer.ServerInstallMethod.SteamCMD && File.Exists(Properties.Settings.Default.SteamCMDPath)) { var mmb = new ModernMessageBox(this); var install = mmb.Show($"{ValheimServer.ExecutableName} was not found in this folder, do you want to install it via SteamCMD?", "Install Valheim dedicated server?", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No); if (install == MessageBoxResult.Yes) { try { var process = new Process(); process.StartInfo.FileName = Properties.Settings.Default.SteamCMDPath; process.StartInfo.Arguments = $"+login anonymous +force_install_dir \"{folderName}\" +app_update {ValheimServer.SteamID} +quit"; //process.EnableRaisingEvents = true; //process.Exited += SteamCmdProcess_Exited; process.Start(); process.WaitForExit(); } catch (Exception ex) { LogMessage($"Error installing dedicated server: {ex.Message}", LogEntryType.Error); } } } folderName += $@"\{ValheimServer.ExecutableName}"; txtServerDir.Text = folderName; } RefreshControls(); } private void menuServerDirReset_Click(object sender, RoutedEventArgs e) { txtServerDir.Text = Properties.Settings.Default.ServerFilePath; } private void txtServerDir_ContextMenuOpening(object sender, ContextMenuEventArgs e) { if (!File.Exists(txtServerDir.Text) && cmbServerType.SelectedIndex == (int)ValheimServer.ServerInstallMethod.SteamCMD && File.Exists(Properties.Settings.Default.SteamCMDPath)) { menuServerDirInstall.IsEnabled = true; menuServerDirInstall.Visibility = Visibility.Visible; } else { menuServerDirInstall.IsEnabled = false; menuServerDirInstall.Visibility = Visibility.Collapsed; } } private void menuLogClear_Click(object sender, RoutedEventArgs e) { txtServerLog.Document.Blocks.Clear(); Server.LogEntries.Clear(); } private void menuLogSelectAll_Click(object sender, RoutedEventArgs e) { txtServerLog.SelectAll(); } private void menuLog_Opened(object sender, RoutedEventArgs e) { if (txtServerLog.Selection.IsEmpty) { menuLogCopy.Visibility = Visibility.Collapsed; } else { menuLogCopy.Visibility = Visibility.Visible; } } private void menuLogCopy_Click(object sender, RoutedEventArgs e) { Clipboard.SetText(txtServerLog.Selection.Text); } private void btnSaveAdminList_Click(object sender, RoutedEventArgs e) { try { string savedir; if (Server.SaveDir.Length > 0) { savedir = Server.SaveDir; } else { savedir = ValheimServer.DefaultSaveDir; } File.WriteAllTextAsync(savedir + "\\adminlist.txt", txtAdminList.Text); LogMessage("Admin list updated.", LogEntryType.Success); } catch (Exception ex) { LogMessage($"Error updating admin list: {ex.Message}", LogEntryType.Error); } } private void btnSaveBannedList_Click(object sender, RoutedEventArgs e) { try { string savedir; if (Server.SaveDir.Length > 0) { savedir = Server.SaveDir; } else { savedir = ValheimServer.DefaultSaveDir; } File.WriteAllTextAsync(savedir + "\\bannedlist.txt", txtBannedList.Text); LogMessage("Banned list updated.", LogEntryType.Success); } catch (Exception ex) { LogMessage($"Error updating banned list: {ex.Message}", LogEntryType.Error); } } private void btnSavePermittedList_Click(object sender, RoutedEventArgs e) { try { string savedir; if (Server.SaveDir.Length > 0) { savedir = Server.SaveDir; } else { savedir = ValheimServer.DefaultSaveDir; } File.WriteAllTextAsync(savedir + "\\permittedlist.txt", txtPermittedList.Text); LogMessage("Permitted list updated.", LogEntryType.Success); } catch (Exception ex) { LogMessage($"Error updating permitted list: {ex.Message}", LogEntryType.Error); } } public void ThemeUpdated() { txtServerLog.Document.Blocks.Clear(); foreach (var entry in Server.LogEntries) { if (txtServerLog.Document.Blocks.Count > 0) { txtServerLog.Document.Blocks.InsertBefore(txtServerLog.Document.Blocks.FirstBlock, (Block)entry); } else { txtServerLog.Document.Blocks.Add((Block)entry); } } } private void menuSteamCmdCheckUpdate_Click(object sender, RoutedEventArgs e) { Server.CheckForUpdate(true); } private void chkAutoUpdate_Checked(object sender, RoutedEventArgs e) { txtUpdateCheckInterval.IsEnabled = chkAutoUpdate.IsChecked.GetValueOrDefault(); if (chkAutoUpdate.IsChecked.GetValueOrDefault() && txtUpdateCheckInterval.Text == "") { txtUpdateCheckInterval.Text = "20"; } } private void btnuModUpdate_Click(object sender, RoutedEventArgs e) { if (Server.Status == ValheimServer.ServerStatus.Stopped) { this.Dispatcher.Invoke(() => { btnuModUpdate.IsEnabled = false; }); var umod = new uMod(Server.InstallPath, "valheim"); umod.UpdateEnded += Umod_UpdateEnded; umod.LoggedMessage += (object sender, LoggedMessageEventArgs args) => { LogMessage("uMod: " + args.LogEntry.Message, args.LogEntry.Type); }; umod.Update("core apps extensions"); } else { var mmb = new ModernMessageBox(this); mmb.Show("Stop server before updating.", "Server Running", MessageBoxButton.OK, MessageBoxImage.Error); } } private void Umod_UpdateEnded(object sender, uMod.ProcessEndedEventArgs e) { this.Dispatcher.Invoke(() => { btnuModUpdate.IsEnabled = true; if (e.ExitCode == 0) { var mmb = new ModernMessageBox(this); mmb.Show("uMod update compelete.", "uMod Updated", MessageBoxButton.OK, MessageBoxImage.Information); } else if (e.ExitCode == 2) { var mmb = new ModernMessageBox(this); mmb.Show($"uMod did not need to install any updates.", "No Update Needed", MessageBoxButton.OK, MessageBoxImage.Information); } else { var mmb = new ModernMessageBox(this); mmb.Show($"uMod terminated with code {e.ExitCode}; unable to update uMod core or uMod apps.", "uMod Update Error", MessageBoxButton.OK, MessageBoxImage.Error); } }); } private void btnuModInstall_Click(object sender, RoutedEventArgs e) { if (Server.Status == ValheimServer.ServerStatus.Stopped) { this.Dispatcher.Invoke(() => { btnuModInstall.IsEnabled = false; }); var umod = new uMod(Server.InstallPath, "valheim"); umod.InstallEnded += Umod_InstallEnded; umod.LoggedMessage += (object sender, LoggedMessageEventArgs args) => { LogMessage("uMod: "+args.LogEntry.Message, args.LogEntry.Type); }; umod.Install("umod"); } else { var mmb = new ModernMessageBox(this); mmb.Show("Stop server before updating.", "Server Running", MessageBoxButton.OK, MessageBoxImage.Error); } } private void Umod_InstallEnded(object sender, uMod.ProcessEndedEventArgs e) { this.Dispatcher.Invoke(() => { btnuModInstall.IsEnabled = true; if (e.ExitCode == 0) { var mmb = new ModernMessageBox(this); mmb.Show("uMod installation compelete.", "uMod Installed", MessageBoxButton.OK, MessageBoxImage.Information); } else { var mmb = new ModernMessageBox(this); mmb.Show($"uMod terminated with code {e.ExitCode}, which indicates an error.", "uMod Installation Error", MessageBoxButton.OK, MessageBoxImage.Error); } }); } private void chkuModUpdate_Checked(object sender, RoutedEventArgs e) { Server.AutoUpdateuMod = chkuModUpdate.IsChecked.GetValueOrDefault(); } private void menuConnectPlay_Click(object sender, RoutedEventArgs e) { try { if (_steamPath != null) { //Process.Start(_steamPath, $"steam://connect/127.0.0.1:{this.Server.Port + 1}"); Process.Start(_steamPath, $"-applaunch 892970 +connect 127.0.0.1:{this.Server.Port} +password \"{this.Server.Password}\""); } else { Debug.WriteLine("Steam path not found"); } } catch (Exception ex) { Debug.WriteLine(ex); } } } public class ServerEventArgs : EventArgs { private readonly ValheimServer _server; public ServerEventArgs(ValheimServer server) { _server = server; } public ValheimServer Server { get { return _server; } } } }