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 uuid.UUID `json:"id"`
// Primary represents the primary instance that this account owns
Primary uuid.UUID `json:"primary"`
// Rover represents the rover that this account owns
Rover uuid.UUID `json:"rover"`
}
// Represents the accountant data to store
@ -58,12 +58,12 @@ func (a *Accountant) RegisterAccount(name string) (acc Account, err error) {
return
}
// AssignPrimary assigns primary ownership of an instance to an account
func (a *Accountant) AssignPrimary(account uuid.UUID, instance uuid.UUID) error {
// AssignRover assigns rover ownership of an rover to an account
func (a *Accountant) AssignRover(account uuid.UUID, rover uuid.UUID) error {
// Find the account matching the ID
if this, ok := a.Accounts[account]; ok {
this.Primary = instance
this.Rover = rover
a.Accounts[account] = this
} else {
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
}
// GetPrimary gets the primary instance for the account
func (a *Accountant) GetPrimary(account uuid.UUID) (uuid.UUID, error) {
// GetRover gets the rover rover for the account
func (a *Accountant) GetRover(account uuid.UUID) (uuid.UUID, error) {
// Find the account matching the ID
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)
}

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()
if len(accountant.Accounts) != 0 {
t.Error("New accountant created with non-zero account number")
@ -62,14 +62,14 @@ func TestAccountant_AssignGetPrimary(t *testing.T) {
inst := uuid.New()
err = accountant.AssignPrimary(a.Id, inst)
err = accountant.AssignRover(a.Id, inst)
if err != nil {
t.Error("Failed to set primary for created account")
} else if accountant.Accounts[a.Id].Primary != inst {
t.Error("Primary for assigned account is incorrect")
} else if id, err := accountant.GetPrimary(a.Id); err != nil {
t.Error("Failed to get primary for account")
t.Error("Failed to set rover for created account")
} else if accountant.Accounts[a.Id].Rover != inst {
t.Error("Rover for assigned account is incorrect")
} else if id, err := accountant.GetRover(a.Id); err != nil {
t.Error("Failed to get rover for account")
} 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"
// 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
// 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 {
return func() error {
// 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
func (w *World) CommandSpawn(id uuid.UUID) Command {
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)
assert.NoError(t, world.Execute(spawnCommand), "Failed to execute spawn command")
instance, ok := world.Instances[a]
assert.True(t, ok, "No new instance in world")
assert.Equal(t, a, instance.Id, "New instance has incorrect id")
rover, ok := world.Rovers[a]
assert.True(t, ok, "No new rover in world")
assert.Equal(t, a, rover.Id, "New rover has incorrect id")
}
func TestCommand_Move(t *testing.T) {
world := NewWorld()
a := uuid.New()
assert.NoError(t, world.Spawn(a), "Failed to spawn")
assert.NoError(t, world.SpawnRover(a), "Failed to spawn")
pos := Vector{
X: 1.0,
@ -30,7 +30,7 @@ func TestCommand_Move(t *testing.T) {
}
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
/*
@ -39,8 +39,8 @@ func TestCommand_Move(t *testing.T) {
assert.NoError(t, world.Execute(moveCommand), "Failed to execute move command")
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)
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
type World struct {
// Instances is a map of all the instances in the game
Instances map[uuid.UUID]Instance `json:"instances"`
// Rovers is a id->data map of all the rovers in the game
Rovers map[uuid.UUID]Rover `json:"rovers"`
}
// Instance describes a single entity or instance of an entity in the world
type Instance struct {
// Id is a unique ID for this instance
// Rover describes a single rover in the world
type Rover struct {
// Id is a unique ID for this rover
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"`
// 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"`
// Sight represents the distance the unit can see
@ -30,65 +30,65 @@ type Instance struct {
// NewWorld creates a new world object
func NewWorld() *World {
return &World{
Instances: make(map[uuid.UUID]Instance),
Rovers: make(map[uuid.UUID]Rover),
}
}
// Spawn adds an instance to the game
func (w *World) Spawn(id uuid.UUID) error {
if _, ok := w.Instances[id]; ok {
return fmt.Errorf("instance with id %s already exists in world", id)
// SpawnRover adds an rover to the game
func (w *World) SpawnRover(id uuid.UUID) error {
if _, ok := w.Rovers[id]; ok {
return fmt.Errorf("rover with id %s already exists in world", id)
}
// Initialise the instance
instance := Instance{
// Initialise the rover
rover := Rover{
Id: id,
}
// Append the instance to the list
w.Instances[id] = instance
// Append the rover to the list
w.Rovers[id] = rover
return nil
}
// Removes an instance from the game
func (w *World) DestroyInstance(id uuid.UUID) error {
if _, ok := w.Instances[id]; ok {
delete(w.Instances, id)
// Removes an rover from the game
func (w *World) DestroyRover(id uuid.UUID) error {
if _, ok := w.Rovers[id]; ok {
delete(w.Rovers, id)
} else {
return fmt.Errorf("no instance matching id")
return fmt.Errorf("no rover matching id")
}
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) {
if i, ok := w.Instances[id]; ok {
if i, ok := w.Rovers[id]; ok {
return i.Pos, nil
} 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 {
if i, ok := w.Instances[id]; ok {
if i, ok := w.Rovers[id]; ok {
i.Pos = pos
w.Instances[id] = i
w.Rovers[id] = i
return nil
} 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) {
if i, ok := w.Instances[id]; ok {
if i, ok := w.Rovers[id]; ok {
i.Pos.Add(vec)
w.Instances[id] = i
w.Rovers[id] = i
return i.Pos, nil
} 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()
a := uuid.New()
b := uuid.New()
assert.NoError(t, world.Spawn(a), "Failed to spawn")
assert.NoError(t, world.Spawn(b), "Failed to spawn")
assert.NoError(t, world.SpawnRover(a), "Failed to spawn")
assert.NoError(t, world.SpawnRover(b), "Failed to spawn")
// Basic duplicate check
if a == b {
t.Errorf("Created identical instances")
} else if len(world.Instances) != 2 {
t.Errorf("Incorrect number of instances created")
t.Errorf("Created identical rovers")
} else if len(world.Rovers) != 2 {
t.Errorf("Incorrect number of rovers created")
}
}
func TestWorld_DestroyInstance(t *testing.T) {
func TestWorld_DestroyRover(t *testing.T) {
world := NewWorld()
a := uuid.New()
b := uuid.New()
assert.NoError(t, world.Spawn(a), "Failed to spawn")
assert.NoError(t, world.Spawn(b), "Failed to spawn")
assert.NoError(t, world.SpawnRover(a), "Failed to spawn")
assert.NoError(t, world.SpawnRover(b), "Failed to spawn")
err := world.DestroyInstance(a)
assert.NoError(t, err, "Error returned from instance destroy")
err := world.DestroyRover(a)
assert.NoError(t, err, "Error returned from rover destroy")
// Basic duplicate check
if len(world.Instances) != 1 {
t.Error("Too many instances left in world")
} else if _, ok := world.Instances[b]; !ok {
t.Error("Remaining instance is incorrect")
if len(world.Rovers) != 1 {
t.Error("Too many rovers left in world")
} else if _, ok := world.Rovers[b]; !ok {
t.Error("Remaining rover is incorrect")
}
}
func TestWorld_GetSetMovePosition(t *testing.T) {
world := NewWorld()
a := uuid.New()
assert.NoError(t, world.Spawn(a), "Failed to spawn")
assert.NoError(t, world.SpawnRover(a), "Failed to spawn")
pos := Vector{
X: 1.0,
@ -59,14 +59,14 @@ func TestWorld_GetSetMovePosition(t *testing.T) {
}
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)
assert.NoError(t, err, "Failed to set position for instance")
assert.Equal(t, pos, newpos, "Failed to correctly 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 rover")
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)
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
// Spawns the primary entity for an account
// Responds with the position of said entity
// Spawns the rover for an account
// Responds with the position of said rover
// SpawnData is the data to be sent for the spawn command
type SpawnData struct {

View file

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

View file

@ -77,8 +77,8 @@ func TestHandleCommands(t *testing.T) {
a, err := s.accountant.RegisterAccount("test")
assert.NoError(t, err, "Error registering account")
// Spawn the primary instance for the account
_, inst, err := s.SpawnPrimaryForAccount(a.Id)
// Spawn the rover rover for the account
_, inst, err := s.SpawnRoverForAccount(a.Id)
data := CommandsData{
Id: a.Id.String(),
@ -107,7 +107,7 @@ func TestHandleCommands(t *testing.T) {
}
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

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
func (s *Server) SpawnPrimaryForAccount(accountid uuid.UUID) (game.Vector, uuid.UUID, error) {
// SpawnRoverForAccount spawns the rover rover for an account
func (s *Server) SpawnRoverForAccount(accountid uuid.UUID) (game.Vector, uuid.UUID, error) {
inst := uuid.New()
s.world.Spawn(inst)
s.world.SpawnRover(inst)
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 {
if err := s.accountant.AssignPrimary(accountid, inst); err != nil {
// Try and clear up the instance
if err := s.world.DestroyInstance(inst); err != nil {
fmt.Printf("Failed to destroy instance after failed primary assign: %s", err)
if err := s.accountant.AssignRover(accountid, inst); err != nil {
// Try and clear up the rover
if err := s.world.DestroyRover(inst); err != nil {
fmt.Printf("Failed to destroy rover after failed rover assign: %s", err)
}
return game.Vector{}, uuid.UUID{}, err