From aabda1cc908f5526b1aa960cd1c31f140516db79 Mon Sep 17 00:00:00 2001 From: Stephen McQuay Date: Wed, 13 Nov 2013 20:38:57 -0800 Subject: [PATCH] added config file support --- config.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++ control.go | 19 ++++++++++------- game.go | 38 +++++++++++++++++---------------- main.go | 22 ++++++++++++-------- protocol.go | 7 ++++++- 5 files changed, 110 insertions(+), 36 deletions(-) create mode 100644 config.go diff --git a/config.go b/config.go new file mode 100644 index 0000000..224bd2f --- /dev/null +++ b/config.go @@ -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 +} diff --git a/control.go b/control.go index b62ab9b..432497c 100644 --- a/control.go +++ b/control.go @@ -20,7 +20,8 @@ func startGame(w http.ResponseWriter, req *http.Request) { log.Println("asked to create a game") 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 // a posted json blob @@ -30,12 +31,13 @@ func startGame(w http.ResponseWriter, req *http.Request) { log.Printf("unable to read request body:", err) } req.Body.Close() - conf := struct { - With float32 `json:"width"` + cfg := struct { + Width float32 `json:"width"` Height float32 `json:"height"` Name string `json:"name"` + Tick int `json:"tick"` }{} - err = json.Unmarshal(body, &conf) + err = json.Unmarshal(body, &cfg) if err != nil { NewFailure(err.Error()) if err := json.NewEncoder(w).Encode(NewFailure(err.Error())); err != nil { @@ -43,15 +45,16 @@ func startGame(w http.ResponseWriter, req *http.Request) { } return } - requested_game_name = conf.Name - width = conf.With - height = conf.Height + requested_game_name = cfg.Name + width = cfg.Width + height = cfg.Height + tick = cfg.Tick } g := games.get(requested_game_name) if g == nil { 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() games.add(g) } else { diff --git a/game.go b/game.go index c656f42..d6fd7c2 100644 --- a/game.go +++ b/game.go @@ -80,26 +80,28 @@ type game struct { kill chan bool repair_hp int 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{ - id: id, - register: make(chan *player), - unregister: make(chan *player, maxPlayer), - projectiles: make(map[*Projectile]bool), - splosions: make(map[*Splosion]bool), - obstacles: GenerateObstacles(*obstacle_count, width, height), - players: make(map[*player]bool), - turn: 0, - width: width, - height: height, - spectators: make(map[*Spectator]bool), - sregister: make(chan *Spectator), - sunregister: make(chan *Spectator), - kill: make(chan bool, maxPlayer), - repair_hp: 5, - repair_rate: 3.0, + id: id, + register: make(chan *player), + unregister: make(chan *player, maxPlayer), + projectiles: make(map[*Projectile]bool), + splosions: make(map[*Splosion]bool), + obstacles: GenerateObstacles(conf.Obstacles, width, height), + players: make(map[*player]bool), + turn: 0, + width: width, + height: height, + spectators: make(map[*Spectator]bool), + sregister: make(chan *Spectator), + sunregister: make(chan *Spectator), + kill: make(chan bool, maxPlayer), + repair_hp: 5, + repair_rate: 3.0, + tick_duration: tick, } return g } @@ -251,7 +253,7 @@ func (g *game) sendUpdate(payload *Boardstate) { func (g *game) run() { var t0, t1 time.Time - ticker := time.NewTicker(time.Duration(*tick) * time.Millisecond) + ticker := time.NewTicker(time.Duration(conf.Tick) * time.Millisecond) for { select { case <-g.kill: diff --git a/main.go b/main.go index e600dc6..58ddeb6 100644 --- a/main.go +++ b/main.go @@ -13,25 +13,23 @@ import ( ) var addr = flag.String("addr", ":8666", "http service address") -var tick = flag.Int("tick", 60, "") -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 debug = flag.Bool("debug", false, "automatically create games if they don't exist") 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 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 idg *IdGenerator +var conf Config // This is the main, global collection of games var games MapLock func main() { log.Printf("Starting Server...") + var err error rand.Seed(time.Now().UnixNano()) flag.Parse() @@ -51,7 +49,13 @@ func main() { games = MapLock{m: make(map[string]*game)} 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() @@ -62,7 +66,7 @@ func main() { sm.HandleFunc("/game/stop/", stopGame) sm.HandleFunc("/fuck/shit/up/", killServer) - err := http.ListenAndServe(*addr, sm) + err = http.ListenAndServe(*addr, sm) if err != nil { log.Fatal("unable to start server") } diff --git a/protocol.go b/protocol.go index 036906f..d47c9eb 100644 --- a/protocol.go +++ b/protocol.go @@ -125,7 +125,12 @@ func addPlayer(ws *websocket.Conn) { if game == nil { force := *debug 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() games.add(game) } else {