Веб-панель управления сервером Project Zomboid
Менеджер запускает сервер 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>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user