Split Atlas chunks into tiles and objects

This commit is contained in:
Marc Di Luzio 2020-07-03 17:00:04 +01:00
parent 74dcae6542
commit 062f9cfec8
11 changed files with 284 additions and 169 deletions

View file

@ -108,6 +108,7 @@ func TestServer_Radar(t *testing.T) {
assert.NotZero(t, resp.Range, "Radar should return valid range")
w := int(resp.Range*2 + 1)
assert.Equal(t, w*w, len(resp.Tiles), "radar should return correct number of tiles")
assert.Equal(t, w*w, len(resp.Objects), "radar should return correct number of objects")
}
func TestServer_Rover(t *testing.T) {

View file

@ -59,6 +59,11 @@ func (s *Server) Rover(ctx context.Context, req *rove.RoverRequest) (*rove.Rover
return nil, fmt.Errorf("error getting rover: %s", err)
} else {
var inv []byte
for _, i := range rover.Inventory {
inv = append(inv, byte(i.Type))
}
response = &rove.RoverResponse{
Name: rover.Name,
Position: &rove.Vector{
@ -66,7 +71,7 @@ func (s *Server) Rover(ctx context.Context, req *rove.RoverRequest) (*rove.Rover
Y: int32(rover.Pos.Y),
},
Range: int32(rover.Range),
Inventory: rover.Inventory,
Inventory: inv,
Integrity: int32(rover.Integrity),
}
}
@ -88,10 +93,11 @@ func (s *Server) Radar(ctx context.Context, req *rove.RadarRequest) (*rove.Radar
} else if rover, err := s.world.GetRover(resp); err != nil {
return nil, fmt.Errorf("error getting rover attributes: %s", err)
} else if radar, err := s.world.RadarFromRover(resp); err != nil {
} else if radar, objs, err := s.world.RadarFromRover(resp); err != nil {
return nil, fmt.Errorf("error getting radar from rover: %s", err)
} else {
response.Objects = objs
response.Tiles = radar
response.Range = int32(rover.Range)
}

View file

@ -1,7 +1,6 @@
package atlas
import (
"log"
"math/rand"
"github.com/mdiluz/rove/pkg/maths"
@ -9,27 +8,28 @@ import (
"github.com/mdiluz/rove/pkg/vector"
)
// Tile describes the type of terrain
type Tile byte
const (
// TileNone is a keyword for nothing
TileNone = Tile(0)
// TileRock is solid rock ground
TileRock = Tile('.')
// TileSand is sand
TileSand = Tile(',')
)
// Chunk represents a fixed square grid of tiles
type Chunk struct {
// Tiles represents the tiles within the chunk
Tiles []byte `json:"tiles"`
}
// SpawnContent will create a chunk and fill it with spawned tiles
func (c *Chunk) SpawnContent(size int) {
c.Tiles = make([]byte, size*size)
for i := 0; i < len(c.Tiles); i++ {
c.Tiles[i] = objects.Empty
}
// For now, fill it randomly with objects
for i := range c.Tiles {
if rand.Intn(16) == 0 {
c.Tiles[i] = objects.LargeRock
} else if rand.Intn(32) == 0 {
c.Tiles[i] = objects.SmallRock
}
}
// Objects represents the objects within the chunk
// only one possible object per tile for now
Objects map[int]objects.Object `json:"objects"`
}
// Atlas represents a grid of Chunks
@ -58,50 +58,101 @@ func NewAtlas(chunkSize int) Atlas {
WorldOrigin: vector.Vector{X: 0, Y: 0},
}
// Initialise the first chunk
a.Chunks[0].SpawnContent(chunkSize)
a.Chunks[0].populate(chunkSize)
return a
}
// SetTile sets an individual tile's kind
func (a *Atlas) SetTile(v vector.Vector, tile byte) {
// Get the chunk
func (a *Atlas) SetTile(v vector.Vector, tile Tile) {
c := a.worldSpaceToChunkWithGrow(v)
chunk := a.Chunks[c]
if chunk.Tiles == nil {
chunk.SpawnContent(a.ChunkSize)
}
local := a.worldSpaceToChunkLocal(v)
tileID := local.X + local.Y*a.ChunkSize
// Sanity check
if tileID >= len(chunk.Tiles) || tileID < 0 {
log.Fatalf("Local tileID is not in valid chunk, somehow, this means something is very wrong")
}
// Set the chunk back
chunk.Tiles[tileID] = tile
a.Chunks[c] = chunk
a.setTile(c, local, byte(tile))
}
// GetTile will return an individual tile
func (a *Atlas) GetTile(v vector.Vector) byte {
// Get the chunk
// SetObject sets the object on a tile
func (a *Atlas) SetObject(v vector.Vector, obj objects.Object) {
c := a.worldSpaceToChunkWithGrow(v)
local := a.worldSpaceToChunkLocal(v)
a.setObject(c, local, obj)
}
// QueryPosition will return information for a specific position
func (a *Atlas) QueryPosition(v vector.Vector) (byte, objects.Object) {
c := a.worldSpaceToChunkWithGrow(v)
local := a.worldSpaceToChunkLocal(v)
chunk := a.Chunks[c]
if chunk.Tiles == nil {
chunk.SpawnContent(a.ChunkSize)
chunk.populate(a.ChunkSize)
}
i := a.chunkTileIndex(local)
return chunk.Tiles[i], chunk.Objects[i]
}
// chunkTileID returns the tile index within a chunk
func (a *Atlas) chunkTileIndex(local vector.Vector) int {
return local.X + local.Y*a.ChunkSize
}
// populate will fill a chunk with data
func (c *Chunk) populate(size int) {
c.Tiles = make([]byte, size*size)
c.Objects = make(map[int]objects.Object)
// Set up the tiles
for i := 0; i < len(c.Tiles); i++ {
if rand.Intn(3) == 0 {
c.Tiles[i] = byte(TileRock)
} else {
c.Tiles[i] = byte(TileSand)
}
}
local := a.worldSpaceToChunkLocal(v)
tileID := local.X + local.Y*a.ChunkSize
// Set up any objects
for i := 0; i < len(c.Tiles); i++ {
if rand.Intn(16) == 0 {
c.Objects[i] = objects.Object{Type: objects.LargeRock}
}
}
}
// Sanity check
if tileID >= len(chunk.Tiles) || tileID < 0 {
log.Fatalf("Local tileID is not in valid chunk, somehow, this means something is very wrong")
// setTile sets a tile in a specific chunk
func (a *Atlas) setTile(chunk int, local vector.Vector, tile byte) {
c := a.Chunks[chunk]
if c.Tiles == nil {
c.populate(a.ChunkSize)
}
return chunk.Tiles[tileID]
c.Tiles[a.chunkTileIndex(local)] = tile
a.Chunks[chunk] = c
}
// setObject sets an object in a specific chunk
func (a *Atlas) setObject(chunk int, local vector.Vector, object objects.Object) {
c := a.Chunks[chunk]
if c.Tiles == nil {
c.populate(a.ChunkSize)
}
i := a.chunkTileIndex(local)
if object.Type != objects.None {
c.Objects[i] = object
} else {
delete(c.Objects, i)
}
a.Chunks[chunk] = c
}
// setTileAndObject sets both tile and object information for location in chunk
func (a *Atlas) setTileAndObject(chunk int, local vector.Vector, tile byte, object objects.Object) {
c := a.Chunks[chunk]
if c.Tiles == nil {
c.populate(a.ChunkSize)
}
i := a.chunkTileIndex(local)
c.Tiles[i] = tile
c.Objects[i] = object
a.Chunks[chunk] = c
}
// worldSpaceToChunkLocal gets a chunk local coordinate for a tile

View file

@ -3,6 +3,7 @@ package atlas
import (
"testing"
"github.com/mdiluz/rove/pkg/objects"
"github.com/mdiluz/rove/pkg/vector"
"github.com/stretchr/testify/assert"
)
@ -19,8 +20,8 @@ func TestAtlas_toChunk(t *testing.T) {
assert.NotNil(t, a)
// Get a tile to spawn the chunks
a.GetTile(vector.Vector{X: -1, Y: -1})
a.GetTile(vector.Vector{X: 0, Y: 0})
a.QueryPosition(vector.Vector{X: -1, Y: -1})
a.QueryPosition(vector.Vector{X: 0, Y: 0})
// Chunks should look like:
// 2 | 3
@ -38,8 +39,8 @@ func TestAtlas_toChunk(t *testing.T) {
a = NewAtlas(2)
assert.NotNil(t, a)
// Get a tile to spawn the chunks
a.GetTile(vector.Vector{X: -2, Y: -2})
a.GetTile(vector.Vector{X: 1, Y: 1})
a.QueryPosition(vector.Vector{X: -2, Y: -2})
a.QueryPosition(vector.Vector{X: 1, Y: 1})
// Chunks should look like:
// 2 | 3
// -----
@ -56,8 +57,8 @@ func TestAtlas_toChunk(t *testing.T) {
a = NewAtlas(2)
assert.NotNil(t, a)
// Get a tile to spawn the chunks
a.GetTile(vector.Vector{X: 5, Y: 5})
a.GetTile(vector.Vector{X: -5, Y: -5})
a.QueryPosition(vector.Vector{X: 5, Y: 5})
a.QueryPosition(vector.Vector{X: -5, Y: -5})
// Chunks should look like:
// 12| 13|| 14| 15
// ----------------
@ -82,15 +83,30 @@ func TestAtlas_GetSetTile(t *testing.T) {
// Set the origin tile to 1 and test it
a.SetTile(vector.Vector{X: 0, Y: 0}, 1)
tile := a.GetTile(vector.Vector{X: 0, Y: 0})
tile, _ := a.QueryPosition(vector.Vector{X: 0, Y: 0})
assert.Equal(t, byte(1), tile)
// Set another tile to 1 and test it
a.SetTile(vector.Vector{X: 5, Y: -2}, 2)
tile = a.GetTile(vector.Vector{X: 5, Y: -2})
tile, _ = a.QueryPosition(vector.Vector{X: 5, Y: -2})
assert.Equal(t, byte(2), tile)
}
func TestAtlas_GetSetObject(t *testing.T) {
a := NewAtlas(10)
assert.NotNil(t, a)
// Set the origin tile to 1 and test it
a.SetObject(vector.Vector{X: 0, Y: 0}, objects.Object{Type: objects.LargeRock})
_, obj := a.QueryPosition(vector.Vector{X: 0, Y: 0})
assert.Equal(t, objects.Object{Type: objects.LargeRock}, obj)
// Set another tile to 1 and test it
a.SetObject(vector.Vector{X: 5, Y: -2}, objects.Object{Type: objects.SmallRock})
_, obj = a.QueryPosition(vector.Vector{X: 5, Y: -2})
assert.Equal(t, objects.Object{Type: objects.SmallRock}, obj)
}
func TestAtlas_Grown(t *testing.T) {
// Start with a small example
a := NewAtlas(2)
@ -103,21 +119,21 @@ func TestAtlas_Grown(t *testing.T) {
a.SetTile(vector.Vector{X: 1, Y: -2}, 3)
// Check tile values
tile := a.GetTile(vector.Vector{X: 0, Y: 0})
tile, _ := a.QueryPosition(vector.Vector{X: 0, Y: 0})
assert.Equal(t, byte(1), tile)
tile = a.GetTile(vector.Vector{X: -1, Y: -1})
tile, _ = a.QueryPosition(vector.Vector{X: -1, Y: -1})
assert.Equal(t, byte(2), tile)
tile = a.GetTile(vector.Vector{X: 1, Y: -2})
tile, _ = a.QueryPosition(vector.Vector{X: 1, Y: -2})
assert.Equal(t, byte(3), tile)
tile = a.GetTile(vector.Vector{X: 0, Y: 0})
tile, _ = a.QueryPosition(vector.Vector{X: 0, Y: 0})
assert.Equal(t, byte(1), tile)
tile = a.GetTile(vector.Vector{X: -1, Y: -1})
tile, _ = a.QueryPosition(vector.Vector{X: -1, Y: -1})
assert.Equal(t, byte(2), tile)
tile = a.GetTile(vector.Vector{X: 1, Y: -2})
tile, _ = a.QueryPosition(vector.Vector{X: 1, Y: -2})
assert.Equal(t, byte(3), tile)
}

View file

@ -1,6 +1,7 @@
package game
import (
"github.com/mdiluz/rove/pkg/objects"
"github.com/mdiluz/rove/pkg/vector"
)
@ -16,7 +17,7 @@ type Rover struct {
Range int `json:"range"`
// Inventory represents any items the rover is carrying
Inventory []byte `json:"inventory"`
Inventory []objects.Object `json:"inventory"`
// Integrity represents current rover health
Integrity int `json:"integrity"`

View file

@ -101,8 +101,8 @@ func (w *World) SpawnRover() (string, error) {
// Seach until we error (run out of world)
for {
tile := w.Atlas.GetTile(rover.Pos)
if !objects.IsBlocking(tile) {
_, obj := w.Atlas.QueryPosition(rover.Pos)
if !obj.IsBlocking() {
break
} else {
// Try and spawn to the east of the blockage
@ -136,13 +136,11 @@ func (w *World) DestroyRover(rover string) error {
w.worldMutex.Lock()
defer w.worldMutex.Unlock()
i, ok := w.Rovers[rover]
_, ok := w.Rovers[rover]
if !ok {
return fmt.Errorf("no rover matching id")
}
// Clear the tile
w.Atlas.SetTile(i.Pos, objects.Empty)
delete(w.Rovers, rover)
return nil
}
@ -175,7 +173,7 @@ func (w *World) SetRoverPosition(rover string, pos vector.Vector) error {
}
// RoverInventory returns the inventory of a requested rover
func (w *World) RoverInventory(rover string) ([]byte, error) {
func (w *World) RoverInventory(rover string) ([]objects.Object, error) {
w.worldMutex.RLock()
defer w.worldMutex.RUnlock()
@ -201,8 +199,8 @@ func (w *World) WarpRover(rover string, pos vector.Vector) error {
}
// Check the tile is not blocked
tile := w.Atlas.GetTile(pos)
if objects.IsBlocking(tile) {
_, obj := w.Atlas.QueryPosition(pos)
if obj.IsBlocking() {
return fmt.Errorf("can't warp rover to occupied tile, check before warping")
}
@ -224,8 +222,8 @@ func (w *World) MoveRover(rover string, b bearing.Bearing) (vector.Vector, error
newPos := i.Pos.Added(b.Vector())
// Get the tile and verify it's empty
tile := w.Atlas.GetTile(newPos)
if !objects.IsBlocking(tile) {
_, obj := w.Atlas.QueryPosition(newPos)
if !obj.IsBlocking() {
// Perform the move
i.Pos = newPos
w.Rovers[rover] = i
@ -243,34 +241,35 @@ func (w *World) MoveRover(rover string, b bearing.Bearing) (vector.Vector, error
}
// RoverStash will stash an item at the current rovers position
func (w *World) RoverStash(rover string) (byte, error) {
func (w *World) RoverStash(rover string) (objects.Type, error) {
w.worldMutex.Lock()
defer w.worldMutex.Unlock()
r, ok := w.Rovers[rover]
if !ok {
return objects.Empty, fmt.Errorf("no rover matching id")
return objects.None, fmt.Errorf("no rover matching id")
}
tile := w.Atlas.GetTile(r.Pos)
if !objects.IsStashable(tile) {
return objects.Empty, nil
_, obj := w.Atlas.QueryPosition(r.Pos)
if !obj.IsStashable() {
return objects.None, nil
}
r.Inventory = append(r.Inventory, tile)
r.Inventory = append(r.Inventory, obj)
w.Rovers[rover] = r
w.Atlas.SetTile(r.Pos, objects.Empty)
return tile, nil
w.Atlas.SetObject(r.Pos, objects.Object{Type: objects.None})
return obj.Type, nil
}
// RadarFromRover can be used to query what a rover can currently see
func (w *World) RadarFromRover(rover string) ([]byte, error) {
func (w *World) RadarFromRover(rover string) (radar []byte, objs []byte, err error) {
w.worldMutex.RLock()
defer w.worldMutex.RUnlock()
r, ok := w.Rovers[rover]
if !ok {
return nil, fmt.Errorf("no rover matching id")
err = fmt.Errorf("no rover matching id")
return
}
// The radar should span in range direction on each axis, plus the row/column the rover is currently on
@ -288,18 +287,19 @@ func (w *World) RadarFromRover(rover string) ([]byte, error) {
}
// Gather up all tiles within the range
var radar = make([]byte, radarSpan*radarSpan)
radar = make([]byte, radarSpan*radarSpan)
objs = make([]byte, radarSpan*radarSpan)
for j := radarMin.Y; j <= radarMax.Y; j++ {
for i := radarMin.X; i <= radarMax.X; i++ {
q := vector.Vector{X: i, Y: j}
tile := w.Atlas.GetTile(q)
tile, obj := w.Atlas.QueryPosition(q)
// Get the position relative to the bottom left of the radar
relative := q.Added(radarMin.Negated())
index := relative.X + relative.Y*radarSpan
radar[index] = tile
objs[index] = byte(obj.Type)
}
}
@ -312,14 +312,11 @@ func (w *World) RadarFromRover(rover string) ([]byte, error) {
if dist.X <= r.Range && dist.Y <= r.Range {
relative := r.Pos.Added(radarMin.Negated())
index := relative.X + relative.Y*radarSpan
radar[index] = objects.Rover
objs[index] = byte(objects.Rover)
}
}
// Add this rover
radar[len(radar)/2] = objects.Rover
return radar, nil
return radar, objs, nil
}
// Enqueue will queue the commands given
@ -433,7 +430,14 @@ func PrintTiles(tiles []byte) {
num := int(math.Sqrt(float64(len(tiles))))
for j := num - 1; j >= 0; j-- {
for i := 0; i < num; i++ {
fmt.Printf("%c", tiles[i+num*j])
t := tiles[i+num*j]
if t != 0 {
fmt.Printf("%c", t)
} else {
fmt.Printf(" ")
}
}
fmt.Print("\n")
}

View file

@ -3,6 +3,7 @@ package game
import (
"testing"
"github.com/mdiluz/rove/pkg/atlas"
"github.com/mdiluz/rove/pkg/bearing"
"github.com/mdiluz/rove/pkg/objects"
"github.com/mdiluz/rove/pkg/vector"
@ -84,7 +85,7 @@ func TestWorld_GetSetMovePosition(t *testing.T) {
assert.Equal(t, pos, newPos, "Failed to correctly move position for rover")
// Place a tile in front of the rover
world.Atlas.SetTile(vector.Vector{X: 0, Y: 2}, objects.LargeRock)
world.Atlas.SetObject(vector.Vector{X: 0, Y: 2}, objects.Object{Type: objects.LargeRock})
newPos, err = world.MoveRover(a, b)
assert.Equal(t, pos, newPos, "Failed to correctly not move position for rover into wall")
}
@ -102,14 +103,15 @@ func TestWorld_RadarFromRover(t *testing.T) {
assert.NoError(t, world.WarpRover(b, bpos), "Failed to warp rover")
assert.NoError(t, world.WarpRover(a, vector.Vector{X: 0, Y: 0}), "Failed to warp rover")
radar, err := world.RadarFromRover(a)
radar, objs, err := world.RadarFromRover(a)
assert.NoError(t, err, "Failed to get radar from rover")
fullRange := 4 + 4 + 1
assert.Equal(t, fullRange*fullRange, len(radar), "Radar returned wrong length")
assert.Equal(t, fullRange*fullRange, len(objs), "Radar returned wrong length")
// Test the expected values
assert.Equal(t, objects.Rover, radar[1+fullRange])
assert.Equal(t, objects.Rover, radar[4+4*fullRange])
assert.Equal(t, byte(objects.Rover), objs[1+fullRange])
assert.Equal(t, byte(objects.Rover), objs[4+4*fullRange])
}
func TestWorld_RoverStash(t *testing.T) {
@ -125,18 +127,20 @@ func TestWorld_RoverStash(t *testing.T) {
err = world.WarpRover(a, pos)
assert.NoError(t, err, "Failed to set position for rover")
world.Atlas.SetTile(pos, objects.SmallRock)
// Set to a traversible tile
world.Atlas.SetTile(pos, atlas.TileRock)
world.Atlas.SetObject(pos, objects.Object{Type: objects.SmallRock})
o, err := world.RoverStash(a)
assert.NoError(t, err, "Failed to stash")
assert.Equal(t, objects.SmallRock, o, "Failed to get correct object")
tile := world.Atlas.GetTile(pos)
assert.Equal(t, objects.Empty, tile, "Stash failed to remove object from atlas")
_, obj := world.Atlas.QueryPosition(pos)
assert.Equal(t, objects.None, obj.Type, "Stash failed to remove object from atlas")
inv, err := world.RoverInventory(a)
assert.NoError(t, err, "Failed to get inventory")
assert.Equal(t, objects.SmallRock, inv[0])
assert.Equal(t, objects.Object{Type: objects.SmallRock}, inv[0])
}
func TestWorld_RoverDamage(t *testing.T) {
@ -155,7 +159,7 @@ func TestWorld_RoverDamage(t *testing.T) {
info, err := world.GetRover(a)
assert.NoError(t, err, "couldn't get rover info")
world.Atlas.SetTile(vector.Vector{X: 0.0, Y: 1.0}, objects.LargeRock)
world.Atlas.SetObject(vector.Vector{X: 0.0, Y: 1.0}, objects.Object{Type: objects.LargeRock})
vec, err := world.MoveRover(a, bearing.North)
assert.NoError(t, err, "Failed to move rover")
@ -176,19 +180,22 @@ func TestWorld_RoverRepair(t *testing.T) {
Y: 0.0,
}
world.Atlas.SetTile(pos, atlas.TileNone)
world.Atlas.SetObject(pos, objects.Object{Type: objects.None})
err = world.WarpRover(a, pos)
assert.NoError(t, err, "Failed to set position for rover")
originalInfo, err := world.GetRover(a)
assert.NoError(t, err, "couldn't get rover info")
world.Atlas.SetTile(pos, objects.SmallRock)
world.Atlas.SetObject(pos, objects.Object{Type: objects.SmallRock})
o, err := world.RoverStash(a)
assert.NoError(t, err, "Failed to stash")
assert.Equal(t, objects.SmallRock, o, "Failed to get correct object")
world.Atlas.SetTile(vector.Vector{X: 0.0, Y: 1.0}, objects.LargeRock)
world.Atlas.SetObject(vector.Vector{X: 0.0, Y: 1.0}, objects.Object{Type: objects.LargeRock})
vec, err := world.MoveRover(a, bearing.North)
assert.NoError(t, err, "Failed to move rover")

View file

@ -1,28 +1,37 @@
package objects
// Type represents an object type
type Type byte
// Types of objects
const (
// Empty represents an non-existant object
Empty = byte(' ')
// None represents no object at all
None = Type(0)
// Rover represents a live rover
Rover = byte('R')
Rover = Type('R')
// SmallRock is a small stashable rock
SmallRock = byte('o')
SmallRock = Type('o')
// LargeRock is a large blocking rock
LargeRock = byte('O')
LargeRock = Type('o')
)
// Object represents an object in the world
type Object struct {
Type Type `json:"type"`
}
// IsBlocking checks if an object is a blocking object
func IsBlocking(object byte) bool {
var blocking = [...]byte{
func (o *Object) IsBlocking() bool {
var blocking = [...]Type{
Rover,
LargeRock,
}
for _, t := range blocking {
if object == t {
if o.Type == t {
return true
}
}
@ -30,13 +39,13 @@ func IsBlocking(object byte) bool {
}
// IsStashable checks if an object is stashable
func IsStashable(object byte) bool {
var stashable = [...]byte{
func (o *Object) IsStashable() bool {
var stashable = [...]Type{
SmallRock,
}
for _, t := range stashable {
if object == t {
if o.Type == t {
return true
}
}

View file

@ -42,6 +42,7 @@ type Command struct {
// The command to execute
// "move" - Move the rover in a direction, requires bearing
// "stash" - Stashes item at current location in rover inventory
// "repair" - Repairs the rover using an inventory object
Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"`
// The bearing, example: NE
Bearing string `protobuf:"bytes,2,opt,name=bearing,proto3" json:"bearing,omitempty"`
@ -294,6 +295,8 @@ type RadarResponse struct {
Range int32 `protobuf:"varint,1,opt,name=range,proto3" json:"range,omitempty"`
// A 1D array representing range*2 + 1 squared set of tiles, origin bottom left and in row->column order
Tiles []byte `protobuf:"bytes,2,opt,name=tiles,proto3" json:"tiles,omitempty"`
// A similar array to the tile array, but containing objects
Objects []byte `protobuf:"bytes,3,opt,name=objects,proto3" json:"objects,omitempty"`
}
func (x *RadarResponse) Reset() {
@ -342,6 +345,13 @@ func (x *RadarResponse) GetTiles() []byte {
return nil
}
func (x *RadarResponse) GetObjects() []byte {
if x != nil {
return x.Objects
}
return nil
}
// Empty placeholder
type RegisterResponse struct {
state protoimpl.MessageState
@ -751,64 +761,66 @@ var file_rove_rove_proto_rawDesc = []byte{
0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22,
0x28, 0x0a, 0x0c, 0x52, 0x61, 0x64, 0x61, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3b, 0x0a, 0x0d, 0x52, 0x61, 0x64,
0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x55, 0x0a, 0x0d, 0x52, 0x61, 0x64,
0x61, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x61,
0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65,
0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x05, 0x74, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x0a, 0x0f, 0x52, 0x65,
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x22, 0x28, 0x0a, 0x0c, 0x52, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x9f, 0x01, 0x0a, 0x0d,
0x52, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x12, 0x28, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f,
0x72, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x72,
0x61, 0x6e, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x72, 0x61, 0x6e, 0x67,
0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x12,
0x1c, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01,
0x28, 0x05, 0x52, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0f, 0x0a,
0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x71,
0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x14, 0x0a,
0x05, 0x72, 0x65, 0x61, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65,
0x61, 0x64, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28,
0x05, 0x52, 0x04, 0x74, 0x69, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x22, 0x24, 0x0a, 0x06, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x0c, 0x0a, 0x01, 0x78,
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x02,
0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x79, 0x32, 0xf8, 0x02, 0x0a, 0x04, 0x52, 0x6f, 0x76, 0x65,
0x12, 0x44, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x13, 0x2e, 0x72, 0x6f, 0x76,
0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x14, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x09, 0x12, 0x07, 0x2f,
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4f, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
0x65, 0x72, 0x12, 0x15, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x6f, 0x76, 0x65,
0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x22, 0x09, 0x2f, 0x72, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x4f, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x73, 0x12, 0x15, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61,
0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x6f, 0x76,
0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x22, 0x09, 0x2f, 0x63, 0x6f, 0x6d,
0x6d, 0x61, 0x6e, 0x64, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x43, 0x0a, 0x05, 0x52, 0x61, 0x64, 0x61,
0x72, 0x12, 0x12, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x52, 0x61, 0x64, 0x61, 0x72, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x52, 0x61, 0x64,
0x61, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x0b, 0x22, 0x06, 0x2f, 0x72, 0x61, 0x64, 0x61, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x43, 0x0a,
0x05, 0x52, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x12, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x52, 0x6f,
0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x72, 0x6f, 0x76,
0x65, 0x2e, 0x52, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x22, 0x06, 0x2f, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x3a,
0x01, 0x2a, 0x42, 0x21, 0x5a, 0x1f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x6d, 0x64, 0x69, 0x6c, 0x75, 0x7a, 0x2f, 0x72, 0x6f, 0x76, 0x65, 0x2f, 0x70, 0x6b, 0x67,
0x2f, 0x72, 0x6f, 0x76, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x05, 0x74, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73,
0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x28, 0x0a, 0x0c, 0x52,
0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x9f, 0x01, 0x0a, 0x0d, 0x52, 0x6f, 0x76, 0x65, 0x72, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x08, 0x70,
0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
0x72, 0x6f, 0x76, 0x65, 0x2e, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x70, 0x6f, 0x73,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69,
0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09,
0x69, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x6e, 0x74,
0x65, 0x67, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x49, 0x6e,
0x74, 0x65, 0x67, 0x72, 0x69, 0x74, 0x79, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x71, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x65,
0x78, 0x74, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e,
0x65, 0x78, 0x74, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x61, 0x64, 0x79,
0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x61, 0x64, 0x79, 0x12, 0x12, 0x0a,
0x04, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x69, 0x63,
0x6b, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x24, 0x0a, 0x06, 0x56,
0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01,
0x79, 0x32, 0xf8, 0x02, 0x0a, 0x04, 0x52, 0x6f, 0x76, 0x65, 0x12, 0x44, 0x0a, 0x06, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x12, 0x13, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x6f, 0x76, 0x65,
0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x0f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x09, 0x12, 0x07, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x12, 0x4f, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x15, 0x2e, 0x72,
0x6f, 0x76, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73,
0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4,
0x93, 0x02, 0x0e, 0x22, 0x09, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x3a, 0x01,
0x2a, 0x12, 0x4f, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x15, 0x2e,
0x72, 0x6f, 0x76, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d,
0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x0e, 0x22, 0x09, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x3a,
0x01, 0x2a, 0x12, 0x43, 0x0a, 0x05, 0x52, 0x61, 0x64, 0x61, 0x72, 0x12, 0x12, 0x2e, 0x72, 0x6f,
0x76, 0x65, 0x2e, 0x52, 0x61, 0x64, 0x61, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x13, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x52, 0x61, 0x64, 0x61, 0x72, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x22, 0x06, 0x2f, 0x72,
0x61, 0x64, 0x61, 0x72, 0x3a, 0x01, 0x2a, 0x12, 0x43, 0x0a, 0x05, 0x52, 0x6f, 0x76, 0x65, 0x72,
0x12, 0x12, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x52, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x2e, 0x52, 0x6f, 0x76, 0x65,
0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x0b, 0x22, 0x06, 0x2f, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x3a, 0x01, 0x2a, 0x42, 0x21, 0x5a, 0x1f,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x64, 0x69, 0x6c, 0x75,
0x7a, 0x2f, 0x72, 0x6f, 0x76, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x72, 0x6f, 0x76, 0x65, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View file

@ -212,7 +212,7 @@
"properties": {
"command": {
"type": "string",
"title": "The command to execute\n\"move\" - Move the rover in a direction, requires bearing\n\"stash\" - Stashes item at current location in rover inventory"
"title": "The command to execute\n\"move\" - Move the rover in a direction, requires bearing\n\"stash\" - Stashes item at current location in rover inventory\n\"repair\" - Repairs the rover using an inventory object"
},
"bearing": {
"type": "string",
@ -261,6 +261,11 @@
"type": "string",
"format": "byte",
"title": "A 1D array representing range*2 + 1 squared set of tiles, origin bottom left and in row-\u003ecolumn order"
},
"objects": {
"type": "string",
"format": "byte",
"title": "A similar array to the tile array, but containing objects"
}
}
},

View file

@ -98,6 +98,9 @@ message RadarResponse {
// A 1D array representing range*2 + 1 squared set of tiles, origin bottom left and in row->column order
bytes tiles = 2;
// A similar array to the tile array, but containing objects
bytes objects = 3;
}
// Empty placeholder