Менеджер запускает сервер PZ как дочерний процесс и держит его stdin/stdout: отсюда живая консоль без RCON, стриминг логов через SSE и корректная остановка по цепочке quit -> SIGTERM -> SIGKILL для всей группы процессов. Сам менеджер работает под systemd. Что входит: - управление жизненным циклом сервера, автозапуск и автоподъём после падения; - метрики процесса из /proc и состояние хоста, список игроков онлайн; - редакторы servertest.ini и SandboxVars.lua, сохраняющие исходное форматирование файлов; - моды: списки Workshop ID и Mod ID с порядком загрузки, названия из Steam; - бэкапы мира по расписанию и вручную, с ротацией и восстановлением; - установка и обновление сервера через SteamCMD; - вход по логину и паролю, первичная настройка по одноразовому коду. Веб-интерфейс без сборщика, вшит в бинарник через embed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
63 lines
1.9 KiB
Go
63 lines
1.9 KiB
Go
package pzconfig
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// javaLauncherFile — файл, из которого сервер берёт аргументы JVM.
|
|
const javaLauncherFile = "ProjectZomboid64.json"
|
|
|
|
var xmxRe = regexp.MustCompile(`^-Xm[sx]`)
|
|
|
|
// SetJavaMemory прописывает лимит памяти JVM в ProjectZomboid64.json. Именно
|
|
// оттуда start-server.sh берёт -Xmx, поэтому менять размер памяти в аргументах
|
|
// запуска бесполезно.
|
|
func SetJavaMemory(serverDir, memory string) error {
|
|
memory = strings.TrimSpace(memory)
|
|
if memory == "" {
|
|
return nil
|
|
}
|
|
if !regexp.MustCompile(`^[0-9]+[kKmMgG]$`).MatchString(memory) {
|
|
return fmt.Errorf("объём памяти должен выглядеть как 4g или 8192m, получено %q", memory)
|
|
}
|
|
|
|
path := filepath.Join(serverDir, javaLauncherFile)
|
|
raw, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return fmt.Errorf("прочитать %s: %w", path, err)
|
|
}
|
|
|
|
// Разбираем в map, чтобы не потерять поля, о которых мы не знаем.
|
|
var doc map[string]any
|
|
if err := json.Unmarshal(raw, &doc); err != nil {
|
|
return fmt.Errorf("разобрать %s: %w", path, err)
|
|
}
|
|
|
|
args, _ := doc["vmArgs"].([]any)
|
|
updated := make([]any, 0, len(args)+2)
|
|
for _, a := range args {
|
|
if str, ok := a.(string); ok && xmxRe.MatchString(str) {
|
|
continue
|
|
}
|
|
updated = append(updated, a)
|
|
}
|
|
// -Xms равным -Xmx: JVM сразу забирает память и не тратит время на рост
|
|
// кучи в момент, когда на сервере много игроков.
|
|
updated = append(updated, "-Xms"+memory, "-Xmx"+memory)
|
|
doc["vmArgs"] = updated
|
|
|
|
out, err := json.MarshalIndent(doc, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := backupFile(path); err != nil {
|
|
return err
|
|
}
|
|
return writeAtomic(path, out, 0o644)
|
|
}
|