# Abiotic Factor Server Manager Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $configPath = "$scriptDir\server_config.json" $script:serverProcess = $null $script:configChanged = $false # Get local IP address function Get-LocalIP { $ip = Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notlike "*Loopback*" -and $_.InterfaceAlias -notlike "*Virtual*" -and $_.IPAddress -notlike "169.254.*" } | Select-Object -First 1 if ($ip) { return $ip.IPAddress } return "127.0.0.1" } # Get public IP (WAN) function Get-PublicIP { try { $wanIP = (Invoke-WebRequest -Uri "https://api.ipify.org" -UseBasicParsing -TimeoutSec 3).Content return $wanIP } catch { return "Unavailable" } } # Load/Save Config function Load-Config { if (Test-Path $configPath) { try { $cfg = Get-Content $configPath -Raw | ConvertFrom-Json $txtSteamCMDDir.Text = $cfg.SteamCMDDir $txtInstallDir.Text = $cfg.InstallDir $txtMaxPlayers.Text = $cfg.MaxPlayers $txtPort.Text = $cfg.Port $txtQueryPort.Text = $cfg.QueryPort $txtServerPassword.Text = $cfg.ServerPassword $txtAdminPassword.Text = $cfg.AdminPassword $txtServerName.Text = $cfg.ServerName $script:configChanged = $false $btnSave.BackColor = [System.Drawing.Color]::FromArgb(240, 240, 240) } catch { Set-Defaults } } else { Set-Defaults } Update-SteamCMDStatus Update-GameDirStatus } function Set-Defaults { $txtSteamCMDDir.Text = Join-Path $scriptDir "SteamCMD" $txtInstallDir.Text = Join-Path $scriptDir "ServerFiles" $txtMaxPlayers.Text = "6" $txtPort.Text = "7777" $txtQueryPort.Text = "27015" $txtServerPassword.Text = "" $txtAdminPassword.Text = "" $txtServerName.Text = "My Abiotic Factor Server" $script:configChanged = $false $btnSave.BackColor = [System.Drawing.Color]::FromArgb(240, 240, 240) } function Save-Config { $cfg = @{ SteamCMDDir = $txtSteamCMDDir.Text InstallDir = $txtInstallDir.Text MaxPlayers = $txtMaxPlayers.Text Port = $txtPort.Text QueryPort = $txtQueryPort.Text ServerPassword = $txtServerPassword.Text AdminPassword = $txtAdminPassword.Text ServerName = $txtServerName.Text } $cfg | ConvertTo-Json | Out-File $configPath -Encoding UTF8 -Force $script:configChanged = $false $btnSave.BackColor = [System.Drawing.Color]::FromArgb(240, 240, 240) Update-SteamCMDStatus Update-GameDirStatus } function Mark-ConfigChanged { if (-not $script:configChanged) { $script:configChanged = $true $btnSave.BackColor = [System.Drawing.Color]::LightBlue } } function Update-SteamCMDStatus { $exe = "$($txtSteamCMDDir.Text)\steamcmd.exe" if (Test-Path $exe) { $lblSteamCMDStatus.Text = "SteamCMD: Ready" $lblSteamCMDStatus.ForeColor = "Green" $btnInstallSteamCMD.Enabled = $false $btnInstallSteamCMD.Text = "SteamCMD Installed" } else { $lblSteamCMDStatus.Text = "SteamCMD: Not Found" $lblSteamCMDStatus.ForeColor = "Red" $btnInstallSteamCMD.Enabled = $true $btnInstallSteamCMD.Text = "Install SteamCMD" } } function Update-GameDirStatus { $installDir = $txtInstallDir.Text if (-not $installDir) { $lblGameDirStatus.Text = "Game Directory: Not Set" $lblGameDirStatus.ForeColor = "Red" return } $serverExe = Join-Path $installDir "AbioticFactor\Binaries\Win64\AbioticFactorServer-Win64-Shipping.exe" if (Test-Path $serverExe) { $lblGameDirStatus.Text = "Game Directory: Ready" $lblGameDirStatus.ForeColor = "Green" } else { $lblGameDirStatus.Text = "Game Directory: Not Found (Run Update Server)" $lblGameDirStatus.ForeColor = "Red" } } function Check-ServerSetupComplete { $installDir = $txtInstallDir.Text if (-not $installDir) { return $false } $serverExe = Join-Path $installDir "AbioticFactor\Binaries\Win64\AbioticFactorServer-Win64-Shipping.exe" return (Test-Path $serverExe) } function Install-SteamCMD { $path = $txtSteamCMDDir.Text if (-not $path) { return } if (Test-Path "$path\steamcmd.exe") { Update-SteamCMDStatus return } New-Item -ItemType Directory -Path $path -Force | Out-Null $zip = "$env:TEMP\steamcmd.zip" $wc = New-Object System.Net.WebClient $wc.DownloadFile("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip", $zip) $shell = New-Object -ComObject Shell.Application $shell.NameSpace($zip).Items() | ForEach-Object { $shell.NameSpace($path).CopyHere($_, 16) } Start-Sleep -Seconds 2 Remove-Item $zip -Force Update-SteamCMDStatus Save-Config } function Update-Server { if (-not (Test-Path "$($txtSteamCMDDir.Text)\steamcmd.exe")) { [System.Windows.Forms.MessageBox]::Show("Please install SteamCMD first!", "Error", "OK", "Error") return } $installDir = $txtInstallDir.Text if (-not $installDir) { $installDir = "$($txtSteamCMDDir.Text)\AbioticFactorServer" $txtInstallDir.Text = $installDir Save-Config } New-Item -ItemType Directory -Path $installDir -Force | Out-Null $appId = "2857200" $scriptFile = [System.IO.Path]::GetTempFileName() + ".txt" $scriptContent = "@ShutdownOnFailedCommand 0`n" $scriptContent += "@NoPromptForPassword 1`n" $scriptContent += "force_install_dir `"$installDir`"`n" $scriptContent += "login anonymous`n" $scriptContent += "app_update $appId`n" $scriptContent += "app_update $appId validate`n" $scriptContent += "quit`n" $scriptContent | Out-File $scriptFile -Encoding ASCII $steamCMDExe = "$($txtSteamCMDDir.Text)\steamcmd.exe" $arguments = "+runscript `"$scriptFile`"" Write-Host "Updating server. Please wait..." $process = Start-Process -FilePath $steamCMDExe -ArgumentList $arguments -Wait -PassThru -NoNewWindow $process.WaitForExit() Start-Sleep -Seconds 2 try { Remove-Item $scriptFile -Force -ErrorAction SilentlyContinue } catch {} Write-Host "Update complete!" Update-GameDirStatus [System.Windows.Forms.MessageBox]::Show("Server update completed!", "Success", "OK", "Information") } function Start-Server { if ($script:configChanged) { $result = [System.Windows.Forms.MessageBox]::Show("You have unsaved configuration changes.`n`nDo you want to save them before starting the server?", "Unsaved Changes", "YesNoCancel", "Question") if ($result -eq "Cancel") { return } if ($result -eq "Yes") { Save-Config } } $installDir = $txtInstallDir.Text if (-not $installDir) { [System.Windows.Forms.MessageBox]::Show("Please set Game Install Directory first!", "Error", "OK", "Error") return } $serverExe = Join-Path $installDir "AbioticFactor\Binaries\Win64\AbioticFactorServer-Win64-Shipping.exe" if (-not (Test-Path $serverExe)) { [System.Windows.Forms.MessageBox]::Show("Server not found! Please run Update Server first.", "Error", "OK", "Error") return } $binariesDir = Join-Path $installDir "AbioticFactor\Binaries\Win64" $appIdFile = Join-Path $binariesDir "steam_appid.txt" "2896390" | Out-File -FilePath $appIdFile -Encoding ASCII -Force $args = "-log -newconsole -useperfthreads -NoAsyncLoadingThread -MaxServerPlayers=$($txtMaxPlayers.Text) -PORT=$($txtPort.Text) -QueryPort=$($txtQueryPort.Text)" if ($txtServerPassword.Text) { $args += " -ServerPassword=`"$($txtServerPassword.Text)`"" } if ($txtAdminPassword.Text) { $args += " -AdminPassword=`"$($txtAdminPassword.Text)`"" } if ($txtServerName.Text) { $args += " -SteamServerName=`"$($txtServerName.Text)`"" } try { $script:serverProcess = Start-Process -FilePath $serverExe -ArgumentList $args -WorkingDirectory $binariesDir -PassThru $btnStop.Enabled = $true $btnStart.Enabled = $false $btnUpdate.Enabled = $false $lblStatusValue.Text = "RUNNING" $lblStatusValue.ForeColor = "Green" } catch { [System.Windows.Forms.MessageBox]::Show("Failed to start server: $_", "Error", "OK", "Error") } } function Stop-Server { if ($script:serverProcess -and (-not $script:serverProcess.HasExited)) { $script:serverProcess.Kill() $script:serverProcess.WaitForExit(3000) } Get-Process -Name "AbioticFactorServer-Win64-Shipping" -ErrorAction SilentlyContinue | ForEach-Object { try { $_.Kill() } catch {} } $script:serverProcess = $null $btnStop.Enabled = $false $btnStart.Enabled = $true $btnUpdate.Enabled = $true $lblStatusValue.Text = "STOPPED" $lblStatusValue.ForeColor = "Red" } function Browse-Directory { param($txtBox) $dlg = New-Object System.Windows.Forms.FolderBrowserDialog if ($dlg.ShowDialog() -eq "OK") { $txtBox.Text = $dlg.SelectedPath if ($txtBox.Name -eq "txtSteamCMDDir") { Update-SteamCMDStatus } if ($txtBox.Name -eq "txtInstallDir") { Update-GameDirStatus } Mark-ConfigChanged } } function Show-Password { param($txtBox) if ($txtBox.PasswordChar -eq '*') { $txtBox.PasswordChar = $null } else { $txtBox.PasswordChar = '*' } } # Create Form $form = New-Object System.Windows.Forms.Form $form.Text = "Abiotic Factor Server Manager" $form.Size = New-Object System.Drawing.Size(920, 780) $form.StartPosition = "CenterScreen" $form.MinimumSize = New-Object System.Drawing.Size(920, 780) $form.MaximumSize = New-Object System.Drawing.Size(920, 780) $form.FormBorderStyle = "FixedDialog" $form.MaximizeBox = $false $stdButtonWidth = 120 $stdButtonHeight = 32 # Status Panel $statusPanel = New-Object System.Windows.Forms.Panel $statusPanel.BackColor = [System.Drawing.Color]::FromArgb(240, 240, 240) $statusPanel.Location = New-Object System.Drawing.Point(0, 0) $statusPanel.Size = New-Object System.Drawing.Size(920, 100) $statusPanel.BorderStyle = "FixedSingle" # Logo/Image Area with embedded image $logoBox = New-Object System.Windows.Forms.PictureBox $logoBox.Location = New-Object System.Drawing.Point(15, 15) $logoBox.Size = New-Object System.Drawing.Size(70, 70) $logoBox.Width = 70 $logoBox.Height = 70 $logoBox.BackColor = [System.Drawing.Color]::Transparent $logoBox.BorderStyle = "None" $logoBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom # Embedded image (replace YOUR_BASE64_STRING_HERE with your actual base64 string) $base64String = "#" if ($base64String -and $base64String -ne "#") { $imageBytes = [System.Convert]::FromBase64String($base64String) $ms = New-Object System.IO.MemoryStream($imageBytes, 0, $imageBytes.Length) $ms.Write($imageBytes, 0, $imageBytes.Length) $logoBox.Image = [System.Drawing.Image]::FromStream($ms) $ms.Close() } $statusPanel.Controls.Add($logoBox) $lblStatusLabel = New-Object System.Windows.Forms.Label $lblStatusLabel.Text = "Server Status:" $lblStatusLabel.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold) $lblStatusLabel.Location = New-Object System.Drawing.Point(100, 15) $lblStatusLabel.Size = New-Object System.Drawing.Size(100, 20) $statusPanel.Controls.Add($lblStatusLabel) $lblStatusValue = New-Object System.Windows.Forms.Label $lblStatusValue.Text = "STOPPED" $lblStatusValue.ForeColor = "Red" $lblStatusValue.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold) $lblStatusValue.Location = New-Object System.Drawing.Point(200, 15) $lblStatusValue.Size = New-Object System.Drawing.Size(100, 20) $statusPanel.Controls.Add($lblStatusValue) $lblServerNameLabel = New-Object System.Windows.Forms.Label $lblServerNameLabel.Text = "Server Name:" $lblServerNameLabel.Font = New-Object System.Drawing.Font("Segoe UI", 8) $lblServerNameLabel.Location = New-Object System.Drawing.Point(100, 40) $lblServerNameLabel.Size = New-Object System.Drawing.Size(80, 18) $statusPanel.Controls.Add($lblServerNameLabel) $lblServerNameValue = New-Object System.Windows.Forms.Label $lblServerNameValue.Font = New-Object System.Drawing.Font("Segoe UI", 8, [System.Drawing.FontStyle]::Bold) $lblServerNameValue.Location = New-Object System.Drawing.Point(180, 40) $lblServerNameValue.Size = New-Object System.Drawing.Size(400, 18) $lblServerNameValue.AutoEllipsis = $true $statusPanel.Controls.Add($lblServerNameValue) $lblPortLabel = New-Object System.Windows.Forms.Label $lblPortLabel.Text = "Game Port:" $lblPortLabel.Font = New-Object System.Drawing.Font("Segoe UI", 8) $lblPortLabel.Location = New-Object System.Drawing.Point(100, 63) $lblPortLabel.Size = New-Object System.Drawing.Size(70, 18) $statusPanel.Controls.Add($lblPortLabel) $lblPortValue = New-Object System.Windows.Forms.Label $lblPortValue.Text = "7777" $lblPortValue.Font = New-Object System.Drawing.Font("Segoe UI", 8) $lblPortValue.Location = New-Object System.Drawing.Point(170, 63) $lblPortValue.Size = New-Object System.Drawing.Size(60, 18) $statusPanel.Controls.Add($lblPortValue) $lblPasswordLabel = New-Object System.Windows.Forms.Label $lblPasswordLabel.Text = "Password:" $lblPasswordLabel.Font = New-Object System.Drawing.Font("Segoe UI", 8) $lblPasswordLabel.Location = New-Object System.Drawing.Point(250, 63) $lblPasswordLabel.Size = New-Object System.Drawing.Size(65, 18) $statusPanel.Controls.Add($lblPasswordLabel) $lblPasswordValue = New-Object System.Windows.Forms.Label $lblPasswordValue.Font = New-Object System.Drawing.Font("Segoe UI", 8) $lblPasswordValue.Location = New-Object System.Drawing.Point(315, 63) $lblPasswordValue.Size = New-Object System.Drawing.Size(80, 18) $statusPanel.Controls.Add($lblPasswordValue) $lblLocalLabel = New-Object System.Windows.Forms.Label $lblLocalLabel.Text = "Local IP:" $lblLocalLabel.Font = New-Object System.Drawing.Font("Segoe UI", 8) $lblLocalLabel.Location = New-Object System.Drawing.Point(590, 15) $lblLocalLabel.Size = New-Object System.Drawing.Size(60, 18) $statusPanel.Controls.Add($lblLocalLabel) $lblLocalValue = New-Object System.Windows.Forms.Label $lblLocalValue.Text = (Get-LocalIP) $lblLocalValue.Font = New-Object System.Drawing.Font("Segoe UI", 8) $lblLocalValue.Location = New-Object System.Drawing.Point(650, 15) $lblLocalValue.Size = New-Object System.Drawing.Size(230, 18) $statusPanel.Controls.Add($lblLocalValue) $lblWANLabel = New-Object System.Windows.Forms.Label $lblWANLabel.Text = "WAN IP:" $lblWANLabel.Font = New-Object System.Drawing.Font("Segoe UI", 8) $lblWANLabel.Location = New-Object System.Drawing.Point(590, 40) $lblWANLabel.Size = New-Object System.Drawing.Size(60, 18) $statusPanel.Controls.Add($lblWANLabel) $lblWANValue = New-Object System.Windows.Forms.Label $lblWANValue.Text = (Get-PublicIP) $lblWANValue.Font = New-Object System.Drawing.Font("Segoe UI", 8) $lblWANValue.Location = New-Object System.Drawing.Point(650, 40) $lblWANValue.Size = New-Object System.Drawing.Size(230, 18) $statusPanel.Controls.Add($lblWANValue) $form.Controls.Add($statusPanel) # Server Controls GroupBox $controlsGroup = New-Object System.Windows.Forms.GroupBox $controlsGroup.Text = "Server Controls" $controlsGroup.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold) $controlsGroup.Location = New-Object System.Drawing.Point(15, 110) $controlsGroup.Size = New-Object System.Drawing.Size(880, 70) $form.Controls.Add($controlsGroup) $btnSave = New-Object System.Windows.Forms.Button $btnSave.Text = "Save Config" $btnSave.Size = New-Object System.Drawing.Size($stdButtonWidth, $stdButtonHeight) $btnSave.Location = New-Object System.Drawing.Point(20, 25) $btnSave.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnSave.Add_Click({ Save-Config }) $controlsGroup.Controls.Add($btnSave) $btnUpdate = New-Object System.Windows.Forms.Button $btnUpdate.Text = "Update Server" $btnUpdate.Size = New-Object System.Drawing.Size($stdButtonWidth, $stdButtonHeight) $btnUpdate.Location = New-Object System.Drawing.Point(155, 25) $btnUpdate.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnUpdate.Add_Click({ Update-Server }) $controlsGroup.Controls.Add($btnUpdate) $btnStart = New-Object System.Windows.Forms.Button $btnStart.Text = "Start Server" $btnStart.Size = New-Object System.Drawing.Size($stdButtonWidth, $stdButtonHeight) $btnStart.Location = New-Object System.Drawing.Point(290, 25) $btnStart.BackColor = [System.Drawing.Color]::LightGreen $btnStart.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnStart.Add_Click({ Start-Server }) $controlsGroup.Controls.Add($btnStart) $btnStop = New-Object System.Windows.Forms.Button $btnStop.Text = "Stop Server" $btnStop.Size = New-Object System.Drawing.Size($stdButtonWidth, $stdButtonHeight) $btnStop.Location = New-Object System.Drawing.Point(425, 25) $btnStop.BackColor = [System.Drawing.Color]::LightCoral $btnStop.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnStop.Enabled = $false $btnStop.Add_Click({ Stop-Server }) $controlsGroup.Controls.Add($btnStop) # Settings Panel $settingsPanel = New-Object System.Windows.Forms.Panel $settingsPanel.Location = New-Object System.Drawing.Point(15, 190) $settingsPanel.Size = New-Object System.Drawing.Size(880, 490) $settingsPanel.AutoScroll = $true $form.Controls.Add($settingsPanel) # SteamCMD Group $steamCMDGroup = New-Object System.Windows.Forms.GroupBox $steamCMDGroup.Text = "SteamCMD Configuration" $steamCMDGroup.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold) $steamCMDGroup.Location = New-Object System.Drawing.Point(5, 5) $steamCMDGroup.Size = New-Object System.Drawing.Size(855, 90) $settingsPanel.Controls.Add($steamCMDGroup) $lbl1 = New-Object System.Windows.Forms.Label $lbl1.Text = "SteamCMD Directory:" $lbl1.Font = New-Object System.Drawing.Font("Segoe UI", 9) $lbl1.Location = New-Object System.Drawing.Point(15, 30) $lbl1.Size = New-Object System.Drawing.Size(135, 22) $steamCMDGroup.Controls.Add($lbl1) $txtSteamCMDDir = New-Object System.Windows.Forms.TextBox $txtSteamCMDDir.Location = New-Object System.Drawing.Point(155, 28) $txtSteamCMDDir.Size = New-Object System.Drawing.Size(450, 23) $txtSteamCMDDir.Font = New-Object System.Drawing.Font("Segoe UI", 9) $txtSteamCMDDir.Name = "txtSteamCMDDir" $steamCMDGroup.Controls.Add($txtSteamCMDDir) $btnBrowse1 = New-Object System.Windows.Forms.Button $btnBrowse1.Text = "Browse" $btnBrowse1.Location = New-Object System.Drawing.Point(615, 27) $btnBrowse1.Size = New-Object System.Drawing.Size(90, 26) $btnBrowse1.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnBrowse1.Add_Click({ Browse-Directory $txtSteamCMDDir }) $steamCMDGroup.Controls.Add($btnBrowse1) $btnInstallSteamCMD = New-Object System.Windows.Forms.Button $btnInstallSteamCMD.Location = New-Object System.Drawing.Point(715, 27) $btnInstallSteamCMD.Size = New-Object System.Drawing.Size(125, 26) $btnInstallSteamCMD.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnInstallSteamCMD.Add_Click({ Install-SteamCMD }) $steamCMDGroup.Controls.Add($btnInstallSteamCMD) $lblSteamCMDStatus = New-Object System.Windows.Forms.Label $lblSteamCMDStatus.Location = New-Object System.Drawing.Point(155, 60) $lblSteamCMDStatus.Size = New-Object System.Drawing.Size(450, 20) $lblSteamCMDStatus.Font = New-Object System.Drawing.Font("Segoe UI", 9) $steamCMDGroup.Controls.Add($lblSteamCMDStatus) # Install Dir Group $installGroup = New-Object System.Windows.Forms.GroupBox $installGroup.Text = "Game Installation" $installGroup.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold) $installGroup.Location = New-Object System.Drawing.Point(5, 105) $installGroup.Size = New-Object System.Drawing.Size(855, 90) $settingsPanel.Controls.Add($installGroup) $lbl2 = New-Object System.Windows.Forms.Label $lbl2.Text = "Game Install Directory:" $lbl2.Font = New-Object System.Drawing.Font("Segoe UI", 9) $lbl2.Location = New-Object System.Drawing.Point(15, 30) $lbl2.Size = New-Object System.Drawing.Size(135, 22) $installGroup.Controls.Add($lbl2) $txtInstallDir = New-Object System.Windows.Forms.TextBox $txtInstallDir.Location = New-Object System.Drawing.Point(155, 28) $txtInstallDir.Size = New-Object System.Drawing.Size(540, 23) $txtInstallDir.Font = New-Object System.Drawing.Font("Segoe UI", 9) $installGroup.Controls.Add($txtInstallDir) $btnBrowse2 = New-Object System.Windows.Forms.Button $btnBrowse2.Text = "Browse" $btnBrowse2.Location = New-Object System.Drawing.Point(705, 27) $btnBrowse2.Size = New-Object System.Drawing.Size(90, 26) $btnBrowse2.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnBrowse2.Add_Click({ Browse-Directory $txtInstallDir }) $installGroup.Controls.Add($btnBrowse2) $lblGameDirStatus = New-Object System.Windows.Forms.Label $lblGameDirStatus.Location = New-Object System.Drawing.Point(155, 60) $lblGameDirStatus.Size = New-Object System.Drawing.Size(540, 20) $lblGameDirStatus.Font = New-Object System.Drawing.Font("Segoe UI", 9) $installGroup.Controls.Add($lblGameDirStatus) # Server Settings Group $serverGroup = New-Object System.Windows.Forms.GroupBox $serverGroup.Text = "Server Settings" $serverGroup.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold) $serverGroup.Location = New-Object System.Drawing.Point(5, 205) $serverGroup.Size = New-Object System.Drawing.Size(855, 185) $settingsPanel.Controls.Add($serverGroup) $lblMax = New-Object System.Windows.Forms.Label $lblMax.Text = "Max Players:" $lblMax.Font = New-Object System.Drawing.Font("Segoe UI", 9) $lblMax.Location = New-Object System.Drawing.Point(15, 32) $lblMax.Size = New-Object System.Drawing.Size(90, 22) $serverGroup.Controls.Add($lblMax) $txtMaxPlayers = New-Object System.Windows.Forms.TextBox $txtMaxPlayers.Location = New-Object System.Drawing.Point(110, 30) $txtMaxPlayers.Size = New-Object System.Drawing.Size(100, 23) $txtMaxPlayers.Font = New-Object System.Drawing.Font("Segoe UI", 9) $serverGroup.Controls.Add($txtMaxPlayers) $lblPort = New-Object System.Windows.Forms.Label $lblPort.Text = "Game Port:" $lblPort.Font = New-Object System.Drawing.Font("Segoe UI", 9) $lblPort.Location = New-Object System.Drawing.Point(235, 32) $lblPort.Size = New-Object System.Drawing.Size(80, 22) $serverGroup.Controls.Add($lblPort) $txtPort = New-Object System.Windows.Forms.TextBox $txtPort.Location = New-Object System.Drawing.Point(320, 30) $txtPort.Size = New-Object System.Drawing.Size(100, 23) $txtPort.Font = New-Object System.Drawing.Font("Segoe UI", 9) $serverGroup.Controls.Add($txtPort) $lblQuery = New-Object System.Windows.Forms.Label $lblQuery.Text = "Query Port:" $lblQuery.Font = New-Object System.Drawing.Font("Segoe UI", 9) $lblQuery.Location = New-Object System.Drawing.Point(445, 32) $lblQuery.Size = New-Object System.Drawing.Size(85, 22) $serverGroup.Controls.Add($lblQuery) $txtQueryPort = New-Object System.Windows.Forms.TextBox $txtQueryPort.Location = New-Object System.Drawing.Point(535, 30) $txtQueryPort.Size = New-Object System.Drawing.Size(100, 23) $txtQueryPort.Font = New-Object System.Drawing.Font("Segoe UI", 9) $serverGroup.Controls.Add($txtQueryPort) $lblPassServer = New-Object System.Windows.Forms.Label $lblPassServer.Text = "Server Password:" $lblPassServer.Font = New-Object System.Drawing.Font("Segoe UI", 9) $lblPassServer.Location = New-Object System.Drawing.Point(15, 75) $lblPassServer.Size = New-Object System.Drawing.Size(115, 22) $serverGroup.Controls.Add($lblPassServer) $txtServerPassword = New-Object System.Windows.Forms.TextBox $txtServerPassword.Location = New-Object System.Drawing.Point(135, 73) $txtServerPassword.Size = New-Object System.Drawing.Size(200, 23) $txtServerPassword.Font = New-Object System.Drawing.Font("Segoe UI", 9) $txtServerPassword.PasswordChar = '*' $serverGroup.Controls.Add($txtServerPassword) $btnViewServerPass = New-Object System.Windows.Forms.Button $btnViewServerPass.Text = "Ⓟ" $btnViewServerPass.Location = New-Object System.Drawing.Point(340, 72) $btnViewServerPass.Size = New-Object System.Drawing.Size(30, 25) $btnViewServerPass.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnViewServerPass.Add_Click({ Show-Password $txtServerPassword }) $serverGroup.Controls.Add($btnViewServerPass) $lblAdmin = New-Object System.Windows.Forms.Label $lblAdmin.Text = "Admin Password:" $lblAdmin.Font = New-Object System.Drawing.Font("Segoe UI", 9) $lblAdmin.Location = New-Object System.Drawing.Point(410, 75) $lblAdmin.Size = New-Object System.Drawing.Size(120, 22) $serverGroup.Controls.Add($lblAdmin) $txtAdminPassword = New-Object System.Windows.Forms.TextBox $txtAdminPassword.Location = New-Object System.Drawing.Point(535, 73) $txtAdminPassword.Size = New-Object System.Drawing.Size(200, 23) $txtAdminPassword.Font = New-Object System.Drawing.Font("Segoe UI", 9) $txtAdminPassword.PasswordChar = '*' $serverGroup.Controls.Add($txtAdminPassword) $btnViewAdminPass = New-Object System.Windows.Forms.Button $btnViewAdminPass.Text = "Ⓟ" $btnViewAdminPass.Location = New-Object System.Drawing.Point(740, 72) $btnViewAdminPass.Size = New-Object System.Drawing.Size(30, 25) $btnViewAdminPass.Font = New-Object System.Drawing.Font("Segoe UI", 9) $btnViewAdminPass.Add_Click({ Show-Password $txtAdminPassword }) $serverGroup.Controls.Add($btnViewAdminPass) $lblName = New-Object System.Windows.Forms.Label $lblName.Text = "Server Name:" $lblName.Font = New-Object System.Drawing.Font("Segoe UI", 9) $lblName.Location = New-Object System.Drawing.Point(15, 118) $lblName.Size = New-Object System.Drawing.Size(115, 22) $serverGroup.Controls.Add($lblName) $txtServerName = New-Object System.Windows.Forms.TextBox $txtServerName.Location = New-Object System.Drawing.Point(135, 116) $txtServerName.Size = New-Object System.Drawing.Size(650, 23) $txtServerName.Font = New-Object System.Drawing.Font("Segoe UI", 9) $serverGroup.Controls.Add($txtServerName) # Bottom Info Panel (replaces startup popup) $bottomInfoPanel = New-Object System.Windows.Forms.Panel $bottomInfoPanel.BackColor = [System.Drawing.Color]::FromArgb(255, 255, 225) $bottomInfoPanel.Location = New-Object System.Drawing.Point(0, 700) $bottomInfoPanel.Size = New-Object System.Drawing.Size(920, 50) $bottomInfoPanel.BorderStyle = "FixedSingle" $bottomInfoLabel = New-Object System.Windows.Forms.Label $bottomInfoLabel.Text = "Setup Guide: Set SteamCMD Directory → Install SteamCMD → Set Game Install Directory → Update Server → Configure Settings → Save Config → Start Server" $bottomInfoLabel.Font = New-Object System.Drawing.Font("Segoe UI", 8) $bottomInfoLabel.Location = New-Object System.Drawing.Point(10, 5) $bottomInfoLabel.Size = New-Object System.Drawing.Size(895, 40) $bottomInfoLabel.TextAlign = "MiddleLeft" $bottomInfoPanel.Controls.Add($bottomInfoLabel) $form.Controls.Add($bottomInfoPanel) # Event handlers $txtPort.Add_TextChanged({ $lblPortValue.Text = $txtPort.Text Mark-ConfigChanged }) $txtServerName.Add_TextChanged({ $lblServerNameValue.Text = $txtServerName.Text Mark-ConfigChanged }) $txtServerPassword.Add_TextChanged({ if ($txtServerPassword.Text) { $lblPasswordValue.Text = "Set" $lblPasswordValue.ForeColor = "Green" } else { $lblPasswordValue.Text = "None" $lblPasswordValue.ForeColor = "Gray" } Mark-ConfigChanged }) $txtMaxPlayers.Add_TextChanged({ Mark-ConfigChanged }) $txtQueryPort.Add_TextChanged({ Mark-ConfigChanged }) $txtAdminPassword.Add_TextChanged({ Mark-ConfigChanged }) $txtSteamCMDDir.Add_TextChanged({ Mark-ConfigChanged Update-SteamCMDStatus }) $txtInstallDir.Add_TextChanged({ Mark-ConfigChanged Update-GameDirStatus }) # Initialize display values $lblPortValue.Text = "7777" $lblServerNameValue.Text = "My Abiotic Factor Server" $lblPasswordValue.Text = "None" $lblPasswordValue.ForeColor = "Gray" # Load config and check setup (no popups) Load-Config # Silently check server setup - updates UI status without popup $null = Check-ServerSetupComplete $form.ShowDialog()