Ідеальний скрипт запуску сервера Minecraft

Ідеальний скрипт запуску сервера Minecraft

Автор дуже любить гру, і сам є адміністратором невеликого сервера "чисто для друзів". Як водиться серед любителів, на сервері замодовано все, а це спричиняє нестабільність роботи і як наслідок падіння. Оскільки Powershell автор знає краще, ніж розташування магазинів на своїй вулиці, він вирішив зробити «Найкращий Скрипт Для Запуску Майнкрафт 2020». Цей же скрипт послужив основою для шаблону маркетплейсі Ruvds. Але всі вихідники вже є у статті. Зараз по порядку, як це все робилося.

Потрібні нам команди

Альтернативне логування

Якось поставивши ще пару модів я виявив, що сервер, зважаючи на все, падає без оголошення війни. Сервер не писав помилки в latest.log або в debug, а консоль, яка, за ідеєю, цю помилку повинна була написати і зупинитися, була закрита.

Не хоче писати – не треба. У нас є Powershell із командлетом Трійник-об'єкт, який бере об'єкт і виводить його у файл і консоль одночасно.

.handler.ps1 | Tee-Object .StandardOutput.txt -Append

Таким чином, Powershell забиратиме StandardOutput і записуватиме його у файл. Не намагайтеся використовувати Пуск-процес, тому що він поверне System.ComponentModel.Component, а не StandardOutput, а -RedirectStandardOutput унеможливить введення в консоль, чого ми хочемо уникнути.

Аргументи запуску

Поставивши ту саму пару модів, автор зауважив, що на сервері ще не вистачає оперативної пам'яті. А це треба міняти аргументи запуску. Замість кожного разу змінювати їх у start.bat, який всі використовують просто використовуйте цей скрипт.

Так як Tee-Object читає StandardOutput, тільки коли файл, що виконується, викликається «Прямо так», доведеться зробити ще один скрипт. Цей скрипт запускатиме сам майнкрафт. Почнемо із аргументів.

Щоб у майбутньому вдаватися до ультимативної ліні, скрипт повинен збирати аргументи запуску на льоту. Для цього почнемо з пошуку останньої версії кувати.

$forge = ((Get-ChildItem | Where-Object Name -Like "forge*").Name | Sort-Object -Descending) | Select-Object -last 1

За допомогою sort-object ми завжди братимемо об'єкт із найбільшою циферкою, скільки б ви туди їх не поклали. Ультимативна лінь.

Тепер потрібно призначити сервер пам'ять. Для цього беремо кількість системної пам'яті та записуємо його суму у string.

