package main import ( "encoding/json" "errors" "os" "path/filepath" ) // ПРИМЕЧАНИЕ: как и "Трупные батончики", "Странник" сохраняется на // диск — это открытая, долгоиграющая карьера без фиксированного // конца партии, и жалко было бы сбрасывать прогресс при каждом // выходе в меню. Остальные игры коллекции по-прежнему не сохраняются // между запусками. var ErrWayfarerNoSave = errors.New("файл сохранения не найден") func wayfarerSavePath() (string, error) { dir, err := os.UserConfigDir() if err != nil { return "", err } return filepath.Join(dir, "go-games-collection", "wayfarer_save.json"), nil } // SaveWayfarerShip сохраняет текущее состояние карьеры на диск. func SaveWayfarerShip(s *WayfarerShip) error { path, err := wayfarerSavePath() if err != nil { return err } if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return err } data, err := json.MarshalIndent(s, "", " ") if err != nil { return err } return os.WriteFile(path, data, 0o644) } // LoadWayfarerShip загружает сохранённую карьеру с диска. Возвращает // ErrWayfarerNoSave, если файла нет — вызывающий код должен в этом // случае начать новую карьеру. func LoadWayfarerShip() (*WayfarerShip, error) { path, err := wayfarerSavePath() if err != nil { return nil, err } data, err := os.ReadFile(path) if err != nil { if os.IsNotExist(err) { return nil, ErrWayfarerNoSave } return nil, err } var s WayfarerShip if err := json.Unmarshal(data, &s); err != nil { return nil, err } if s.Equipment == nil { s.Equipment = map[WayfarerEquipment]bool{} } if s.Visited == nil { s.Visited = map[WayfarerSystemID]bool{} } if s.CompletedQuests == nil { s.CompletedQuests = map[string]bool{} } if s.FailedQuests == nil { s.FailedQuests = map[string]bool{} } if s.MissileCapacity == 0 { // поле появилось уже после того, как некоторые сохранения были // созданы — без этой миграции у них "нет свободных слотов" // навсегда, хотя ракет на борту нет вовсе (0 >= 0) s.MissileCapacity = 2 } if len(s.Cargo) < len(WayfarerCommodities) { grown := make([]int, len(WayfarerCommodities)) copy(grown, s.Cargo) s.Cargo = grown } return &s, nil } // DeleteWayfarerSave удаляет файл сохранения (используется при // гибели корабля без спасательной капсулы — карьера окончена // безвозвратно, начинать заново нужно с чистого листа). func DeleteWayfarerSave() error { path, err := wayfarerSavePath() if err != nil { return err } err = os.Remove(path) if err != nil && !os.IsNotExist(err) { return err } return nil }