Импорт пресета песочницы .cfg и списка модов
Сборки нередко раздают только пресет одиночной игры. Внутри это плоский список «Параметр=значение» с точками вместо вложенности, поэтому значения переносятся в SandboxVars.lua профиля по одному: комментарии игры и порядок остаются на месте, а параметры модов, которых в файле ещё нет, пропускаются со счётом. Если файла нет вовсе, он собирается из пресета целиком. Заодно панель принимает строку из игровой кнопки «Поделиться» («Название:ModA;ModB;…»): она заменяет список включённых модов, сохраняя порядок загрузки. Идентификаторов мастерской в такой строке нет, поэтому пакеты добавляются только для модов, чьи файлы уже на диске, а про остальные панель предупреждает. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+55
-21
@@ -32,28 +32,35 @@ const (
|
||||
// ErrNoServerFiles возвращается, когда в архиве нет ни одного серверного файла.
|
||||
var ErrNoServerFiles = errors.New("в архиве нет серверных файлов Project Zomboid")
|
||||
|
||||
// ErrNoSandboxPreset — загруженный .cfg не похож на пресет песочницы.
|
||||
var ErrNoSandboxPreset = errors.New("файл не похож на пресет песочницы")
|
||||
|
||||
// Files — серверная часть пакета: то, что PZ читает при запуске.
|
||||
type Files struct {
|
||||
// Name — имя, под которым файлы лежали в архиве (sophie-server-42-2).
|
||||
Name string
|
||||
INI []byte
|
||||
Sandbox []byte
|
||||
SpawnRegions []byte
|
||||
Name string
|
||||
INI []byte
|
||||
Sandbox []byte
|
||||
// SandboxPreset — пресет песочницы одиночной игры (.cfg). Готового файла
|
||||
// сервера в пакете может не быть: сборки нередко раздают только его.
|
||||
SandboxPreset []byte
|
||||
SpawnRegions []byte
|
||||
}
|
||||
|
||||
// Summary — то, что панель показывает до импорта, чтобы человек понимал, что
|
||||
// именно он собирается записать поверх своих настроек.
|
||||
type Summary struct {
|
||||
Name string `json:"name"`
|
||||
ServerName string `json:"server_name"`
|
||||
Maps []string `json:"maps"`
|
||||
Mods int `json:"mods"`
|
||||
WorkshopItems int `json:"workshop_items"`
|
||||
Settings int `json:"settings"`
|
||||
SandboxSettings int `json:"sandbox_settings"`
|
||||
HasINI bool `json:"has_ini"`
|
||||
HasSandbox bool `json:"has_sandbox"`
|
||||
HasSpawnRegions bool `json:"has_spawn_regions"`
|
||||
Name string `json:"name"`
|
||||
ServerName string `json:"server_name"`
|
||||
Maps []string `json:"maps"`
|
||||
Mods int `json:"mods"`
|
||||
WorkshopItems int `json:"workshop_items"`
|
||||
Settings int `json:"settings"`
|
||||
SandboxSettings int `json:"sandbox_settings"`
|
||||
HasINI bool `json:"has_ini"`
|
||||
HasSandbox bool `json:"has_sandbox"`
|
||||
HasSandboxPreset bool `json:"has_sandbox_preset"`
|
||||
HasSpawnRegions bool `json:"has_spawn_regions"`
|
||||
}
|
||||
|
||||
// markers — параметры, по которым .ini опознаётся как конфиг сервера. В
|
||||
@@ -67,6 +74,19 @@ var markers = []string{
|
||||
|
||||
const markersRequired = 3
|
||||
|
||||
// FromUpload разбирает то, что загрузили в панель: ZIP-пакет сборки или
|
||||
// одиночный пресет песочницы.
|
||||
func FromUpload(filename string, data []byte) ([]Files, error) {
|
||||
if strings.HasSuffix(strings.ToLower(filename), ".cfg") {
|
||||
if !looksLikeSandboxPreset(data) {
|
||||
return nil, ErrNoSandboxPreset
|
||||
}
|
||||
name := strings.TrimSuffix(path.Base(filename), path.Ext(filename))
|
||||
return []Files{{Name: name, SandboxPreset: data}}, nil
|
||||
}
|
||||
return FromZip(data)
|
||||
}
|
||||
|
||||
// FromZip достаёт из архива все наборы серверных файлов. Наборов может быть
|
||||
// несколько: сборки иногда кладут рядом варианты конфигов.
|
||||
func FromZip(data []byte) ([]Files, error) {
|
||||
@@ -106,6 +126,11 @@ func FromZip(data []byte) ([]Files, error) {
|
||||
if kind == kindINI && !looksLikeServerConfig(content) {
|
||||
continue
|
||||
}
|
||||
// .cfg в архиве хватает и помимо песочницы: списки модов, настройки
|
||||
// папок. Отличаем по знакомым параметрам.
|
||||
if kind == kindSandboxPreset && !looksLikeSandboxPreset(content) {
|
||||
continue
|
||||
}
|
||||
|
||||
set := sets[base]
|
||||
if set == nil {
|
||||
@@ -117,6 +142,8 @@ func FromZip(data []byte) ([]Files, error) {
|
||||
set.INI = content
|
||||
case kindSandbox:
|
||||
set.Sandbox = content
|
||||
case kindSandboxPreset:
|
||||
set.SandboxPreset = content
|
||||
case kindSpawnRegions:
|
||||
set.SpawnRegions = content
|
||||
}
|
||||
@@ -125,7 +152,7 @@ func FromZip(data []byte) ([]Files, error) {
|
||||
out := make([]Files, 0, len(sets))
|
||||
for _, set := range sets {
|
||||
// Одни точки появления без конфига и песочницы импортировать некуда.
|
||||
if set.INI == nil && set.Sandbox == nil {
|
||||
if set.INI == nil && set.Sandbox == nil && set.SandboxPreset == nil {
|
||||
continue
|
||||
}
|
||||
out = append(out, *set)
|
||||
@@ -143,6 +170,7 @@ const (
|
||||
kindOther kind = iota
|
||||
kindINI
|
||||
kindSandbox
|
||||
kindSandboxPreset
|
||||
kindSpawnRegions
|
||||
)
|
||||
|
||||
@@ -156,6 +184,8 @@ func classify(name string) (string, kind) {
|
||||
return name[:len(name)-len("_spawnregions.lua")], kindSpawnRegions
|
||||
case strings.HasSuffix(lower, ".ini"):
|
||||
return name[:len(name)-len(".ini")], kindINI
|
||||
case strings.HasSuffix(lower, ".cfg"):
|
||||
return name[:len(name)-len(".cfg")], kindSandboxPreset
|
||||
}
|
||||
return "", kindOther
|
||||
}
|
||||
@@ -193,11 +223,12 @@ func readEntry(entry *zip.File) ([]byte, error) {
|
||||
// Describe собирает сводку по набору: сколько модов, карт и параметров.
|
||||
func (f Files) Describe() Summary {
|
||||
s := Summary{
|
||||
Name: f.Name,
|
||||
HasINI: f.INI != nil,
|
||||
HasSandbox: f.Sandbox != nil,
|
||||
HasSpawnRegions: f.SpawnRegions != nil,
|
||||
Maps: []string{},
|
||||
Name: f.Name,
|
||||
HasINI: f.INI != nil,
|
||||
HasSandbox: f.Sandbox != nil,
|
||||
HasSandboxPreset: f.SandboxPreset != nil,
|
||||
HasSpawnRegions: f.SpawnRegions != nil,
|
||||
Maps: []string{},
|
||||
}
|
||||
if f.INI != nil {
|
||||
ini := pzconfig.ParseINI(f.INI)
|
||||
@@ -207,8 +238,11 @@ func (f Files) Describe() Summary {
|
||||
s.Maps = splitList(ini.Get("Map"))
|
||||
s.Settings = len(ini.Keys())
|
||||
}
|
||||
if f.Sandbox != nil {
|
||||
switch {
|
||||
case f.Sandbox != nil:
|
||||
s.SandboxSettings = len(pzconfig.ParseSandbox(f.Sandbox).Entries())
|
||||
case f.SandboxPreset != nil:
|
||||
s.SandboxSettings = len(ParseSandboxPreset(f.SandboxPreset).Values)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user