$ram = ((Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb)
$xmx = "-Xms" + $ram + "G"

Правильний автоматичний перезапуск

Автор бачив файли .bat від інших людей, але вони не враховували причину, з якої сервер був зупинений. Це незручно, якщо потрібно просто поміняти файл мода або видалити щось?
Тепер зробимо правильний перезапуск. Автор раніше натикався на дивні скрипти, які перезапускали сервер, незважаючи на те, чому сервер завершив роботу. Ми будемо використовувати exitcode. Java використовує 0 як успішне завершення, звідси і танцюватимемо.

Спочатку створимо функцію, яка перезапускатиме сервер у разі його невдалого завершення його роботи.

function Get-MinecraftExitCode {
   
    do {
        
        if ($global:Process.ExitCode -ne 0) {
            Write-Log
            Restart-Minecraft
        }
        else {
            Write-Log
        }
 
    } until ($global:Process.ExitCode -eq 0)
    
}

Скрипт залишиться в циклі до тих пір, поки сервер зі своєї консолі не завершить роботу штатно, за допомогою команди / stop.

Якщо ми всі вирішили автоматизувати, то непогано б і збирати дату запуску, завершення, а також причину завершення.

Для цього ми записуємо результат Start-Process у змінну. У скрипті це виглядає так:

$global:Process = Start-Process -FilePath  "C:Program Files (x86)common filesOracleJavajavapath_target_*java.exe" -ArgumentList "$xmx -server -jar $forge nogui" -Wait -NoNewWindow -PassThru

А далі записуємо результати у файл. Ось що повертається нам у змінну:

$global:Process.StartTime
$global:Process.ExitCode	
$global:Process.ExitTime

Все це за допомогою Add-Content можна додати до файлу. Трохи зачесаючи, отримуємо такий скрипт, а на кличемо його handler.ps1.

Add-Content -Value "Start time:" -Path $Logfile 
$global:Process.StartTime
 
Add-Content -Value "Exit code:" -Path $Logfile 
$global:Process.ExitCode | Add-Content $Logfile
    
Add-Content -Value "Exit time:" -Path $Logfile 
$global:Process.ExitTime | Add-Content $Logfile

Тепер давайте оформимо скрипт із запуском handler'a.

Правильне автозавантаження

Автор хоче одним модулем запускати майнкрафт різних версій із будь-яких шляхів, а також мати можливість складати логи в конкретну папку.

Проблема полягає в тому, що процес повинен запустити користувач, який перебуває в системі. Це можна робити через робочий стіл або WinRm. Якщо запускати сервер від імені системи або навіть адміністратора, але не входити до системи, Server.jar не зможе навіть прочитати eula.txt і запуститися.

Включити автовхід до системи ми можемо за допомогою додавання трьох записів до Реєстру.

New-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -Name DefaultUserName -Value $Username -ErrorAction SilentlyContinue
New-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -Name DefaultPassword -Value $Password  -ErrorAction SilentlyContinue
New-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -Name AutoAdminLogon -Value 1 -ErrorAction SilentlyContinue

Це не безпечно. Логін і пароль вказуються тут плейнтекстом, тому під запуск сервера потрібно заводити окремого користувача, який має доступ на рівні користувача, або ще вужчій групі. Використовувати стандартного адміністратора категорично не рекомендується.

З автовходом розібралися. Тепер потрібно зареєструвати нову таску під сервер. Запускатимемо команду з Powershell, тому виглядатиме це так:

$Trigger = New-ScheduledTaskTrigger -AtLogOn
$User = "ServerAdmin"
$PS = New-ScheduledTaskAction -Execute 'PowerShell.exe" -Argument "Start-Minecraft -Type Forge -LogFile "C:minecraftstdout.txt" -MinecraftPath "C:minecraft"'
Register-ScheduledTask -TaskName "StartSSMS" -Trigger $Trigger -User $User -Action $PS -RunLevel Highest

Збираємо модуль

Тепер давайте оформимо все у модулі, які можна буде потім використовувати. Весь код готових скриптів тут, імпортуйте та користуйтеся.

Все описане вище можна використовувати окремо, якщо не хочете морочитися з модулями.

Start-Minecraft

Спочатку зробимо модуль, який тільки й буде робити, що запускатиме скрипт, який слухатиме і записуватиме standardoutput.

У блоці параметрів він запитує з якої папки запускати майнкрафт і куди складати балку.

Set-Location (Split-Path $MyInvocation.MyCommand.Path)
function Start-Minecraft {
    [CmdletBinding()]
    param (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]
        $LogFile,
 
        [Parameter(Mandatory)]  
        [ValidateSet('Vanilla', 'Forge')]
        [ValidateNotNullOrEmpty()]
        [string]
        $Type,
 
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $MinecraftPath
 
    )
    powershell.exe -file .handler.ps1 -type $type -MinecraftPath $MinecraftPath | Tee-Object $LogFile -Append
}
Export-ModuleMember -Function Start-Minecraft

А запускати майнкрафт потрібно буде так:

Start-Minecraft -Type Forge -LogFile "C:minecraftstdout.txt" -MinecraftPath "C:minecraft"

Тепер перейдемо до готового до вживання Handler.ps1

Щоб наш скрипт міг приймати параметри під час дзвінка, також потрібно вказувати блок параметрів. Зверніть увагу, він запускає Oracle Java, якщо ви використовуєте інший дистрибутив, потрібно буде змінити шлях до файлу, що виконується.

param (
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string]$type,
 
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string]$MinecraftPath,
 
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string]$StandardOutput
)
 
Set-Location $MinecraftPath
 
