Add the /commands path to handle a set of commands
Entirely synchronous now but allows for the "move" command
This commit is contained in:
parent
e5d5d123a6
commit
e2857d7506
5 changed files with 169 additions and 19 deletions
|
@ -71,3 +71,12 @@ 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) {
|
||||
// Find the account matching the ID
|
||||
if this, ok := a.Accounts[account]; ok {
|
||||
return this.Primary, nil
|
||||
}
|
||||
return uuid.UUID{}, fmt.Errorf("no account found for id: %s", account)
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ func TestAccountant_RegisterAccount(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAccountant_AssignPrimary(t *testing.T) {
|
||||
func TestAccountant_AssignGetPrimary(t *testing.T) {
|
||||
accountant := NewAccountant()
|
||||
if len(accountant.Accounts) != 0 {
|
||||
t.Error("New accountant created with non-zero account number")
|
||||
|
@ -67,5 +67,9 @@ func TestAccountant_AssignPrimary(t *testing.T) {
|
|||
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")
|
||||
} else if id != inst {
|
||||
t.Error("Fetched primary is incorrect for account")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@ func (s *Server) SetUpRouter() {
|
|||
path: "/spawn",
|
||||
handler: s.HandleSpawn,
|
||||
},
|
||||
{
|
||||
path: "/commands",
|
||||
handler: s.HandleCommands,
|
||||
},
|
||||
}
|
||||
|
||||
// Set up the handlers
|
||||
|
@ -192,27 +196,95 @@ func (s *Server) HandleSpawn(w http.ResponseWriter, r *http.Request) {
|
|||
fmt.Printf("\tspawn data: %v\n", data)
|
||||
|
||||
// Create a new instance
|
||||
inst := uuid.New()
|
||||
s.world.Spawn(inst)
|
||||
if pos, err := s.world.GetPosition(inst); err != nil {
|
||||
response.Error = fmt.Sprint("No position found for created instance")
|
||||
|
||||
} else {
|
||||
if err := s.accountant.AssignPrimary(id, inst); err != nil {
|
||||
if pos, _, err := s.SpawnPrimary(id); err != nil {
|
||||
response.Error = err.Error()
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
} else {
|
||||
// Reply with valid data
|
||||
response.Success = true
|
||||
response.Position = pos
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Be a good citizen and set the header for the return
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
// Log the response
|
||||
fmt.Printf("\tresponse: %+v\n", response)
|
||||
|
||||
// Reply with the current status
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
const (
|
||||
// CommandMove describes a single move command
|
||||
CommandMove = "move"
|
||||
)
|
||||
|
||||
// Command describes a single command to execute
|
||||
// it contains the type, and then any members used for each command type
|
||||
type Command struct {
|
||||
// Command is the main command string
|
||||
Command string `json:"command"`
|
||||
|
||||
// Used for CommandMove
|
||||
Vector game.Vector `json:"vector"`
|
||||
}
|
||||
|
||||
// CommandsData is a set of commands to execute in order
|
||||
type CommandsData struct {
|
||||
BasicAccountData
|
||||
Commands []Command `json:"commands"`
|
||||
}
|
||||
|
||||
// HandleSpawn will spawn the player entity for the associated account
|
||||
func (s *Server) HandleCommands(w http.ResponseWriter, r *http.Request) {
|
||||
// Verify we're hit with a get request
|
||||
if r.Method != http.MethodPost {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%s\t%s\n", r.Method, r.RequestURI)
|
||||
|
||||
// Set up the response
|
||||
var response = BasicResponse{
|
||||
Success: false,
|
||||
}
|
||||
|
||||
// Pull out the incoming info
|
||||
var data CommandsData
|
||||
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||
fmt.Printf("Failed to decode json: %s\n", err)
|
||||
response.Error = err.Error()
|
||||
|
||||
} else if len(data.Id) == 0 {
|
||||
response.Error = "No account ID provided"
|
||||
|
||||
} 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 {
|
||||
// log the data sent
|
||||
fmt.Printf("\tcommands data: %v\n", data)
|
||||
|
||||
// Iterate through the commands to generate all game commands
|
||||
var cmds []game.Command
|
||||
for _, c := range data.Commands {
|
||||
switch c.Command {
|
||||
case CommandMove:
|
||||
cmds = append(cmds, s.world.CommandMove(inst, c.Vector))
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the commands
|
||||
if err := s.world.Execute(cmds...); err != nil {
|
||||
response.Error = fmt.Sprintf("Failed to execute commands: %s", err)
|
||||
} else {
|
||||
response.Success = true
|
||||
}
|
||||
}
|
||||
|
||||
// Be a good citizen and set the header for the return
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/mdiluz/rove/pkg/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -71,3 +72,45 @@ func TestHandleSpawn(t *testing.T) {
|
|||
t.Errorf("got false for /spawn")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleCommands(t *testing.T) {
|
||||
s := NewServer()
|
||||
a, err := s.accountant.RegisterAccount("test")
|
||||
assert.NoError(t, err, "Error registering account")
|
||||
|
||||
// Spawn the primary instance for the account
|
||||
_, inst, err := s.SpawnPrimary(a.Id)
|
||||
|
||||
move := game.Vector{X: 1, Y: 2, Z: 3}
|
||||
|
||||
data := CommandsData{
|
||||
BasicAccountData: BasicAccountData{Id: a.Id.String()},
|
||||
Commands: []Command{
|
||||
{
|
||||
Command: CommandMove,
|
||||
Vector: move,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
b, err := json.Marshal(data)
|
||||
assert.NoError(t, err, "Error marshalling data")
|
||||
|
||||
request, _ := http.NewRequest(http.MethodPost, "/commands", bytes.NewReader(b))
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
s.HandleCommands(response, request)
|
||||
|
||||
var status BasicResponse
|
||||
json.NewDecoder(response.Body).Decode(&status)
|
||||
|
||||
if status.Success != true {
|
||||
t.Errorf("got false for /commands")
|
||||
}
|
||||
|
||||
if pos, err := s.world.GetPosition(inst); err != nil {
|
||||
t.Error("Couldn't get position for the primary instance")
|
||||
} else if pos != move {
|
||||
t.Error("Mismatched position after commands")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mdiluz/rove/pkg/accounts"
|
||||
"github.com/mdiluz/rove/pkg/game"
|
||||
|
@ -133,3 +134,24 @@ func (s *Server) Close() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SpawnPrimary spawns the primary instance for an account
|
||||
func (s *Server) SpawnPrimary(accountid uuid.UUID) (game.Vector, uuid.UUID, error) {
|
||||
inst := uuid.New()
|
||||
s.world.Spawn(inst)
|
||||
if pos, err := s.world.GetPosition(inst); err != nil {
|
||||
return game.Vector{}, uuid.UUID{}, fmt.Errorf("No position found for created instance")
|
||||
|
||||
} 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)
|
||||
}
|
||||
|
||||
return game.Vector{}, uuid.UUID{}, err
|
||||
} else {
|
||||
return pos, inst, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue