181 lines
3.1 KiB
Go
181 lines
3.1 KiB
Go
package save
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
const (
|
|
dataFile = "data.toml"
|
|
)
|
|
|
|
// Save file structure
|
|
|
|
type Data struct {
|
|
Settings Settings `toml:"settings"`
|
|
GameState GameState `toml:"game_state"`
|
|
}
|
|
|
|
type Settings struct {
|
|
FPSMonitor bool `toml:"fps_monitor"`
|
|
FPSCap string `toml:"fps_cap"`
|
|
}
|
|
|
|
type GameState struct {
|
|
HasSave bool `toml:"has_save"`
|
|
SavedAt time.Time `toml:"saved_at"`
|
|
HeroX float64 `toml:"hero_x"`
|
|
HeroY float64 `toml:"hero_y"`
|
|
HeroStamina float64 `toml:"hero_stamina"`
|
|
PlayTimeMS int64 `toml:"play_time_ms"`
|
|
}
|
|
|
|
// Save manager
|
|
|
|
type Manager struct {
|
|
dataPath string
|
|
}
|
|
|
|
func NewManager() (*Manager, error) {
|
|
exePath, err := os.Executable()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get executable path: %w", err)
|
|
}
|
|
|
|
exeDir := filepath.Dir(exePath)
|
|
|
|
return &Manager{
|
|
dataPath: filepath.Join(exeDir, dataFile),
|
|
}, nil
|
|
}
|
|
|
|
// Data operations
|
|
|
|
func (m *Manager) LoadData() (*Data, error) {
|
|
if _, err := os.Stat(m.dataPath); os.IsNotExist(err) {
|
|
return &Data{
|
|
Settings: Settings{
|
|
FPSMonitor: false,
|
|
FPSCap: "60",
|
|
},
|
|
GameState: GameState{
|
|
HasSave: false,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
var data Data
|
|
if _, err := toml.DecodeFile(m.dataPath, &data); err != nil {
|
|
return nil, fmt.Errorf("failed to parse data file: %w", err)
|
|
}
|
|
|
|
return &data, nil
|
|
}
|
|
|
|
func (m *Manager) SaveData(data *Data) error {
|
|
file, err := os.Create(m.dataPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create data file: %w", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
encoder := toml.NewEncoder(file)
|
|
if err := encoder.Encode(data); err != nil {
|
|
return fmt.Errorf("failed to write data file: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Settings operations
|
|
|
|
func (m *Manager) LoadSettings() (*Settings, error) {
|
|
data, err := m.LoadData()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &data.Settings, nil
|
|
}
|
|
|
|
func (m *Manager) SaveSettings(settings *Settings) error {
|
|
data, err := m.LoadData()
|
|
if err != nil {
|
|
data = &Data{
|
|
Settings: *settings,
|
|
GameState: GameState{
|
|
HasSave: false,
|
|
},
|
|
}
|
|
} else {
|
|
data.Settings = *settings
|
|
}
|
|
|
|
return m.SaveData(data)
|
|
}
|
|
|
|
// Game state operations
|
|
|
|
func (m *Manager) LoadGameState() (*GameState, error) {
|
|
data, err := m.LoadData()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !data.GameState.HasSave {
|
|
return nil, nil
|
|
}
|
|
|
|
return &data.GameState, nil
|
|
}
|
|
|
|
func (m *Manager) SaveGameState(state *GameState) error {
|
|
data, err := m.LoadData()
|
|
if err != nil {
|
|
data = &Data{
|
|
Settings: Settings{
|
|
FPSMonitor: false,
|
|
FPSCap: "60",
|
|
},
|
|
GameState: *state,
|
|
}
|
|
} else {
|
|
data.GameState = *state
|
|
}
|
|
|
|
data.GameState.HasSave = true
|
|
data.GameState.SavedAt = time.Now()
|
|
|
|
return m.SaveData(data)
|
|
}
|
|
|
|
func (m *Manager) HasSavedGame() bool {
|
|
data, err := m.LoadData()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return data.GameState.HasSave
|
|
}
|
|
|
|
func (m *Manager) DeleteGameState() error {
|
|
data, err := m.LoadData()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
data.GameState = GameState{
|
|
HasSave: false,
|
|
}
|
|
|
|
return m.SaveData(data)
|
|
}
|
|
|
|
// Utilities
|
|
|
|
func (m *Manager) GetSaveFilePath() string {
|
|
return m.dataPath
|
|
}
|