commit
89123394cd
11 changed files with 246 additions and 153 deletions
|
@ -22,6 +22,9 @@ const (
|
|||
// GlyphRoverLive represents a live rover
|
||||
GlyphRoverLive = Glyph('R')
|
||||
|
||||
// GlyphRoverDormant represents a dormant rover
|
||||
GlyphRoverDormant = Glyph('r')
|
||||
|
||||
// GlyphRockSmall is a small stashable rock
|
||||
GlyphRockSmall = Glyph('o')
|
||||
|
||||
|
@ -51,6 +54,8 @@ func ObjectGlyph(o roveapi.Object) Glyph {
|
|||
return GlyphRoverLive
|
||||
case roveapi.Object_RockSmall:
|
||||
return GlyphRockSmall
|
||||
case roveapi.Object_RoverDormant:
|
||||
return GlyphRoverDormant
|
||||
case roveapi.Object_RockLarge:
|
||||
return GlyphRockLarge
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package atlas
|
||||
package rove
|
||||
|
||||
import (
|
||||
"github.com/mdiluz/rove/pkg/maths"
|
|
@ -1,4 +1,4 @@
|
|||
package atlas
|
||||
package rove
|
||||
|
||||
import (
|
||||
"testing"
|
|
@ -1,4 +1,4 @@
|
|||
package atlas
|
||||
package rove
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/mdiluz/rove/pkg/maths"
|
||||
"github.com/mdiluz/rove/proto/roveapi"
|
||||
"github.com/ojrac/opensimplex-go"
|
||||
)
|
||||
|
||||
// chunk represents a fixed square grid of tiles
|
||||
|
@ -34,17 +33,12 @@ type chunkBasedAtlas struct {
|
|||
// ChunkSize is the x/y dimensions of each square chunk
|
||||
ChunkSize int `json:"chunksize"`
|
||||
|
||||
// terrainNoise describes the noise function for the terrain
|
||||
terrainNoise opensimplex.Noise
|
||||
|
||||
// terrainNoise describes the noise function for the terrain
|
||||
objectNoise opensimplex.Noise
|
||||
// worldGen is the internal world generator
|
||||
worldGen WorldGen
|
||||
}
|
||||
|
||||
const (
|
||||
noiseSeed = 1024
|
||||
terrainNoiseScale = 6
|
||||
objectNoiseScale = 3
|
||||
)
|
||||
|
||||
// NewChunkAtlas creates a new empty atlas
|
||||
|
@ -55,8 +49,7 @@ func NewChunkAtlas(chunkSize int) Atlas {
|
|||
Chunks: make([]chunk, 1),
|
||||
LowerBound: maths.Vector{X: 0, Y: 0},
|
||||
UpperBound: maths.Vector{X: chunkSize, Y: chunkSize},
|
||||
terrainNoise: opensimplex.New(noiseSeed),
|
||||
objectNoise: opensimplex.New(noiseSeed),
|
||||
worldGen: NewNoiseWorldGen(noiseSeed),
|
||||
}
|
||||
// Initialise the first chunk
|
||||
a.populate(0)
|
||||
|
@ -105,31 +98,15 @@ func (a *chunkBasedAtlas) populate(chunk int) {
|
|||
origin := a.chunkOriginInWorldSpace(chunk)
|
||||
for i := 0; i < a.ChunkSize; i++ {
|
||||
for j := 0; j < a.ChunkSize; j++ {
|
||||
loc := maths.Vector{X: origin.X + i, Y: origin.Y + j}
|
||||
|
||||
// Get the terrain noise value for this location
|
||||
t := a.terrainNoise.Eval2(float64(origin.X+i)/terrainNoiseScale, float64(origin.Y+j)/terrainNoiseScale)
|
||||
var tile roveapi.Tile
|
||||
switch {
|
||||
case t > 0.5:
|
||||
tile = roveapi.Tile_Gravel
|
||||
case t > 0.05:
|
||||
tile = roveapi.Tile_Sand
|
||||
default:
|
||||
tile = roveapi.Tile_Rock
|
||||
}
|
||||
c.Tiles[j*a.ChunkSize+i] = byte(tile)
|
||||
// Set the tile
|
||||
c.Tiles[j*a.ChunkSize+i] = byte(a.worldGen.GetTile(loc))
|
||||
|
||||
// Get the object noise value for this location
|
||||
o := a.objectNoise.Eval2(float64(origin.X+i)/objectNoiseScale, float64(origin.Y+j)/objectNoiseScale)
|
||||
var obj = roveapi.Object_ObjectUnknown
|
||||
switch {
|
||||
case o > 0.6:
|
||||
obj = roveapi.Object_RockLarge
|
||||
case o > 0.5:
|
||||
obj = roveapi.Object_RockSmall
|
||||
}
|
||||
if obj != roveapi.Object_ObjectUnknown {
|
||||
c.Objects[j*a.ChunkSize+i] = Object{Type: roveapi.Object(obj)}
|
||||
// Set the object
|
||||
obj := a.worldGen.GetObject(loc)
|
||||
if obj.Type != roveapi.Object_ObjectUnknown {
|
||||
c.Objects[j*a.ChunkSize+i] = obj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,8 +217,7 @@ func (a *chunkBasedAtlas) worldSpaceToChunkWithGrow(v maths.Vector) int {
|
|||
LowerBound: lower,
|
||||
UpperBound: upper,
|
||||
Chunks: make([]chunk, size.X*size.Y),
|
||||
terrainNoise: a.terrainNoise,
|
||||
objectNoise: a.objectNoise,
|
||||
worldGen: a.worldGen,
|
||||
}
|
||||
|
||||
// Log that we're resizing
|
|
@ -1,4 +1,4 @@
|
|||
package atlas
|
||||
package rove
|
||||
|
||||
import (
|
||||
"github.com/mdiluz/rove/proto/roveapi"
|
||||
|
@ -8,12 +8,16 @@ import (
|
|||
type Object struct {
|
||||
// The type of the object
|
||||
Type roveapi.Object `json:"type"`
|
||||
|
||||
// Data is an internal type used for certain types of object
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
// IsBlocking checks if an object is a blocking object
|
||||
func (o *Object) IsBlocking() bool {
|
||||
var blocking = [...]roveapi.Object{
|
||||
roveapi.Object_RoverLive,
|
||||
roveapi.Object_RoverDormant,
|
||||
roveapi.Object_RockLarge,
|
||||
}
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
package rove
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/mdiluz/rove/pkg/atlas"
|
||||
"github.com/google/uuid"
|
||||
"github.com/mdiluz/rove/pkg/maths"
|
||||
)
|
||||
|
||||
|
@ -30,7 +33,7 @@ type Rover struct {
|
|||
Range int `json:"range"`
|
||||
|
||||
// Inventory represents any items the rover is carrying
|
||||
Inventory []atlas.Object `json:"inventory"`
|
||||
Inventory []Object `json:"inventory"`
|
||||
|
||||
// Capacity is the maximum number of inventory items
|
||||
Capacity int `json:"capacity"`
|
||||
|
@ -51,6 +54,19 @@ type Rover struct {
|
|||
Logs []RoverLogEntry `json:"logs"`
|
||||
}
|
||||
|
||||
// DefaultRover returns a default rover object with default settings
|
||||
func DefaultRover() Rover {
|
||||
return Rover{
|
||||
Range: 4,
|
||||
Integrity: 10,
|
||||
MaximumIntegrity: 10,
|
||||
Capacity: 10,
|
||||
Charge: 10,
|
||||
MaximumCharge: 10,
|
||||
Name: GenerateRoverName(),
|
||||
}
|
||||
}
|
||||
|
||||
// AddLogEntryf adds an entry to the rovers log
|
||||
func (r *Rover) AddLogEntryf(format string, args ...interface{}) {
|
||||
text := fmt.Sprintf(format, args...)
|
||||
|
@ -62,3 +78,36 @@ func (r *Rover) AddLogEntryf(format string, args ...interface{}) {
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
var wordsFile = os.Getenv("WORDS_FILE")
|
||||
var roverWords []string
|
||||
|
||||
// GenerateRoverName generates a new rover name
|
||||
func GenerateRoverName() string {
|
||||
|
||||
// Try and load the rover words file
|
||||
if len(roverWords) == 0 {
|
||||
// Try and load the words file
|
||||
if file, err := os.Open(wordsFile); err != nil {
|
||||
log.Printf("Couldn't read words file [%s], running without words: %s\n", wordsFile, err)
|
||||
} else {
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
roverWords = append(roverWords, scanner.Text())
|
||||
}
|
||||
if scanner.Err() != nil {
|
||||
log.Printf("Failure during word file scan: %s\n", scanner.Err())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assign a random name if we have words
|
||||
if len(roverWords) > 0 {
|
||||
// Loop until we find a unique name
|
||||
return fmt.Sprintf("%s-%s", roverWords[rand.Intn(len(roverWords))], roverWords[rand.Intn(len(roverWords))])
|
||||
}
|
||||
|
||||
// Default to a unique string
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
package rove
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/mdiluz/rove/pkg/atlas"
|
||||
"github.com/mdiluz/rove/pkg/maths"
|
||||
"github.com/mdiluz/rove/proto/roveapi"
|
||||
)
|
||||
|
@ -26,7 +22,7 @@ type World struct {
|
|||
Rovers map[string]Rover `json:"rovers"`
|
||||
|
||||
// Atlas represends the world map of chunks and tiles
|
||||
Atlas atlas.Atlas `json:"atlas"`
|
||||
Atlas Atlas `json:"atlas"`
|
||||
|
||||
// Commands is the set of currently executing command streams per rover
|
||||
CommandQueue map[string]CommandStream `json:"commands"`
|
||||
|
@ -37,36 +33,15 @@ type World struct {
|
|||
worldMutex sync.RWMutex
|
||||
// Mutex to lock around command operations
|
||||
cmdMutex sync.RWMutex
|
||||
// Set of possible words to use for names
|
||||
words []string
|
||||
}
|
||||
|
||||
var wordsFile = os.Getenv("WORDS_FILE")
|
||||
|
||||
// NewWorld creates a new world object
|
||||
func NewWorld(chunkSize int) *World {
|
||||
|
||||
// Try and load the words file
|
||||
var lines []string
|
||||
if file, err := os.Open(wordsFile); err != nil {
|
||||
log.Printf("Couldn't read words file [%s], running without words: %s\n", wordsFile, err)
|
||||
} else {
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
lines = append(lines, scanner.Text())
|
||||
}
|
||||
if scanner.Err() != nil {
|
||||
log.Printf("Failure during word file scan: %s\n", scanner.Err())
|
||||
}
|
||||
}
|
||||
|
||||
return &World{
|
||||
Rovers: make(map[string]Rover),
|
||||
CommandQueue: make(map[string]CommandStream),
|
||||
CommandIncoming: make(map[string]CommandStream),
|
||||
Atlas: atlas.NewChunkAtlas(chunkSize),
|
||||
words: lines,
|
||||
Atlas: NewChunkAtlas(chunkSize),
|
||||
TicksPerDay: 24,
|
||||
CurrentTicks: 0,
|
||||
}
|
||||
|
@ -78,27 +53,7 @@ func (w *World) SpawnRover() (string, error) {
|
|||
defer w.worldMutex.Unlock()
|
||||
|
||||
// Initialise the rover
|
||||
rover := Rover{
|
||||
Range: 4,
|
||||
Integrity: 10,
|
||||
MaximumIntegrity: 10,
|
||||
Capacity: 10,
|
||||
Charge: 10,
|
||||
MaximumCharge: 10,
|
||||
Name: uuid.New().String(),
|
||||
}
|
||||
|
||||
// Assign a random name if we have words
|
||||
if len(w.words) > 0 {
|
||||
for {
|
||||
// Loop until we find a unique name
|
||||
name := fmt.Sprintf("%s-%s", w.words[rand.Intn(len(w.words))], w.words[rand.Intn(len(w.words))])
|
||||
if _, ok := w.Rovers[name]; !ok {
|
||||
rover.Name = name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
rover := DefaultRover()
|
||||
|
||||
// Spawn in a random place near the origin
|
||||
rover.Pos = maths.Vector{
|
||||
|
@ -240,7 +195,7 @@ func (w *World) SetRoverPosition(rover string, pos maths.Vector) error {
|
|||
}
|
||||
|
||||
// RoverInventory returns the inventory of a requested rover
|
||||
func (w *World) RoverInventory(rover string) ([]atlas.Object, error) {
|
||||
func (w *World) RoverInventory(rover string) ([]Object, error) {
|
||||
w.worldMutex.RLock()
|
||||
defer w.worldMutex.RUnlock()
|
||||
|
||||
|
@ -346,7 +301,7 @@ func (w *World) RoverStash(rover string) (roveapi.Object, error) {
|
|||
r.AddLogEntryf("stashed %c", obj.Type)
|
||||
r.Inventory = append(r.Inventory, obj)
|
||||
w.Rovers[rover] = r
|
||||
w.Atlas.SetObject(r.Pos, atlas.Object{Type: roveapi.Object_ObjectUnknown})
|
||||
w.Atlas.SetObject(r.Pos, Object{Type: roveapi.Object_ObjectUnknown})
|
||||
return obj.Type, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package rove
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mdiluz/rove/pkg/atlas"
|
||||
"github.com/mdiluz/rove/pkg/maths"
|
||||
"github.com/mdiluz/rove/proto/roveapi"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -90,7 +89,7 @@ func TestWorld_GetSetMovePosition(t *testing.T) {
|
|||
assert.Contains(t, rover.Logs[len(rover.Logs)-1].Text, "moved", "Rover logs should contain the move")
|
||||
|
||||
// Place a tile in front of the rover
|
||||
world.Atlas.SetObject(maths.Vector{X: 0, Y: 2}, atlas.Object{Type: roveapi.Object_RockLarge})
|
||||
world.Atlas.SetObject(maths.Vector{X: 0, Y: 2}, Object{Type: roveapi.Object_RockLarge})
|
||||
newPos, err = world.MoveRover(a, b)
|
||||
assert.NoError(t, err, "Failed to move rover")
|
||||
assert.Equal(t, pos, newPos, "Failed to correctly not move position for rover into wall")
|
||||
|
@ -110,7 +109,9 @@ func TestWorld_RadarFromRover(t *testing.T) {
|
|||
|
||||
// Warp the rovers into position
|
||||
bpos := maths.Vector{X: -3, Y: -3}
|
||||
world.Atlas.SetObject(bpos, Object{Type: roveapi.Object_ObjectUnknown})
|
||||
assert.NoError(t, world.WarpRover(b, bpos), "Failed to warp rover")
|
||||
world.Atlas.SetObject(maths.Vector{X: 0, Y: 0}, Object{Type: roveapi.Object_ObjectUnknown})
|
||||
assert.NoError(t, world.WarpRover(a, maths.Vector{X: 0, Y: 0}), "Failed to warp rover")
|
||||
|
||||
radar, objs, err := world.RadarFromRover(a)
|
||||
|
@ -142,7 +143,7 @@ func TestWorld_RoverStash(t *testing.T) {
|
|||
Y: 0.0,
|
||||
}
|
||||
|
||||
world.Atlas.SetObject(pos, atlas.Object{Type: roveapi.Object_ObjectUnknown})
|
||||
world.Atlas.SetObject(pos, Object{Type: roveapi.Object_ObjectUnknown})
|
||||
err = world.WarpRover(a, pos)
|
||||
assert.NoError(t, err, "Failed to set position for rover")
|
||||
|
||||
|
@ -151,7 +152,7 @@ func TestWorld_RoverStash(t *testing.T) {
|
|||
|
||||
for i := 0; i < rover.Capacity; i++ {
|
||||
// Place an object
|
||||
world.Atlas.SetObject(pos, atlas.Object{Type: roveapi.Object_RockSmall})
|
||||
world.Atlas.SetObject(pos, Object{Type: roveapi.Object_RockSmall})
|
||||
|
||||
// Pick it up
|
||||
o, err := world.RoverStash(a)
|
||||
|
@ -166,7 +167,7 @@ func TestWorld_RoverStash(t *testing.T) {
|
|||
inv, err := world.RoverInventory(a)
|
||||
assert.NoError(t, err, "Failed to get inventory")
|
||||
assert.Equal(t, i+1, len(inv))
|
||||
assert.Equal(t, atlas.Object{Type: roveapi.Object_RockSmall}, inv[i])
|
||||
assert.Equal(t, Object{Type: roveapi.Object_RockSmall}, inv[i])
|
||||
|
||||
// Check that this did reduce the charge
|
||||
info, err := world.GetRover(a)
|
||||
|
@ -183,7 +184,7 @@ func TestWorld_RoverStash(t *testing.T) {
|
|||
}
|
||||
|
||||
// Place an object
|
||||
world.Atlas.SetObject(pos, atlas.Object{Type: roveapi.Object_RockSmall})
|
||||
world.Atlas.SetObject(pos, Object{Type: roveapi.Object_RockSmall})
|
||||
|
||||
// Try to pick it up
|
||||
o, err := world.RoverStash(a)
|
||||
|
@ -221,7 +222,7 @@ func TestWorld_RoverDamage(t *testing.T) {
|
|||
info, err := world.GetRover(a)
|
||||
assert.NoError(t, err, "couldn't get rover info")
|
||||
|
||||
world.Atlas.SetObject(maths.Vector{X: 0.0, Y: 1.0}, atlas.Object{Type: roveapi.Object_RockLarge})
|
||||
world.Atlas.SetObject(maths.Vector{X: 0.0, Y: 1.0}, Object{Type: roveapi.Object_RockLarge})
|
||||
|
||||
vec, err := world.MoveRover(a, roveapi.Bearing_North)
|
||||
assert.NoError(t, err, "Failed to move rover")
|
||||
|
@ -243,7 +244,7 @@ func TestWorld_RoverRepair(t *testing.T) {
|
|||
Y: 0.0,
|
||||
}
|
||||
|
||||
world.Atlas.SetObject(pos, atlas.Object{Type: roveapi.Object_ObjectUnknown})
|
||||
world.Atlas.SetObject(pos, Object{Type: roveapi.Object_ObjectUnknown})
|
||||
|
||||
err = world.WarpRover(a, pos)
|
||||
assert.NoError(t, err, "Failed to set position for rover")
|
||||
|
@ -252,12 +253,12 @@ func TestWorld_RoverRepair(t *testing.T) {
|
|||
assert.NoError(t, err, "couldn't get rover info")
|
||||
|
||||
// Pick up something to repair with
|
||||
world.Atlas.SetObject(pos, atlas.Object{Type: roveapi.Object_RockSmall})
|
||||
world.Atlas.SetObject(pos, Object{Type: roveapi.Object_RockSmall})
|
||||
o, err := world.RoverStash(a)
|
||||
assert.NoError(t, err, "Failed to stash")
|
||||
assert.Equal(t, roveapi.Object_RockSmall, o, "Failed to get correct object")
|
||||
|
||||
world.Atlas.SetObject(maths.Vector{X: 0.0, Y: 1.0}, atlas.Object{Type: roveapi.Object_RockLarge})
|
||||
world.Atlas.SetObject(maths.Vector{X: 0.0, Y: 1.0}, Object{Type: roveapi.Object_RockLarge})
|
||||
|
||||
// Try and bump into the rock
|
||||
vec, err := world.MoveRover(a, roveapi.Bearing_North)
|
||||
|
@ -277,7 +278,7 @@ func TestWorld_RoverRepair(t *testing.T) {
|
|||
assert.Contains(t, newinfo.Logs[len(newinfo.Logs)-1].Text, "repair", "Rover logs should contain the repair")
|
||||
|
||||
// Check again that it can't repair past the max
|
||||
world.Atlas.SetObject(pos, atlas.Object{Type: roveapi.Object_RockSmall})
|
||||
world.Atlas.SetObject(pos, Object{Type: roveapi.Object_RockSmall})
|
||||
o, err = world.RoverStash(a)
|
||||
assert.NoError(t, err, "Failed to stash")
|
||||
assert.Equal(t, roveapi.Object_RockSmall, o, "Failed to get correct object")
|
||||
|
@ -308,7 +309,7 @@ func TestWorld_Charge(t *testing.T) {
|
|||
|
||||
// Ensure the path ahead is empty
|
||||
world.Atlas.SetTile(initialPos.Added(maths.BearingToVector(roveapi.Bearing_North)), roveapi.Tile_Rock)
|
||||
world.Atlas.SetObject(initialPos.Added(maths.BearingToVector(roveapi.Bearing_North)), atlas.Object{Type: roveapi.Object_ObjectUnknown})
|
||||
world.Atlas.SetObject(initialPos.Added(maths.BearingToVector(roveapi.Bearing_North)), Object{Type: roveapi.Object_ObjectUnknown})
|
||||
|
||||
// Try and move north (along unblocked path)
|
||||
newPos, err := world.MoveRover(a, roveapi.Bearing_North)
|
||||
|
@ -372,6 +373,8 @@ func TestWorld_Broadcast(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
|
||||
// Warp rovers near to eachother
|
||||
world.Atlas.SetObject(maths.Vector{X: 0, Y: 0}, Object{Type: roveapi.Object_ObjectUnknown})
|
||||
world.Atlas.SetObject(maths.Vector{X: 1, Y: 0}, Object{Type: roveapi.Object_ObjectUnknown})
|
||||
assert.NoError(t, world.WarpRover(a, maths.Vector{X: 0, Y: 0}))
|
||||
assert.NoError(t, world.WarpRover(b, maths.Vector{X: 1, Y: 0}))
|
||||
|
||||
|
@ -390,7 +393,7 @@ func TestWorld_Broadcast(t *testing.T) {
|
|||
assert.Contains(t, rb.Logs[len(rb.Logs)-1].Text, "ABC", "Rover A should have logged it's broadcast")
|
||||
|
||||
// Warp B outside of the range of A
|
||||
world.Atlas.SetObject(maths.Vector{X: ra.Range, Y: 0}, atlas.Object{Type: roveapi.Object_ObjectUnknown})
|
||||
world.Atlas.SetObject(maths.Vector{X: ra.Range, Y: 0}, Object{Type: roveapi.Object_ObjectUnknown})
|
||||
assert.NoError(t, world.WarpRover(b, maths.Vector{X: ra.Range, Y: 0}))
|
||||
|
||||
// Broadcast from a again
|
||||
|
@ -407,7 +410,7 @@ func TestWorld_Broadcast(t *testing.T) {
|
|||
assert.Contains(t, rb.Logs[len(rb.Logs)-1].Text, "XYZ", "Rover A should have logged it's broadcast")
|
||||
|
||||
// Warp B outside of the range of A
|
||||
world.Atlas.SetObject(maths.Vector{X: ra.Range + 1, Y: 0}, atlas.Object{Type: roveapi.Object_ObjectUnknown})
|
||||
world.Atlas.SetObject(maths.Vector{X: ra.Range + 1, Y: 0}, Object{Type: roveapi.Object_ObjectUnknown})
|
||||
assert.NoError(t, world.WarpRover(b, maths.Vector{X: ra.Range + 1, Y: 0}))
|
||||
|
||||
// Broadcast from a again
|
||||
|
|
93
pkg/rove/worldgen.go
Normal file
93
pkg/rove/worldgen.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
package rove
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/mdiluz/rove/pkg/maths"
|
||||
"github.com/mdiluz/rove/proto/roveapi"
|
||||
"github.com/ojrac/opensimplex-go"
|
||||
)
|
||||
|
||||
// WorldGen describes a world gen algorythm
|
||||
type WorldGen interface {
|
||||
// GetTile generates a tile for a location
|
||||
GetTile(v maths.Vector) roveapi.Tile
|
||||
|
||||
// GetObject generates an object for a location
|
||||
GetObject(v maths.Vector) Object
|
||||
}
|
||||
|
||||
// NoiseWorldGen returns a noise based world generator
|
||||
type NoiseWorldGen struct {
|
||||
// noise describes the noise function
|
||||
noise opensimplex.Noise
|
||||
}
|
||||
|
||||
// NewNoiseWorldGen creates a new noise based world generator
|
||||
func NewNoiseWorldGen(seed int64) WorldGen {
|
||||
return &NoiseWorldGen{
|
||||
noise: opensimplex.New(seed),
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
terrainNoiseScale = 6
|
||||
rockNoiseScale = 3
|
||||
)
|
||||
|
||||
// GetTile returns the chosen tile at a location
|
||||
func (g *NoiseWorldGen) GetTile(v maths.Vector) roveapi.Tile {
|
||||
t := g.noise.Eval2(float64(v.X)/terrainNoiseScale, float64(v.Y)/terrainNoiseScale)
|
||||
switch {
|
||||
case t > 0.5:
|
||||
return roveapi.Tile_Gravel
|
||||
case t > 0.05:
|
||||
return roveapi.Tile_Sand
|
||||
default:
|
||||
return roveapi.Tile_Rock
|
||||
}
|
||||
}
|
||||
|
||||
// GetObject returns the chosen object at a location
|
||||
func (g *NoiseWorldGen) GetObject(v maths.Vector) (obj Object) {
|
||||
o := g.noise.Eval2(float64(v.X)/rockNoiseScale, float64(v.Y)/rockNoiseScale)
|
||||
switch {
|
||||
case o > 0.6:
|
||||
obj.Type = roveapi.Object_RockLarge
|
||||
case o > 0.5:
|
||||
obj.Type = roveapi.Object_RockSmall
|
||||
}
|
||||
|
||||
// Very rarely spawn a dormant rover
|
||||
if obj.Type == roveapi.Object_ObjectUnknown {
|
||||
// TODO: Make this better, ideally with noise
|
||||
if v.X%25 == 0 && v.Y%25 == 0 && v.X != 0 && v.Y != 0 {
|
||||
obj.Type = roveapi.Object_RoverDormant
|
||||
}
|
||||
}
|
||||
|
||||
// Post process any spawned objects
|
||||
switch obj.Type {
|
||||
case roveapi.Object_RoverDormant:
|
||||
// Create the rover
|
||||
r := DefaultRover()
|
||||
|
||||
// Set the rover variables
|
||||
r.Pos = v
|
||||
|
||||
// For now, mark the log as corrupted
|
||||
r.AddLogEntryf("log corrupted")
|
||||
|
||||
// Marshal the rover data into the object data
|
||||
b, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
log.Fatalf("couldn't marshal rover, should never fail: %s", err)
|
||||
}
|
||||
|
||||
// Store the bytes
|
||||
obj.Data = b
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
|
@ -162,10 +162,12 @@ const (
|
|||
Object_ObjectUnknown Object = 0
|
||||
// RoverLive represents a live rover
|
||||
Object_RoverLive Object = 1
|
||||
// RoverDormant describes a dormant rover
|
||||
Object_RoverDormant Object = 2
|
||||
// RockSmall is a small stashable rock
|
||||
Object_RockSmall Object = 2
|
||||
Object_RockSmall Object = 3
|
||||
// RockLarge is a large blocking rock
|
||||
Object_RockLarge Object = 3
|
||||
Object_RockLarge Object = 4
|
||||
)
|
||||
|
||||
// Enum value maps for Object.
|
||||
|
@ -173,14 +175,16 @@ var (
|
|||
Object_name = map[int32]string{
|
||||
0: "ObjectUnknown",
|
||||
1: "RoverLive",
|
||||
2: "RockSmall",
|
||||
3: "RockLarge",
|
||||
2: "RoverDormant",
|
||||
3: "RockSmall",
|
||||
4: "RockLarge",
|
||||
}
|
||||
Object_value = map[string]int32{
|
||||
"ObjectUnknown": 0,
|
||||
"RoverLive": 1,
|
||||
"RockSmall": 2,
|
||||
"RockLarge": 3,
|
||||
"RoverDormant": 2,
|
||||
"RockSmall": 3,
|
||||
"RockLarge": 4,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -1269,39 +1273,40 @@ var file_roveapi_roveapi_proto_rawDesc = []byte{
|
|||
0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x4e, 0x6f, 0x72, 0x74, 0x68,
|
||||
0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x45, 0x61, 0x73, 0x74, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05,
|
||||
0x53, 0x6f, 0x75, 0x74, 0x68, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x65, 0x73, 0x74, 0x10,
|
||||
0x04, 0x2a, 0x48, 0x0a, 0x06, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x11, 0x0a, 0x0d, 0x4f,
|
||||
0x04, 0x2a, 0x5a, 0x0a, 0x06, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x11, 0x0a, 0x0d, 0x4f,
|
||||
0x62, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0d,
|
||||
0x0a, 0x09, 0x52, 0x6f, 0x76, 0x65, 0x72, 0x4c, 0x69, 0x76, 0x65, 0x10, 0x01, 0x12, 0x0d, 0x0a,
|
||||
0x09, 0x52, 0x6f, 0x63, 0x6b, 0x53, 0x6d, 0x61, 0x6c, 0x6c, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09,
|
||||
0x52, 0x6f, 0x63, 0x6b, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x10, 0x03, 0x2a, 0x37, 0x0a, 0x04, 0x54,
|
||||
0x69, 0x6c, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x69, 0x6c, 0x65, 0x55, 0x6e, 0x6b, 0x6e, 0x6f,
|
||||
0x77, 0x6e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x6f, 0x63, 0x6b, 0x10, 0x01, 0x12, 0x0a,
|
||||
0x0a, 0x06, 0x47, 0x72, 0x61, 0x76, 0x65, 0x6c, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x61,
|
||||
0x6e, 0x64, 0x10, 0x03, 0x32, 0xcf, 0x02, 0x0a, 0x04, 0x52, 0x6f, 0x76, 0x65, 0x12, 0x4d, 0x0a,
|
||||
0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x2e,
|
||||
0x0a, 0x09, 0x52, 0x6f, 0x76, 0x65, 0x72, 0x4c, 0x69, 0x76, 0x65, 0x10, 0x01, 0x12, 0x10, 0x0a,
|
||||
0x0c, 0x52, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x74, 0x10, 0x02, 0x12,
|
||||
0x0d, 0x0a, 0x09, 0x52, 0x6f, 0x63, 0x6b, 0x53, 0x6d, 0x61, 0x6c, 0x6c, 0x10, 0x03, 0x12, 0x0d,
|
||||
0x0a, 0x09, 0x52, 0x6f, 0x63, 0x6b, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x10, 0x04, 0x2a, 0x37, 0x0a,
|
||||
0x04, 0x54, 0x69, 0x6c, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x69, 0x6c, 0x65, 0x55, 0x6e, 0x6b,
|
||||
0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x6f, 0x63, 0x6b, 0x10, 0x01,
|
||||
0x12, 0x0a, 0x0a, 0x06, 0x47, 0x72, 0x61, 0x76, 0x65, 0x6c, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04,
|
||||
0x53, 0x61, 0x6e, 0x64, 0x10, 0x03, 0x32, 0xcf, 0x02, 0x0a, 0x04, 0x52, 0x6f, 0x76, 0x65, 0x12,
|
||||
0x4d, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
|
||||
0x1c, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e,
|
||||
0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x6f,
|
||||
0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x08,
|
||||
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x18, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x67,
|
||||
0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
|
||||
0x3e, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x17, 0x2e, 0x72, 0x6f, 0x76,
|
||||
0x65, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
|
||||
0x38, 0x0a, 0x05, 0x52, 0x61, 0x64, 0x61, 0x72, 0x12, 0x15, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x52, 0x61, 0x64, 0x61, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x16, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x64, 0x61, 0x72, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x06, 0x53, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x72, 0x6f,
|
||||
0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x64, 0x69, 0x6c, 0x75, 0x7a, 0x2f, 0x72, 0x6f, 0x76, 0x65,
|
||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41,
|
||||
0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x18, 0x2e, 0x72, 0x6f, 0x76,
|
||||
0x65, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x52,
|
||||
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x3e, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x17, 0x2e, 0x72,
|
||||
0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x38, 0x0a, 0x05, 0x52, 0x61, 0x64, 0x61, 0x72, 0x12, 0x15, 0x2e, 0x72, 0x6f, 0x76,
|
||||
0x65, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x64, 0x61, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x16, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x61, 0x64, 0x61,
|
||||
0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x06, 0x53,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e,
|
||||
0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x64, 0x69, 0x6c, 0x75, 0x7a, 0x2f, 0x72, 0x6f,
|
||||
0x76, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x6f, 0x76, 0x65, 0x61, 0x70, 0x69,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -151,11 +151,14 @@ enum Object {
|
|||
// RoverLive represents a live rover
|
||||
RoverLive = 1;
|
||||
|
||||
// RoverDormant describes a dormant rover
|
||||
RoverDormant = 2;
|
||||
|
||||
// RockSmall is a small stashable rock
|
||||
RockSmall = 2;
|
||||
RockSmall = 3;
|
||||
|
||||
// RockLarge is a large blocking rock
|
||||
RockLarge = 3;
|
||||
RockLarge = 4;
|
||||
}
|
||||
|
||||
enum Tile {
|
||||
|
|
Loading…
Add table
Reference in a new issue