added config file support
This commit is contained in:
parent
c7d5e4be87
commit
aabda1cc90
60
config.go
Normal file
60
config.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Tick int `json:"tick"` // ms
|
||||||
|
Timescale float32 `json:"timescale"`
|
||||||
|
Width int `json:"width"`
|
||||||
|
Height int `json:"height"`
|
||||||
|
Obstacles int `json:"obstacles"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TICK = 60
|
||||||
|
TIMESCALE = 1.0
|
||||||
|
WIDTH = 800
|
||||||
|
HEIGHT = 550
|
||||||
|
OBSTACLES = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadConfig(filename string) (Config, error) {
|
||||||
|
c := Config{}
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
if len(filename) > 1 && filename[:2] == "~/" {
|
||||||
|
filename = strings.Replace(filename, "~", u.HomeDir, 1)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||||
|
log.Printf("%+v not found, using defaults", filename)
|
||||||
|
return Config{
|
||||||
|
Tick: TICK,
|
||||||
|
Timescale: TIMESCALE,
|
||||||
|
Width: WIDTH,
|
||||||
|
Height: HEIGHT,
|
||||||
|
Obstacles: OBSTACLES,
|
||||||
|
}, nil
|
||||||
|
} else {
|
||||||
|
log.Printf("found config file: %s", filename)
|
||||||
|
f, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(f, &c)
|
||||||
|
if err != nil {
|
||||||
|
return c, errors.New(fmt.Sprintf("config parse error: %s", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
19
control.go
19
control.go
@ -20,7 +20,8 @@ func startGame(w http.ResponseWriter, req *http.Request) {
|
|||||||
log.Println("asked to create a game")
|
log.Println("asked to create a game")
|
||||||
|
|
||||||
requested_game_name := idg.Hash()
|
requested_game_name := idg.Hash()
|
||||||
width, height := float32(*width), float32(*height)
|
width, height := float32(conf.Width), float32(conf.Height)
|
||||||
|
tick := conf.Tick
|
||||||
|
|
||||||
// here we determine if we are going to run with defaults or pick them off
|
// here we determine if we are going to run with defaults or pick them off
|
||||||
// a posted json blob
|
// a posted json blob
|
||||||
@ -30,12 +31,13 @@ func startGame(w http.ResponseWriter, req *http.Request) {
|
|||||||
log.Printf("unable to read request body:", err)
|
log.Printf("unable to read request body:", err)
|
||||||
}
|
}
|
||||||
req.Body.Close()
|
req.Body.Close()
|
||||||
conf := struct {
|
cfg := struct {
|
||||||
With float32 `json:"width"`
|
Width float32 `json:"width"`
|
||||||
Height float32 `json:"height"`
|
Height float32 `json:"height"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Tick int `json:"tick"`
|
||||||
}{}
|
}{}
|
||||||
err = json.Unmarshal(body, &conf)
|
err = json.Unmarshal(body, &cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
NewFailure(err.Error())
|
NewFailure(err.Error())
|
||||||
if err := json.NewEncoder(w).Encode(NewFailure(err.Error())); err != nil {
|
if err := json.NewEncoder(w).Encode(NewFailure(err.Error())); err != nil {
|
||||||
@ -43,15 +45,16 @@ func startGame(w http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
requested_game_name = conf.Name
|
requested_game_name = cfg.Name
|
||||||
width = conf.With
|
width = cfg.Width
|
||||||
height = conf.Height
|
height = cfg.Height
|
||||||
|
tick = cfg.Tick
|
||||||
}
|
}
|
||||||
|
|
||||||
g := games.get(requested_game_name)
|
g := games.get(requested_game_name)
|
||||||
if g == nil {
|
if g == nil {
|
||||||
log.Printf("Game '%s' non-existant; making it now", requested_game_name)
|
log.Printf("Game '%s' non-existant; making it now", requested_game_name)
|
||||||
g = NewGame(requested_game_name, width, height)
|
g = NewGame(requested_game_name, width, height, tick)
|
||||||
go g.run()
|
go g.run()
|
||||||
games.add(g)
|
games.add(g)
|
||||||
} else {
|
} else {
|
||||||
|
38
game.go
38
game.go
@ -80,26 +80,28 @@ type game struct {
|
|||||||
kill chan bool
|
kill chan bool
|
||||||
repair_hp int
|
repair_hp int
|
||||||
repair_rate float32
|
repair_rate float32
|
||||||
|
tick_duration int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGame(id string, width, height float32) *game {
|
func NewGame(id string, width, height float32, tick int) *game {
|
||||||
g := &game{
|
g := &game{
|
||||||
id: id,
|
id: id,
|
||||||
register: make(chan *player),
|
register: make(chan *player),
|
||||||
unregister: make(chan *player, maxPlayer),
|
unregister: make(chan *player, maxPlayer),
|
||||||
projectiles: make(map[*Projectile]bool),
|
projectiles: make(map[*Projectile]bool),
|
||||||
splosions: make(map[*Splosion]bool),
|
splosions: make(map[*Splosion]bool),
|
||||||
obstacles: GenerateObstacles(*obstacle_count, width, height),
|
obstacles: GenerateObstacles(conf.Obstacles, width, height),
|
||||||
players: make(map[*player]bool),
|
players: make(map[*player]bool),
|
||||||
turn: 0,
|
turn: 0,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
spectators: make(map[*Spectator]bool),
|
spectators: make(map[*Spectator]bool),
|
||||||
sregister: make(chan *Spectator),
|
sregister: make(chan *Spectator),
|
||||||
sunregister: make(chan *Spectator),
|
sunregister: make(chan *Spectator),
|
||||||
kill: make(chan bool, maxPlayer),
|
kill: make(chan bool, maxPlayer),
|
||||||
repair_hp: 5,
|
repair_hp: 5,
|
||||||
repair_rate: 3.0,
|
repair_rate: 3.0,
|
||||||
|
tick_duration: tick,
|
||||||
}
|
}
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
@ -251,7 +253,7 @@ func (g *game) sendUpdate(payload *Boardstate) {
|
|||||||
|
|
||||||
func (g *game) run() {
|
func (g *game) run() {
|
||||||
var t0, t1 time.Time
|
var t0, t1 time.Time
|
||||||
ticker := time.NewTicker(time.Duration(*tick) * time.Millisecond)
|
ticker := time.NewTicker(time.Duration(conf.Tick) * time.Millisecond)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-g.kill:
|
case <-g.kill:
|
||||||
|
22
main.go
22
main.go
@ -13,25 +13,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var addr = flag.String("addr", ":8666", "http service address")
|
var addr = flag.String("addr", ":8666", "http service address")
|
||||||
var tick = flag.Int("tick", 60, "")
|
var debug = flag.Bool("debug", false, "automatically create games if they don't exist")
|
||||||
var timescale = flag.Float64("timescale", 1, "time scale factor")
|
|
||||||
var verbose = flag.Bool("verbose", false, "")
|
|
||||||
var width = flag.Float64("width", 800, "width of field")
|
|
||||||
var height = flag.Float64("height", 550, "height of field")
|
|
||||||
var obstacle_count = flag.Int("obstacles", 5, "how many obstacles")
|
|
||||||
var profile = flag.String("pprof", "", "if specified will run with pprof")
|
var profile = flag.String("pprof", "", "if specified will run with pprof")
|
||||||
var netprofile = flag.Bool("netprof", false, "if specified will run with net/http/pprof")
|
var netprofile = flag.Bool("netprof", false, "if specified will run with net/http/pprof")
|
||||||
var debug = flag.Bool("debug", false, "automatically create games if they don't exist")
|
var verbose = flag.Bool("verbose", false, "")
|
||||||
|
var config = flag.String("config", "~/.config/hackerbots/config.json", "location of config file")
|
||||||
|
|
||||||
var delta float32
|
var delta float32
|
||||||
|
|
||||||
var idg *IdGenerator
|
var idg *IdGenerator
|
||||||
|
var conf Config
|
||||||
|
|
||||||
// This is the main, global collection of games
|
// This is the main, global collection of games
|
||||||
var games MapLock
|
var games MapLock
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.Printf("Starting Server...")
|
log.Printf("Starting Server...")
|
||||||
|
var err error
|
||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
@ -51,7 +49,13 @@ func main() {
|
|||||||
games = MapLock{m: make(map[string]*game)}
|
games = MapLock{m: make(map[string]*game)}
|
||||||
idg = NewIdGenerator()
|
idg = NewIdGenerator()
|
||||||
|
|
||||||
delta = (float32(*tick) / 1000.0) * float32(*timescale)
|
conf, err = loadConfig(*config)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Printf("config: %+v", conf)
|
||||||
|
|
||||||
|
delta = (float32(conf.Tick) / 1000.0) * float32(conf.Timescale)
|
||||||
|
|
||||||
sm := http.NewServeMux()
|
sm := http.NewServeMux()
|
||||||
|
|
||||||
@ -62,7 +66,7 @@ func main() {
|
|||||||
sm.HandleFunc("/game/stop/", stopGame)
|
sm.HandleFunc("/game/stop/", stopGame)
|
||||||
sm.HandleFunc("/fuck/shit/up/", killServer)
|
sm.HandleFunc("/fuck/shit/up/", killServer)
|
||||||
|
|
||||||
err := http.ListenAndServe(*addr, sm)
|
err = http.ListenAndServe(*addr, sm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("unable to start server")
|
log.Fatal("unable to start server")
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,12 @@ func addPlayer(ws *websocket.Conn) {
|
|||||||
if game == nil {
|
if game == nil {
|
||||||
force := *debug
|
force := *debug
|
||||||
if force {
|
if force {
|
||||||
game = NewGame(gid.Id, float32(*width), float32(*height))
|
game = NewGame(
|
||||||
|
gid.Id,
|
||||||
|
float32(conf.Width),
|
||||||
|
float32(conf.Height),
|
||||||
|
conf.Tick,
|
||||||
|
)
|
||||||
go game.run()
|
go game.run()
|
||||||
games.add(game)
|
games.add(game)
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user