function Restart-Minecraft {
 
    Write-host "=============== Starting godlike game server ============"
 
    $forge = ((Get-ChildItem | Where-Object Name -Like "forge*").Name | Sort-Object -Descending) | Select-Object -first 1
 
    $ram = ((Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb)
    $xmx = "-Xms" + $ram + "G"
    $global:Process = Start-Process -FilePath  "C:Program Files (x86)common filesOracleJavajavapath_target_*java.exe" -ArgumentList "$xmx -server -jar $forge nogui" -Wait -NoNewWindow -PassThru
    
}
 
function Write-Log {
    Write-host "Start time:" $global:Process.StartTime
 
    Write-host "Exit code:" $global:Process.ExitCode
    
    Write-host "Exit time:" $global:Process.ExitTime
 
    Write-host "=============== Stopped godlike game server ============="
}
 
function Get-MinecraftExitCode {
   
    do {
        
        if ($global:Process.ExitCode -ne 0) {
            Restart-Minecraft
            Write-Log
        }
        else {
            Write-Log
        }
 
    } until ($global:Process.ExitCode -eq 0)
    
}
 
Get-MinecraftExitCode

Register-Minecraft

Скрипт практично повторює Start-Minecraft, за винятком того, що тільки реєструє нове завдання. Приймає ті самі аргументи. Ім'я користувача, якщо не було вказано, набирає поточного.

function Register-Minecraft {
    [CmdletBinding()]
    param (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]
        $LogFile,
 
        [Parameter(Mandatory)]  
        [ValidateSet('Vanilla', 'Forge')]
        [ValidateNotNullOrEmpty()]
        [string]$Type,
 
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$MinecraftPath,
 
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$User,
 
        [Parameter(Mandatory)]
        [string]$TaskName = $env:USERNAME
    )
 
    $Trigger = New-ScheduledTaskTrigger -AtLogOn
    $arguments = "Start-Minecraft -Type $Type -LogFile $LogFile -MinecraftPath $MinecraftPath"
    $PS = New-ScheduledTaskAction -Execute "PowerShell" -Argument "-noexit -command $arguments"
    Register-ScheduledTask -TaskName $TaskName -Trigger $Trigger -User $User -Action $PS -RunLevel Highest
    
}
 
Export-ModuleMember -Function Register-Minecraft

Register-Autologon

У блоці параметрів скрипт приймає параметр Username та Password. Якщо Username не було вказано, використовується ім'я користувача.

function Set-Autologon {
 
    param (
        [Parameter(
        HelpMessage="Username for autologon")]
        $Username = $env:USERNAME,
 
        [Parameter(Mandatory=$true,
        HelpMessage="User password")]
        [ValidateNotNullOrEmpty()]
        $Password
    )
 
    $i = Get-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon"
 
    if ($null -eq $i) {
        New-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -Name DefaultUserName -Value $Username
        New-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -Name DefaultPassword -Value $Password 
        New-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -Name AutoAdminLogon -Value 1
        Write-Verbose "Set-Autologon will enable user auto logon."
 
    }
    else {
        Set-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -Name DefaultUserName -Value $Username
        Set-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -Name DefaultPassword -Value $Password
        Set-ItemProperty -Path "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -Name AutoAdminLogon -Value 1
    }
 
    
    Write-Verbose "Autologon was set successfully."
 
}

Запуск цього скрипта виглядає так:

Set-Autologon -Password "PlaintextPassword"

Як користуватися

Зараз розглянемо, як сам автор користується всім цим. Як правильно потрібно розгортати громадський сервер Minecraft на Windows. Почнемо із самого початку.

1. Створюємо користувача

$pass = Get-Credential
New-LocalUser -Name "MinecraftServer" -Password $pass.Password -AccountNeverExpires -PasswordNeverExpires -UserMayNotChangePassword

2. Реєструємо завдання із запуску скрипту

Можете зареєструвати за допомогою модуля так:

Register-Minecraft -Type Forge -LogFile "C:minecraftstdout.txt" -MinecraftPath "C:minecraft" -User "MInecraftServer" -TaskName "MinecraftStarter"

Або скористатися стандартними засобами:

$Trigger = New-ScheduledTaskTrigger -AtLogOn
$User = "ServerAdmin"
$PS = New-ScheduledTaskAction -Execute 'PowerShell.exe" -Argument "Start-Minecraft -Type Forge -LogFile "C:minecraftstdout.txt" -MinecraftPath "C:minecraft"'
Register-ScheduledTask -TaskName "StartSSMS" -Trigger $Trigger -User $User -Action $PS -RunLevel Highest

3. Включаємо автовхід у систему та перезавантажуємо машину

Set-Autologon -Username "MinecraftServer" -Password "Qw3"

Завершення

Автор робив скрипт, у тому числі і для себе, тому із задоволенням вислухає ваші пропозиції щодо покращення скрипту. Автор сподівається, що весь цей код був для вас хоча б мінімально корисним, а стаття цікава.

Ідеальний скрипт запуску сервера Minecraft

Джерело: habr.com

Додати коментар або відгук