package player import ( "fmt" "os" "path/filepath" "strings" "gopkg.in/yaml.v3" "thehouseoficarus/internal/item" ) type AccountStore struct { dataDir string } func NewAccountStore(dataDir string) *AccountStore { return &AccountStore{dataDir: dataDir} } func (s *AccountStore) AccountPath(name string) string { return filepath.Join(s.dataDir, "players", "accounts", name+".yaml") } func (s *AccountStore) LoadAccount(name string) (*Account, error) { path := s.AccountPath(name) data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("account not found: %s", name) } var acc Account if err := yaml.Unmarshal(data, &acc); err != nil { return nil, fmt.Errorf("parse account: %w", err) } return &acc, nil } func (s *AccountStore) SaveAccount(acc *Account) error { path := s.AccountPath(acc.Name) data, err := yaml.Marshal(acc) if err != nil { return err } return os.WriteFile(path, data, 0644) } func (s *AccountStore) AccountExists(name string) bool { _, err := s.FindAccount(name) return err == nil } func (s *AccountStore) FindAccount(name string) (string, error) { path := s.AccountPath(name) if _, err := os.Stat(path); err == nil { return name, nil } dir := filepath.Join(s.dataDir, "players", "accounts") entries, err := os.ReadDir(dir) if err != nil { return "", fmt.Errorf("account not found: %s", name) } lower := strings.ToLower(name) for _, e := range entries { if e.IsDir() { continue } base := strings.TrimSuffix(e.Name(), ".yaml") if strings.ToLower(base) == lower { return base, nil } } return "", fmt.Errorf("account not found: %s", name) } func (s *AccountStore) CharPath(name string) string { return filepath.Join(s.dataDir, "players", "characters", name+".yaml") } func (s *AccountStore) LoadCharacter(name string) (*Player, error) { path := s.CharPath(name) data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("character not found: %s", name) } var p Player if err := yaml.Unmarshal(data, &p); err != nil { return nil, fmt.Errorf("parse character: %w", err) } if p.Skills == nil { p.Skills = make(map[SkillName]int) } if p.Equipment == nil { p.Equipment = make(map[item.EquipSlot]string) } if p.Inventory == nil { p.Inventory = make(map[int]*InventorySlot) } if p.MapSymbols == nil { p.MapSymbols = make(map[int]MapSymbolData) } return &p, nil } func (s *AccountStore) SaveCharacter(p *Player) error { path := s.CharPath(p.Name) data, err := yaml.Marshal(p) if err != nil { return err } return os.WriteFile(path, data, 0644) } func (s *AccountStore) CharacterExists(name string) bool { _, err := s.FindCharacter(name) return err == nil } func (s *AccountStore) FindCharacter(name string) (string, error) { path := s.CharPath(name) if _, err := os.Stat(path); err == nil { return name, nil } dir := filepath.Join(s.dataDir, "players", "characters") entries, err := os.ReadDir(dir) if err != nil { return "", fmt.Errorf("character not found: %s", name) } lower := strings.ToLower(name) for _, e := range entries { if e.IsDir() { continue } base := strings.TrimSuffix(e.Name(), ".yaml") if strings.ToLower(base) == lower { return base, nil } } return "", fmt.Errorf("character not found: %s", name) }