diff --git a/pkg/accounts/accounts.go b/pkg/accounts/accounts.go index ae72732..578271f 100644 --- a/pkg/accounts/accounts.go +++ b/pkg/accounts/accounts.go @@ -26,12 +26,11 @@ type Account struct { // Represents the accountant data to store type accountantData struct { - Accounts map[uuid.UUID]Account `json:"accounts"` } // Accountant manages a set of accounts type Accountant struct { - data accountantData + Accounts map[uuid.UUID]Account `json:"accounts"` dataPath string } @@ -39,9 +38,7 @@ type Accountant struct { func NewAccountant(dataPath string) *Accountant { return &Accountant{ dataPath: dataPath, - data: accountantData{ - Accounts: make(map[uuid.UUID]Account), - }, + Accounts: make(map[uuid.UUID]Account), } } @@ -52,7 +49,7 @@ func (a *Accountant) RegisterAccount(acc Account) (Account, error) { acc.Id = uuid.New() // Verify this acount isn't already registered - for _, a := range a.data.Accounts { + for _, a := range a.Accounts { if a.Name == acc.Name { return Account{}, fmt.Errorf("Account name already registered") } else if a.Id == acc.Id { @@ -61,7 +58,7 @@ func (a *Accountant) RegisterAccount(acc Account) (Account, error) { } // Simply add the account to the map - a.data.Accounts[acc.Id] = acc + a.Accounts[acc.Id] = acc return acc, nil } @@ -82,7 +79,7 @@ func (a *Accountant) Load() error { if b, err := ioutil.ReadFile(a.path()); err != nil { return err - } else if err := json.Unmarshal(b, &a.data); err != nil { + } else if err := json.Unmarshal(b, &a); err != nil { return err } return nil @@ -90,7 +87,7 @@ func (a *Accountant) Load() error { // Save will save the accountant data out func (a *Accountant) Save() error { - if b, err := json.MarshalIndent(a.data, "", "\t"); err != nil { + if b, err := json.MarshalIndent(a, "", "\t"); err != nil { return err } else { if err := ioutil.WriteFile(a.path(), b, os.ModePerm); err != nil { @@ -104,9 +101,9 @@ func (a *Accountant) Save() error { func (a *Accountant) AssignPrimary(account uuid.UUID, instance uuid.UUID) error { // Find the account matching the ID - if this, ok := a.data.Accounts[account]; ok { + if this, ok := a.Accounts[account]; ok { this.Primary = instance - a.data.Accounts[account] = this + a.Accounts[account] = this } else { return fmt.Errorf("no account found for id: %s", account) } diff --git a/pkg/accounts/accounts_test.go b/pkg/accounts/accounts_test.go index 9f77f57..0b5da87 100644 --- a/pkg/accounts/accounts_test.go +++ b/pkg/accounts/accounts_test.go @@ -53,7 +53,7 @@ func TestAccountant_RegisterAccount(t *testing.T) { func TestAccountant_LoadSave(t *testing.T) { accountant := NewAccountant(os.TempDir()) - if len(accountant.data.Accounts) != 0 { + if len(accountant.Accounts) != 0 { t.Error("New accountant created with non-zero account number") } @@ -64,9 +64,9 @@ func TestAccountant_LoadSave(t *testing.T) { t.Error(err) } - if len(accountant.data.Accounts) != 1 { + if len(accountant.Accounts) != 1 { t.Error("No new account made") - } else if accountant.data.Accounts[a.Id].Name != name { + } else if accountant.Accounts[a.Id].Name != name { t.Error("New account created with wrong name") } @@ -77,7 +77,7 @@ func TestAccountant_LoadSave(t *testing.T) { // Re-create the accountant accountant = NewAccountant(os.TempDir()) - if len(accountant.data.Accounts) != 0 { + if len(accountant.Accounts) != 0 { t.Error("New accountant created with non-zero account number") } @@ -87,16 +87,16 @@ func TestAccountant_LoadSave(t *testing.T) { } // Verify we have the same account again - if len(accountant.data.Accounts) != 1 { + if len(accountant.Accounts) != 1 { t.Error("No account after load") - } else if accountant.data.Accounts[a.Id].Name != name { + } else if accountant.Accounts[a.Id].Name != name { t.Error("New account created with wrong name") } } func TestAccountant_AssignPrimary(t *testing.T) { accountant := NewAccountant(os.TempDir()) - if len(accountant.data.Accounts) != 0 { + if len(accountant.Accounts) != 0 { t.Error("New accountant created with non-zero account number") } @@ -112,7 +112,7 @@ func TestAccountant_AssignPrimary(t *testing.T) { err = accountant.AssignPrimary(a.Id, inst) if err != nil { t.Error("Failed to set primary for created account") - } else if accountant.data.Accounts[a.Id].Primary != inst { + } else if accountant.Accounts[a.Id].Primary != inst { t.Error("Primary for assigned account is incorrect") } } diff --git a/pkg/game/world.go b/pkg/game/world.go index 1209e71..3138953 100644 --- a/pkg/game/world.go +++ b/pkg/game/world.go @@ -1,14 +1,21 @@ package game import ( + "encoding/json" "fmt" + "io/ioutil" + "os" + "path" "github.com/google/uuid" ) // World describes a self contained universe and everything in it type World struct { - instances map[uuid.UUID]Instance + Instances map[uuid.UUID]Instance `json:"instances"` + + // dataPath is the location for the data to be stored + dataPath string } // Instance describes a single entity or instance of an entity in the world @@ -20,13 +27,50 @@ type Instance struct { pos Position } +const kWorldFileName = "rove-world.json" + // NewWorld creates a new world object -func NewWorld() *World { +func NewWorld(data string) *World { return &World{ - instances: make(map[uuid.UUID]Instance), + Instances: make(map[uuid.UUID]Instance), + dataPath: data, } } +// path returns the full path to the data file +func (w *World) path() string { + return path.Join(w.dataPath, kWorldFileName) +} + +// Load will load the accountant from data +func (w *World) Load() error { + // Don't load anything if the file doesn't exist + _, err := os.Stat(w.path()) + if os.IsNotExist(err) { + fmt.Printf("File %s didn't exist, loading with fresh world data\n", w.path()) + return nil + } + + if b, err := ioutil.ReadFile(w.path()); err != nil { + return err + } else if err := json.Unmarshal(b, &w); err != nil { + return err + } + return nil +} + +// Save will save the accountant data out +func (w *World) Save() error { + if b, err := json.MarshalIndent(w, "", "\t"); err != nil { + return err + } else { + if err := ioutil.WriteFile(w.path(), b, os.ModePerm); err != nil { + return err + } + } + return nil +} + // Adds an instance to the game func (w *World) CreateInstance() uuid.UUID { id := uuid.New() @@ -37,14 +81,14 @@ func (w *World) CreateInstance() uuid.UUID { } // Append the instance to the list - w.instances[id] = instance + w.Instances[id] = instance return id } // GetPosition returns the position of a given instance func (w World) GetPosition(id uuid.UUID) (Position, error) { - if i, ok := w.instances[id]; ok { + if i, ok := w.Instances[id]; ok { return i.pos, nil } else { return Position{}, fmt.Errorf("no instance matching id") diff --git a/pkg/game/world_test.go b/pkg/game/world_test.go index 6614257..0bfc070 100644 --- a/pkg/game/world_test.go +++ b/pkg/game/world_test.go @@ -1,26 +1,27 @@ package game import ( + "os" "testing" ) func TestNewWorld(t *testing.T) { // Very basic for now, nothing to verify - world := NewWorld() + world := NewWorld(os.TempDir()) if world == nil { t.Error("Failed to create world") } } func TestWorld_CreateInstance(t *testing.T) { - world := NewWorld() + world := NewWorld(os.TempDir()) a := world.CreateInstance() b := world.CreateInstance() // Basic duplicate check if a == b { t.Errorf("Created identical instances") - } else if len(world.instances) != 2 { + } else if len(world.Instances) != 2 { t.Errorf("Incorrect number of instances created") } } diff --git a/pkg/server/server.go b/pkg/server/server.go index 9b274bd..3ffaee4 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -63,7 +63,6 @@ func NewServer(opts ...ServerOption) *Server { // Set up the default server s := &Server{ port: 8080, - world: game.NewWorld(), persistence: EphemeralData, router: router, } @@ -78,21 +77,22 @@ func NewServer(opts ...ServerOption) *Server { // Create the accountant s.accountant = accounts.NewAccountant(s.persistenceLocation) + s.world = game.NewWorld(s.persistenceLocation) return s } // Initialise sets up internal state ready to serve func (s *Server) Initialise() error { - // Set up the world - s.world = game.NewWorld() - fmt.Printf("World created\n\t%+v\n", s.world) // Load the accounts if requested if s.persistence == PersistentData { if err := s.accountant.Load(); err != nil { return err } + if err := s.world.Load(); err != nil { + return err + } } // Create a new router @@ -133,6 +133,9 @@ func (s *Server) Close() error { if err := s.accountant.Save(); err != nil { return err } + if err := s.world.Save(); err != nil { + return err + } } return nil }