Huge Instance -> Rover refactor, for clarification

This commit is contained in:
Marc Di Luzio 2020-06-04 21:17:43 +01:00
parent 33f25a7414
commit 0fbad15c01
10 changed files with 96 additions and 96 deletions

View file

@ -16,8 +16,8 @@ type Account struct {
// Id represents a unique ID per account and is set one registered // Id represents a unique ID per account and is set one registered
Id uuid.UUID `json:"id"` Id uuid.UUID `json:"id"`
// Primary represents the primary instance that this account owns // Rover represents the rover that this account owns
Primary uuid.UUID `json:"primary"` Rover uuid.UUID `json:"rover"`
} }
// Represents the accountant data to store // Represents the accountant data to store
@ -58,12 +58,12 @@ func (a *Accountant) RegisterAccount(name string) (acc Account, err error) {
return return
} }
// AssignPrimary assigns primary ownership of an instance to an account // AssignRover assigns rover ownership of an rover to an account
func (a *Accountant) AssignPrimary(account uuid.UUID, instance uuid.UUID) error { func (a *Accountant) AssignRover(account uuid.UUID, rover uuid.UUID) error {
// Find the account matching the ID // Find the account matching the ID
if this, ok := a.Accounts[account]; ok { if this, ok := a.Accounts[account]; ok {
this.Primary = instance this.Rover = rover
a.Accounts[account] = this a.Accounts[account] = this
} else { } else {
return fmt.Errorf("no account found for id: %s", account) return fmt.Errorf("no account found for id: %s", account)
@ -72,11 +72,11 @@ func (a *Accountant) AssignPrimary(account uuid.UUID, instance uuid.UUID) error
return nil return nil
} }
// GetPrimary gets the primary instance for the account // GetRover gets the rover rover for the account
func (a *Accountant) GetPrimary(account uuid.UUID) (uuid.UUID, error) { func (a *Accountant) GetRover(account uuid.UUID) (uuid.UUID, error) {
// Find the account matching the ID // Find the account matching the ID
if this, ok := a.Accounts[account]; ok { if this, ok := a.Accounts[account]; ok {
return this.Primary, nil return this.Rover, nil
} }
return uuid.UUID{}, fmt.Errorf("no account found for id: %s", account) return uuid.UUID{}, fmt.Errorf("no account found for id: %s", account)
} }

View file

@ -48,7 +48,7 @@ func TestAccountant_RegisterAccount(t *testing.T) {
} }
} }
func TestAccountant_AssignGetPrimary(t *testing.T) { func TestAccountant_AssignGetRover(t *testing.T) {
accountant := NewAccountant() accountant := NewAccountant()
if len(accountant.Accounts) != 0 { if len(accountant.Accounts) != 0 {
t.Error("New accountant created with non-zero account number") t.Error("New accountant created with non-zero account number")
@ -62,14 +62,14 @@ func TestAccountant_AssignGetPrimary(t *testing.T) {
inst := uuid.New() inst := uuid.New()
err = accountant.AssignPrimary(a.Id, inst) err = accountant.AssignRover(a.Id, inst)
if err != nil { if err != nil {
t.Error("Failed to set primary for created account") t.Error("Failed to set rover for created account")
} else if accountant.Accounts[a.Id].Primary != inst { } else if accountant.Accounts[a.Id].Rover != inst {
t.Error("Primary for assigned account is incorrect") t.Error("Rover for assigned account is incorrect")
} else if id, err := accountant.GetPrimary(a.Id); err != nil { } else if id, err := accountant.GetRover(a.Id); err != nil {
t.Error("Failed to get primary for account") t.Error("Failed to get rover for account")
} else if id != inst { } else if id != inst {
t.Error("Fetched primary is incorrect for account") t.Error("Fetched rover is incorrect for account")
} }
} }

View file

@ -2,10 +2,10 @@ package game
import "github.com/google/uuid" import "github.com/google/uuid"
// A command is simply a function that acts on the a given instance in the world // A command is simply a function that acts on the a given rover in the world
type Command func() error type Command func() error
// CommandMove will move the instance in question // CommandMove will move the rover in question
func (w *World) CommandMove(id uuid.UUID, bearing float64, duration int64) Command { func (w *World) CommandMove(id uuid.UUID, bearing float64, duration int64) Command {
return func() error { return func() error {
// TODO: Calculate the move itself // TODO: Calculate the move itself
@ -19,6 +19,6 @@ func (w *World) CommandMove(id uuid.UUID, bearing float64, duration int64) Comma
// TODO: Two spawn commands with the same id could trigger a fail later on, we should prevent that somehow // TODO: Two spawn commands with the same id could trigger a fail later on, we should prevent that somehow
func (w *World) CommandSpawn(id uuid.UUID) Command { func (w *World) CommandSpawn(id uuid.UUID) Command {
return func() error { return func() error {
return w.Spawn(id) return w.SpawnRover(id)
} }
} }

View file

@ -14,15 +14,15 @@ func TestCommand_Spawn(t *testing.T) {
spawnCommand := world.CommandSpawn(a) spawnCommand := world.CommandSpawn(a)
assert.NoError(t, world.Execute(spawnCommand), "Failed to execute spawn command") assert.NoError(t, world.Execute(spawnCommand), "Failed to execute spawn command")
instance, ok := world.Instances[a] rover, ok := world.Rovers[a]
assert.True(t, ok, "No new instance in world") assert.True(t, ok, "No new rover in world")
assert.Equal(t, a, instance.Id, "New instance has incorrect id") assert.Equal(t, a, rover.Id, "New rover has incorrect id")
} }
func TestCommand_Move(t *testing.T) { func TestCommand_Move(t *testing.T) {
world := NewWorld() world := NewWorld()
a := uuid.New() a := uuid.New()
assert.NoError(t, world.Spawn(a), "Failed to spawn") assert.NoError(t, world.SpawnRover(a), "Failed to spawn")
pos := Vector{ pos := Vector{
X: 1.0, X: 1.0,
@ -30,7 +30,7 @@ func TestCommand_Move(t *testing.T) {
} }
err := world.SetPosition(a, pos) err := world.SetPosition(a, pos)
assert.NoError(t, err, "Failed to set position for instance") assert.NoError(t, err, "Failed to set position for rover")
// TODO: Test the bearing/duration movement // TODO: Test the bearing/duration movement
/* /*
@ -39,8 +39,8 @@ func TestCommand_Move(t *testing.T) {
assert.NoError(t, world.Execute(moveCommand), "Failed to execute move command") assert.NoError(t, world.Execute(moveCommand), "Failed to execute move command")
newpos, err := world.GetPosition(a) newpos, err := world.GetPosition(a)
assert.NoError(t, err, "Failed to set position for instance") assert.NoError(t, err, "Failed to set position for rover")
pos.Add(move) pos.Add(move)
assert.Equal(t, pos, newpos, "Failed to correctly set position for instance") assert.Equal(t, pos, newpos, "Failed to correctly set position for rover")
*/ */
} }

View file

@ -8,19 +8,19 @@ import (
// World describes a self contained universe and everything in it // World describes a self contained universe and everything in it
type World struct { type World struct {
// Instances is a map of all the instances in the game // Rovers is a id->data map of all the rovers in the game
Instances map[uuid.UUID]Instance `json:"instances"` Rovers map[uuid.UUID]Rover `json:"rovers"`
} }
// Instance describes a single entity or instance of an entity in the world // Rover describes a single rover in the world
type Instance struct { type Rover struct {
// Id is a unique ID for this instance // Id is a unique ID for this rover
Id uuid.UUID `json:"id"` Id uuid.UUID `json:"id"`
// Pos represents where this instance is in the world // Pos represents where this rover is in the world
Pos Vector `json:"pos"` Pos Vector `json:"pos"`
// Speed represents the Speed that the instance will move per second // Speed represents the Speed that the rover will move per second
Speed float64 `json:"speed"` Speed float64 `json:"speed"`
// Sight represents the distance the unit can see // Sight represents the distance the unit can see
@ -30,65 +30,65 @@ type Instance struct {
// NewWorld creates a new world object // NewWorld creates a new world object
func NewWorld() *World { func NewWorld() *World {
return &World{ return &World{
Instances: make(map[uuid.UUID]Instance), Rovers: make(map[uuid.UUID]Rover),
} }
} }
// Spawn adds an instance to the game // SpawnRover adds an rover to the game
func (w *World) Spawn(id uuid.UUID) error { func (w *World) SpawnRover(id uuid.UUID) error {
if _, ok := w.Instances[id]; ok { if _, ok := w.Rovers[id]; ok {
return fmt.Errorf("instance with id %s already exists in world", id) return fmt.Errorf("rover with id %s already exists in world", id)
} }
// Initialise the instance // Initialise the rover
instance := Instance{ rover := Rover{
Id: id, Id: id,
} }
// Append the instance to the list // Append the rover to the list
w.Instances[id] = instance w.Rovers[id] = rover
return nil return nil
} }
// Removes an instance from the game // Removes an rover from the game
func (w *World) DestroyInstance(id uuid.UUID) error { func (w *World) DestroyRover(id uuid.UUID) error {
if _, ok := w.Instances[id]; ok { if _, ok := w.Rovers[id]; ok {
delete(w.Instances, id) delete(w.Rovers, id)
} else { } else {
return fmt.Errorf("no instance matching id") return fmt.Errorf("no rover matching id")
} }
return nil return nil
} }
// GetPosition returns the position of a given instance // GetPosition returns the position of a given rover
func (w World) GetPosition(id uuid.UUID) (Vector, error) { func (w World) GetPosition(id uuid.UUID) (Vector, error) {
if i, ok := w.Instances[id]; ok { if i, ok := w.Rovers[id]; ok {
return i.Pos, nil return i.Pos, nil
} else { } else {
return Vector{}, fmt.Errorf("no instance matching id") return Vector{}, fmt.Errorf("no rover matching id")
} }
} }
// SetPosition sets an instances position // SetPosition sets an rovers position
func (w *World) SetPosition(id uuid.UUID, pos Vector) error { func (w *World) SetPosition(id uuid.UUID, pos Vector) error {
if i, ok := w.Instances[id]; ok { if i, ok := w.Rovers[id]; ok {
i.Pos = pos i.Pos = pos
w.Instances[id] = i w.Rovers[id] = i
return nil return nil
} else { } else {
return fmt.Errorf("no instance matching id") return fmt.Errorf("no rover matching id")
} }
} }
// SetPosition sets an instances position // SetPosition sets an rovers position
func (w *World) MovePosition(id uuid.UUID, vec Vector) (Vector, error) { func (w *World) MovePosition(id uuid.UUID, vec Vector) (Vector, error) {
if i, ok := w.Instances[id]; ok { if i, ok := w.Rovers[id]; ok {
i.Pos.Add(vec) i.Pos.Add(vec)
w.Instances[id] = i w.Rovers[id] = i
return i.Pos, nil return i.Pos, nil
} else { } else {
return Vector{}, fmt.Errorf("no instance matching id") return Vector{}, fmt.Errorf("no rover matching id")
} }
} }

View file

@ -15,43 +15,43 @@ func TestNewWorld(t *testing.T) {
} }
} }
func TestWorld_CreateInstance(t *testing.T) { func TestWorld_CreateRover(t *testing.T) {
world := NewWorld() world := NewWorld()
a := uuid.New() a := uuid.New()
b := uuid.New() b := uuid.New()
assert.NoError(t, world.Spawn(a), "Failed to spawn") assert.NoError(t, world.SpawnRover(a), "Failed to spawn")
assert.NoError(t, world.Spawn(b), "Failed to spawn") assert.NoError(t, world.SpawnRover(b), "Failed to spawn")
// Basic duplicate check // Basic duplicate check
if a == b { if a == b {
t.Errorf("Created identical instances") t.Errorf("Created identical rovers")
} else if len(world.Instances) != 2 { } else if len(world.Rovers) != 2 {
t.Errorf("Incorrect number of instances created") t.Errorf("Incorrect number of rovers created")
} }
} }
func TestWorld_DestroyInstance(t *testing.T) { func TestWorld_DestroyRover(t *testing.T) {
world := NewWorld() world := NewWorld()
a := uuid.New() a := uuid.New()
b := uuid.New() b := uuid.New()
assert.NoError(t, world.Spawn(a), "Failed to spawn") assert.NoError(t, world.SpawnRover(a), "Failed to spawn")
assert.NoError(t, world.Spawn(b), "Failed to spawn") assert.NoError(t, world.SpawnRover(b), "Failed to spawn")
err := world.DestroyInstance(a) err := world.DestroyRover(a)
assert.NoError(t, err, "Error returned from instance destroy") assert.NoError(t, err, "Error returned from rover destroy")
// Basic duplicate check // Basic duplicate check
if len(world.Instances) != 1 { if len(world.Rovers) != 1 {
t.Error("Too many instances left in world") t.Error("Too many rovers left in world")
} else if _, ok := world.Instances[b]; !ok { } else if _, ok := world.Rovers[b]; !ok {
t.Error("Remaining instance is incorrect") t.Error("Remaining rover is incorrect")
} }
} }
func TestWorld_GetSetMovePosition(t *testing.T) { func TestWorld_GetSetMovePosition(t *testing.T) {
world := NewWorld() world := NewWorld()
a := uuid.New() a := uuid.New()
assert.NoError(t, world.Spawn(a), "Failed to spawn") assert.NoError(t, world.SpawnRover(a), "Failed to spawn")
pos := Vector{ pos := Vector{
X: 1.0, X: 1.0,
@ -59,14 +59,14 @@ func TestWorld_GetSetMovePosition(t *testing.T) {
} }
err := world.SetPosition(a, pos) err := world.SetPosition(a, pos)
assert.NoError(t, err, "Failed to set position for instance") assert.NoError(t, err, "Failed to set position for rover")
newpos, err := world.GetPosition(a) newpos, err := world.GetPosition(a)
assert.NoError(t, err, "Failed to set position for instance") assert.NoError(t, err, "Failed to set position for rover")
assert.Equal(t, pos, newpos, "Failed to correctly set position for instance") assert.Equal(t, pos, newpos, "Failed to correctly set position for rover")
newpos, err = world.MovePosition(a, pos) newpos, err = world.MovePosition(a, pos)
assert.NoError(t, err, "Failed to set position for instance") assert.NoError(t, err, "Failed to set position for rover")
pos.Add(pos) pos.Add(pos)
assert.Equal(t, pos, newpos, "Failed to correctly move position for instance") assert.Equal(t, pos, newpos, "Failed to correctly move position for rover")
} }

View file

@ -30,8 +30,8 @@ type RegisterResponse struct {
// ============================== // ==============================
// API: /spawn method: POST // API: /spawn method: POST
// Spawns the primary entity for an account // Spawns the rover for an account
// Responds with the position of said entity // Responds with the position of said rover
// SpawnData is the data to be sent for the spawn command // SpawnData is the data to be sent for the spawn command
type SpawnData struct { type SpawnData struct {

View file

@ -130,8 +130,8 @@ func HandleSpawn(s *Server, b io.ReadCloser, w io.Writer) error {
// log the data sent // log the data sent
fmt.Printf("\tspawn data: %v\n", data) fmt.Printf("\tspawn data: %v\n", data)
// Create a new instance // Create a new rover
if pos, _, err := s.SpawnPrimaryForAccount(id); err != nil { if pos, _, err := s.SpawnRoverForAccount(id); err != nil {
response.Error = err.Error() response.Error = err.Error()
} else { } else {
response.Success = true response.Success = true
@ -168,8 +168,8 @@ func HandleCommands(s *Server, b io.ReadCloser, w io.Writer) error {
} else if id, err := uuid.Parse(data.Id); err != nil { } else if id, err := uuid.Parse(data.Id); err != nil {
response.Error = fmt.Sprintf("Provided account ID was invalid: %s", err) response.Error = fmt.Sprintf("Provided account ID was invalid: %s", err)
} else if inst, err := s.accountant.GetPrimary(id); err != nil { } else if inst, err := s.accountant.GetRover(id); err != nil {
response.Error = fmt.Sprintf("Provided account has no primary: %s", err) response.Error = fmt.Sprintf("Provided account has no rover: %s", err)
} else { } else {
// log the data sent // log the data sent

View file

@ -77,8 +77,8 @@ func TestHandleCommands(t *testing.T) {
a, err := s.accountant.RegisterAccount("test") a, err := s.accountant.RegisterAccount("test")
assert.NoError(t, err, "Error registering account") assert.NoError(t, err, "Error registering account")
// Spawn the primary instance for the account // Spawn the rover rover for the account
_, inst, err := s.SpawnPrimaryForAccount(a.Id) _, inst, err := s.SpawnRoverForAccount(a.Id)
data := CommandsData{ data := CommandsData{
Id: a.Id.String(), Id: a.Id.String(),
@ -107,7 +107,7 @@ func TestHandleCommands(t *testing.T) {
} }
if _, err := s.world.GetPosition(inst); err != nil { if _, err := s.world.GetPosition(inst); err != nil {
t.Error("Couldn't get position for the primary instance") t.Error("Couldn't get position for the rover rover")
} }
// TODO: Check position is correct // TODO: Check position is correct

View file

@ -161,18 +161,18 @@ func (s *Server) wrapHandler(method string, handler Handler) func(w http.Respons
} }
} }
// SpawnPrimaryForAccount spawns the primary instance for an account // SpawnRoverForAccount spawns the rover rover for an account
func (s *Server) SpawnPrimaryForAccount(accountid uuid.UUID) (game.Vector, uuid.UUID, error) { func (s *Server) SpawnRoverForAccount(accountid uuid.UUID) (game.Vector, uuid.UUID, error) {
inst := uuid.New() inst := uuid.New()
s.world.Spawn(inst) s.world.SpawnRover(inst)
if pos, err := s.world.GetPosition(inst); err != nil { if pos, err := s.world.GetPosition(inst); err != nil {
return game.Vector{}, uuid.UUID{}, fmt.Errorf("No position found for created instance") return game.Vector{}, uuid.UUID{}, fmt.Errorf("No position found for created rover")
} else { } else {
if err := s.accountant.AssignPrimary(accountid, inst); err != nil { if err := s.accountant.AssignRover(accountid, inst); err != nil {
// Try and clear up the instance // Try and clear up the rover
if err := s.world.DestroyInstance(inst); err != nil { if err := s.world.DestroyRover(inst); err != nil {
fmt.Printf("Failed to destroy instance after failed primary assign: %s", err) fmt.Printf("Failed to destroy rover after failed rover assign: %s", err)
} }
return game.Vector{}, uuid.UUID{}, err return game.Vector{}, uuid.UUID{}, err