Cambusta / Arma3-SSPSL

Straightforward Arma 3 Dedicated Server startup script that doesn't get in your way as you're trying to host that Escape mission on Sunday evening.
6 stars 4 forks source link

Headless Client #4

Open MrDerp53 opened 2 years ago

MrDerp53 commented 2 years ago

Love the tool, cuts back a lot of the hassle with Arma 3 hosting. Would it be possible to launch a headless client with it? I am currently doing it manually and it's an immense pain when modlists change.

Cambusta commented 2 years ago

Hey @MrDerp53, really glad that you've liked the tool!

Yes, implementing headless client startup definitely seems possible.!However I've never used them myself so it hard for me to tell how to better implement the configuration / startup procedure. I would appreciate if you could briefly describe the startup process you'd like to see for the headless client.

From what I gather, it seems that starting a headless client requires just two additional parameters, -client and -connect. I think both of these can be put into the tool's configuration in parameters.json where a user can configure them once and forget about them (they don't change too often, right?). Does this sound like a good way to implement this? 🙂

MrDerp53 commented 2 years ago

Those two parameters do most of the work. HCs can also use the -password parameter. As for implementation, maybe also a [Y/N] prompt to ask if you want to start a HC with the server, cause not all missions have headless clients.

Cambusta commented 2 years ago

Interesting, do I get it right that you're starting the Headless Client on the same PC as the server itself?

MrDerp53 commented 2 years ago

Yes, I use it as a way to get an extra CPU core to be used.

10Dozen commented 7 months ago

I am not sure about correctness, but that worked for us.

Added new function to start headless (via arma3_server.exe) and connect to 127.0.0.1 with given password:

# scripts/functions.ps1

function Start-HeadlessClient()
{
    param(
        $ModParameter,
        $ServerModParameter
    )

    $serverNameParameter = "-name=$profileName"
    $headlessClientConnectionParams = "-client -connect=127.0.0.1 -password=server_password"

    $serverExePath = Join-Path $a3RootPath $serverExeName
    $serverConfigParameter = '"-config=' + $(Resolve-Path $serverConfigPath) + '"'
    $basicConfigParameter = '"-cfg=' + $(Resolve-Path $basicConfigPath) +'"'
    $profilesParameter = '"-profiles=' + $(Resolve-Path $profilesPath) + '"'

    Write-Host "Starting headless with $headlessClientConnectionParams..."

    $argumentList = @($serverNameParameter,  $basicConfigParameter, $serverConfigParameter, $profilesParameter, $headlessClientConnectionParams)

    if ($ModParameter)
    {
        $argumentList += $ModParameter
    }

    if ($ServerModParameter)
    {
        $argumentList += $ServerModParameter
    }

    Start-Process -FilePath $serverExePath -ArgumentList $argumentList

    Write-Host "Headless started." -ForegroundColor Black -BackgroundColor Green
    Write-Host
}

And used this function in launch script (with option to not start headless):

# scripts/launch.ps1

function Launch()
{
    Set-WindowTitle

    $launcherParameters = Read-LauncherParametersFile $launcherParametersFile

    $a3RootPath = $launcherParameters.Arma3RootPath
    $serverExeName = $launcherParameters.ServerExeName
    $port = $launcherParameters.Port
    $webhook = $launcherParameters.Webhook
    $executeWebhook = $webhook.Enabled

    if (!(Confirm-ServerNotRunning))
    {
        Write-Host "Another server instance is already running." -BackgroundColor Yellow -ForegroundColor Black
    }

    Write-Host
    Write-Host "Reading presets..."

    Write-Host
    $presets = Get-PresetFiles

    if ($PresetFileName)
    {
        $preset = Select-PresetByName -PresetList $presets -PresetName $PresetFileName
    }
    else
    {
        Write-PresetList $presets

        Write-Host
        $preset = Select-PresetByIndex $presets

        Write-Host
        $executeWebhook = Read-WebhookExecution $webhook.Enabled
    }

    Write-Host
    $mods = Read-PresetFile $($preset.Path)
    $modParameter = Initialize-GlobalModParameter -ModNames $mods.global
    $serverModParameter = Initialize-ServerModParameter -ModNames $mods.server
    Write-OptionalMods -ModNames $mods.optional

    if ($NoKeyCopying -ne $true)
    {
        Write-Host
        Clear-KeysFolder
        Copy-Keys -ModNames $($mods.global + $mods.server + $mods.optional)
    }

    if ($executeWebhook)
    {
        $content = Initialize-WebhookContent $mods.global $mods.optional $port
        Invoke-Webhook $content $webhook
    }

    Write-Host
    Write-Host "Do you want to start Headless Client?: [Y]es or any key to skip" -BackgroundColor Green -ForegroundColor Black
    $response = [console]::ReadKey()

    Write-Host
    Start-Server -ModParameter $modParameter -ServerModParameter $serverModParameter

    if ($response.Key -eq 'Y')
    {
        Start-HeadlessClient -ModParameter $modParameter -ServerModParameter $serverModParameter
    }
    Read-ExitAction

    Write-Host
    Write-Host "Exiting." -ForegroundColor Black -BackgroundColor DarkGray
    exit
}

One also must to update server.cfg and allow headless client connections:

// server.cfg
headlessClients[] = {"127.0.0.1"}; 
localClient[] = {"127.0.0.1"};

P.S. Proper implementation may need separate profile and modset definition, but in our case same profile and mod set was good enough. Another point is server password and a way to pass it to HC params. We are using hardcoded value, but for public release it may be set via parameters.json.