package server import ( "encoding/json" "errors" "fmt" "io/ioutil" "log" "os" "strings" ) // Config embodies the configuration for a game. These are populated in various // ways (json POSTed to server, config file, constants) and are typically owned // by a Controller. type Config struct { Tick int `json:"tick"` // ms Timescale float64 `json:"timescale"` Delta float64 `json:"delta"` Width int `json:"width"` Height int `json:"height"` ObstacleCount int `json:"obstacle_count"` Obstacles []Obstacle `json:'obstacles'` MaxPoints int `json:"max_points"` Mode string `json:"mode"` } const ( TICK = 60 // ms, this is how often physics is updated TIMESCALE = 1.0 // this tweaks the temporal duration of a TICK WIDTH = 800 HEIGHT = 550 OBSTACLE_COUNT = 5 MAX_POINTS = 500 // allowing for 50 pts in every category DEFAULT_MODE = "deathmatch" ) // LoadConfig takes the location of a json file that contains values desired to // be used in the creation of games. Priority is given to values specified at // game cration time using control channel, followed by values in config file, // followed by constants defined above. func LoadConfig(filename string) (Config, error) { c := Config{ Tick: TICK, Timescale: TIMESCALE, Width: WIDTH, Height: HEIGHT, ObstacleCount: OBSTACLE_COUNT, MaxPoints: MAX_POINTS, Mode: DEFAULT_MODE, } home := os.Getenv("HOME") if len(filename) > 1 && filename[:2] == "~/" { filename = strings.Replace(filename, "~", home, 1) } if _, err := os.Stat(filename); os.IsNotExist(err) { log.Printf("%+v not found, using defaults", filename) } 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)) } } c.Delta = float64(c.Tick) / 1000.0 * c.Timescale log.Printf("final config: %#v", c) return c, nil }