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

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

Аўтар вельмі любіць гульню, і сам з'яўляецца адміністратарам невялікага сервера "чыста для сяброў". Як водзіцца сярод аматараў, на серверы замадзіравана ўсё, а гэта цягне за сабой нестабільнасць працы і як следства падзення. Так як Powershell аўтар ведае лепш, чым размяшчэнне крам на сваёй вуліцы, ён прыняў рашэнне зрабіць.Лепшы Скрыпт Для Запуску Майнкрафт 2020». Гэты ж скрыпт паслужыў асновай для шаблону ў маркетплэйсе Ruvds. Але ўсе зыходнікі ўжо ёсць у артыкуле. Цяпер па парадку, як гэта ўсё рабілася.

Патрэбныя нам каманды

Альтэрнатыўнае лагіраванне

Аднойчы паставіўшы яшчэ пару модаў я выявіў, што сервер, судзячы па ўсім, падае без аб'яўлення вайны. Сервер не пісаў памылкі ў latest.log ці ў debug, а кансоль, якая па ідэі гэтую памылку павінна была напісаць і спыніцца, была зачынена.

Не хоча пісаць - не трэба. У нас ёсць Powershell з камандлетам Tee-Object, які бярэ аб'ект і выводзіць яго ў файл і ў кансоль адначасова.

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

Такім чынам, Powershell будзе забіраць StandardOutput і запісваць яго ў файл. Не спрабуйце выкарыстоўваць Start-Process, таму што ён верне 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

Дадаць каментар