ignore new binary
Create new bserv binary Herein lie the following ideas: - change package visibility of many things - try to stash the globals into structs - the code is far from correct; it merely compiles
This commit is contained in:
parent
62222a9ad9
commit
c8efd34080
|
@ -1,3 +1,3 @@
|
||||||
botserv
|
bserv/bserv
|
||||||
*.swp
|
*.swp
|
||||||
tags
|
tags
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"time"
|
"time"
|
||||||
|
"bitbucket.org/hackerbots/botserv"
|
||||||
|
|
||||||
"code.google.com/p/go.net/websocket"
|
"code.google.com/p/go.net/websocket"
|
||||||
)
|
)
|
||||||
|
@ -22,12 +23,6 @@ var config = flag.String("config", "~/.config/hackerbots/config.json", "location
|
||||||
|
|
||||||
var delta float32
|
var delta float32
|
||||||
|
|
||||||
var idg *IdGenerator
|
|
||||||
var conf Config
|
|
||||||
|
|
||||||
// This is the main, global collection of games
|
|
||||||
var games MapLock
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
|
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
|
||||||
log.Printf("Starting Server...")
|
log.Printf("Starting Server...")
|
||||||
|
@ -49,10 +44,7 @@ func main() {
|
||||||
log.Println("serving profile info at http://localhost:8667/debug/pprof/")
|
log.Println("serving profile info at http://localhost:8667/debug/pprof/")
|
||||||
}
|
}
|
||||||
|
|
||||||
games = MapLock{m: make(map[string]*game)}
|
conf, err := botserv.LoadConfig(*config)
|
||||||
idg = NewIdGenerator()
|
|
||||||
|
|
||||||
conf, err = loadConfig(*config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -61,14 +53,24 @@ func main() {
|
||||||
|
|
||||||
sm := http.NewServeMux()
|
sm := http.NewServeMux()
|
||||||
|
|
||||||
sm.Handle("/", JsonHandler(index))
|
c := botserv.Controller{
|
||||||
sm.Handle("/ws/", websocket.Handler(addPlayer))
|
Idg: botserv.NewIdGenerator(),
|
||||||
sm.Handle("/game/start/", JsonHandler(startGame))
|
Conf: conf,
|
||||||
sm.Handle("/game/list/", JsonHandler(listGames))
|
Games: botserv.MapLock{
|
||||||
sm.Handle("/game/stats/", JsonHandler(gameStats))
|
M: make(map[string]*botserv.Game),
|
||||||
sm.Handle("/game/bw/", JsonHandler(bw))
|
},
|
||||||
sm.Handle("/game/stop/", JsonHandler(stopGame))
|
Memprofile: *mprofile,
|
||||||
sm.HandleFunc("/fuck/shit/up/", killServer)
|
Profile: *profile,
|
||||||
|
}
|
||||||
|
|
||||||
|
sm.Handle("/", botserv.JsonHandler(c.Index))
|
||||||
|
sm.Handle("/ws/", websocket.Handler(c.AddPlayer))
|
||||||
|
sm.Handle("/game/start/", botserv.JsonHandler(c.StartGame))
|
||||||
|
sm.Handle("/game/list/", botserv.JsonHandler(c.ListGames))
|
||||||
|
sm.Handle("/game/stats/", botserv.JsonHandler(c.GameStats))
|
||||||
|
sm.Handle("/game/bw/", botserv.JsonHandler(c.BW))
|
||||||
|
sm.Handle("/game/stop/", botserv.JsonHandler(c.StopGame))
|
||||||
|
sm.HandleFunc("/fuck/shit/up/", c.KillServer)
|
||||||
|
|
||||||
err = http.ListenAndServe(*addr, sm)
|
err = http.ListenAndServe(*addr, sm)
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -31,7 +31,7 @@ const (
|
||||||
DEFAULT_MODE = "deathmatch"
|
DEFAULT_MODE = "deathmatch"
|
||||||
)
|
)
|
||||||
|
|
||||||
func loadConfig(filename string) (Config, error) {
|
func LoadConfig(filename string) (Config, error) {
|
||||||
c := Config{
|
c := Config{
|
||||||
Tick: TICK,
|
Tick: TICK,
|
||||||
Timescale: TIMESCALE,
|
Timescale: TIMESCALE,
|
||||||
|
|
74
control.go
74
control.go
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -19,13 +19,21 @@ func (h JsonHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
h(w, req)
|
h(w, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func startGame(w http.ResponseWriter, req *http.Request) {
|
type Controller struct {
|
||||||
|
Idg *IdGenerator
|
||||||
|
Conf Config
|
||||||
|
Games MapLock
|
||||||
|
Memprofile string
|
||||||
|
Profile string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) 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 := c.Idg.Hash()
|
||||||
width, height := float32(conf.Width), float32(conf.Height)
|
width, height := float32(c.Conf.Width), float32(c.Conf.Height)
|
||||||
obstacles := 0
|
obstacles := 0
|
||||||
maxPoints := conf.MaxPoints
|
maxPoints := c.Conf.MaxPoints
|
||||||
mode := "deathmatch"
|
mode := "deathmatch"
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -55,10 +63,10 @@ func startGame(w http.ResponseWriter, req *http.Request) {
|
||||||
mode = cfg.Mode
|
mode = cfg.Mode
|
||||||
}
|
}
|
||||||
|
|
||||||
g := games.get(requested_game_name)
|
g := c.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, err := NewGame(requested_game_name, width, height, obstacles, conf.Tick, maxPoints, mode)
|
g, err := NewGame(requested_game_name, width, height, obstacles, c.Conf.Tick, maxPoints, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("problem creating game: %s: %s", requested_game_name, err)
|
log.Printf("problem creating game: %s: %s", requested_game_name, err)
|
||||||
b, _ := json.Marshal(NewFailure("game creation failure"))
|
b, _ := json.Marshal(NewFailure("game creation failure"))
|
||||||
|
@ -66,7 +74,7 @@ func startGame(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
go g.run()
|
go g.run()
|
||||||
games.add(g)
|
c.Games.add(g)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Game '%s' already exists: %p", requested_game_name, g)
|
log.Printf("Game '%s' already exists: %p", requested_game_name, g)
|
||||||
b, _ := json.Marshal(NewFailure("game already exists"))
|
b, _ := json.Marshal(NewFailure("game already exists"))
|
||||||
|
@ -84,10 +92,10 @@ func startGame(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func listGames(w http.ResponseWriter, req *http.Request) {
|
func (c *Controller) ListGames(w http.ResponseWriter, req *http.Request) {
|
||||||
log.Println("games list requested")
|
log.Println("games list requested")
|
||||||
games.RLock()
|
c.Games.RLock()
|
||||||
defer games.RUnlock()
|
defer c.Games.RUnlock()
|
||||||
type pout struct {
|
type pout struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
@ -97,7 +105,7 @@ func listGames(w http.ResponseWriter, req *http.Request) {
|
||||||
Players []pout `json:"players"`
|
Players []pout `json:"players"`
|
||||||
}
|
}
|
||||||
ids := make([]gl, 0)
|
ids := make([]gl, 0)
|
||||||
for id, g := range games.m {
|
for id, g := range c.Games.M {
|
||||||
players := make([]pout, 0)
|
players := make([]pout, 0)
|
||||||
// TODO - players instead of robots?
|
// TODO - players instead of robots?
|
||||||
for p := range g.players {
|
for p := range g.players {
|
||||||
|
@ -118,19 +126,19 @@ func listGames(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gameStats(w http.ResponseWriter, req *http.Request) {
|
func (c *Controller) GameStats(w http.ResponseWriter, req *http.Request) {
|
||||||
// TODO: wrap this up in something similar to the JsonHandler to verify the
|
// TODO: wrap this up in something similar to the JsonHandler to verify the
|
||||||
// url? Look at gorilla routing?
|
// url? Look at gorilla routing?
|
||||||
key, err := getGameId(req.URL.Path)
|
key, err := c.getGameId(req.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b, _ := json.Marshal(NewFailure(err.Error()))
|
b, _ := json.Marshal(NewFailure(err.Error()))
|
||||||
http.Error(w, string(b), http.StatusBadRequest)
|
http.Error(w, string(b), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("requested stats for game: %s", key)
|
log.Printf("requested stats for game: %s", key)
|
||||||
games.RLock()
|
c.Games.RLock()
|
||||||
g, ok := games.m[key]
|
g, ok := c.Games.M[key]
|
||||||
games.RUnlock()
|
c.Games.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
b, _ := json.Marshal(NewFailure("game not found"))
|
b, _ := json.Marshal(NewFailure("game not found"))
|
||||||
http.Error(w, string(b), http.StatusNotFound)
|
http.Error(w, string(b), http.StatusNotFound)
|
||||||
|
@ -143,19 +151,19 @@ func gameStats(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func bw(w http.ResponseWriter, req *http.Request) {
|
func (c *Controller) BW(w http.ResponseWriter, req *http.Request) {
|
||||||
// TODO: wrap this up in something similar to the JsonHandler to verify the
|
// TODO: wrap this up in something similar to the JsonHandler to verify the
|
||||||
// url? Look at gorilla routing?
|
// url? Look at gorilla routing?
|
||||||
key, err := getGameId(req.URL.Path)
|
key, err := c.getGameId(req.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b, _ := json.Marshal(NewFailure(err.Error()))
|
b, _ := json.Marshal(NewFailure(err.Error()))
|
||||||
http.Error(w, string(b), http.StatusBadRequest)
|
http.Error(w, string(b), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("requested bandwidth for game: %s", key)
|
log.Printf("requested bandwidth for game: %s", key)
|
||||||
games.RLock()
|
c.Games.RLock()
|
||||||
g, ok := games.m[key]
|
g, ok := c.Games.M[key]
|
||||||
games.RUnlock()
|
c.Games.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
b, _ := json.Marshal(NewFailure("game not found"))
|
b, _ := json.Marshal(NewFailure("game not found"))
|
||||||
http.Error(w, string(b), http.StatusNotFound)
|
http.Error(w, string(b), http.StatusNotFound)
|
||||||
|
@ -170,16 +178,16 @@ func bw(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopGame(w http.ResponseWriter, req *http.Request) {
|
func (c *Controller) StopGame(w http.ResponseWriter, req *http.Request) {
|
||||||
key, err := getGameId(req.URL.Path)
|
key, err := c.getGameId(req.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b, _ := json.Marshal(NewFailure(err.Error()))
|
b, _ := json.Marshal(NewFailure(err.Error()))
|
||||||
http.Error(w, string(b), http.StatusBadRequest)
|
http.Error(w, string(b), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
games.Lock()
|
c.Games.Lock()
|
||||||
g, ok := games.m[key]
|
g, ok := c.Games.M[key]
|
||||||
defer games.Unlock()
|
defer c.Games.Unlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
http.NotFound(w, req)
|
http.NotFound(w, req)
|
||||||
return
|
return
|
||||||
|
@ -197,15 +205,15 @@ func stopGame(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func killServer(w http.ResponseWriter, req *http.Request) {
|
func (c *Controller) KillServer(w http.ResponseWriter, req *http.Request) {
|
||||||
if *profile != "" {
|
if c.Profile != "" {
|
||||||
log.Print("trying to stop cpu profile")
|
log.Print("trying to stop cpu profile")
|
||||||
pprof.StopCPUProfile()
|
pprof.StopCPUProfile()
|
||||||
log.Print("stopped cpu profile")
|
log.Print("stopped cpu profile")
|
||||||
}
|
}
|
||||||
if *mprofile != "" {
|
if c.Memprofile != "" {
|
||||||
log.Print("trying to dump memory profile")
|
log.Print("trying to dump memory profile")
|
||||||
f, err := os.Create(*mprofile)
|
f, err := os.Create(c.Memprofile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -216,7 +224,7 @@ func killServer(w http.ResponseWriter, req *http.Request) {
|
||||||
log.Fatal("shit got fucked up")
|
log.Fatal("shit got fucked up")
|
||||||
}
|
}
|
||||||
|
|
||||||
func index(w http.ResponseWriter, req *http.Request) {
|
func (c *Controller) Index(w http.ResponseWriter, req *http.Request) {
|
||||||
log.Println("version requested")
|
log.Println("version requested")
|
||||||
version := struct {
|
version := struct {
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
|
@ -230,7 +238,7 @@ func index(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getGameId(path string) (string, error) {
|
func (c *Controller) getGameId(path string) (string, error) {
|
||||||
var err error
|
var err error
|
||||||
trimmed := strings.Trim(path, "/")
|
trimmed := strings.Trim(path, "/")
|
||||||
fullPath := strings.Split(trimmed, "/")
|
fullPath := strings.Split(trimmed, "/")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
@ -7,10 +7,10 @@ import (
|
||||||
type deathmatch struct {
|
type deathmatch struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *deathmatch) setup(gg *game) {
|
func (g *deathmatch) setup(gg *Game) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *deathmatch) gameOver(gg *game) (bool, *GameOver) {
|
func (g *deathmatch) gameOver(gg *Game) (bool, *GameOver) {
|
||||||
over := false
|
over := false
|
||||||
var stats *GameOver
|
var stats *GameOver
|
||||||
|
|
||||||
|
@ -41,5 +41,5 @@ func (g *deathmatch) gameOver(gg *game) (bool, *GameOver) {
|
||||||
return over, stats
|
return over, stats
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *deathmatch) tick(gg *game, payload *Boardstate) {
|
func (g *deathmatch) tick(gg *Game, payload *Boardstate) {
|
||||||
}
|
}
|
||||||
|
|
51
game.go
51
game.go
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
// delete me
|
// delete me
|
||||||
|
|
||||||
|
@ -24,23 +24,23 @@ type Scanner struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type MapLock struct {
|
type MapLock struct {
|
||||||
m map[string]*game
|
M map[string]*Game
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// get is a function that returns a game if found, and creates one if
|
// get is a function that returns a game if found, and creates one if
|
||||||
// not found and force is true. In order to get a hash (rather than use
|
// not found and force is true. In order to get a hash (rather than use
|
||||||
// the string you pass) send "" for id.
|
// the string you pass) send "" for id.
|
||||||
func (ml *MapLock) get(id string) *game {
|
func (ml *MapLock) get(id string) *Game {
|
||||||
ml.Lock()
|
ml.Lock()
|
||||||
g, _ := ml.m[id]
|
g, _ := ml.M[id]
|
||||||
ml.Unlock()
|
ml.Unlock()
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ml *MapLock) add(g *game) {
|
func (ml *MapLock) add(g *Game) {
|
||||||
ml.Lock()
|
ml.Lock()
|
||||||
ml.m[g.id] = g
|
ml.M[g.id] = g
|
||||||
ml.Unlock()
|
ml.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ type GameStats struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type game struct {
|
type Game struct {
|
||||||
id string
|
id string
|
||||||
players map[*player]bool
|
players map[*player]bool
|
||||||
projectiles map[*Projectile]bool
|
projectiles map[*Projectile]bool
|
||||||
|
@ -87,15 +87,18 @@ type game struct {
|
||||||
stats GameStats
|
stats GameStats
|
||||||
mode GameMode
|
mode GameMode
|
||||||
bw *bandwidth.Bandwidth
|
bw *bandwidth.Bandwidth
|
||||||
|
Conf Config
|
||||||
|
Games *MapLock
|
||||||
|
Verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type GameMode interface {
|
type GameMode interface {
|
||||||
setup(g *game)
|
setup(g *Game)
|
||||||
tick(gg *game, payload *Boardstate)
|
tick(gg *Game, payload *Boardstate)
|
||||||
gameOver(gg *game) (bool, *GameOver)
|
gameOver(gg *Game) (bool, *GameOver)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGame(id string, width, height float32, obstacles, tick, maxPoints int, mode string) (*game, error) {
|
func NewGame(id string, width, height float32, obstacles, tick, maxPoints int, mode string) (*Game, error) {
|
||||||
bw, err := bandwidth.NewBandwidth(
|
bw, err := bandwidth.NewBandwidth(
|
||||||
[]int{1, 10, 60},
|
[]int{1, 10, 60},
|
||||||
1*time.Second,
|
1*time.Second,
|
||||||
|
@ -105,7 +108,7 @@ func NewGame(id string, width, height float32, obstacles, tick, maxPoints int, m
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
go bw.Run()
|
go bw.Run()
|
||||||
g := &game{
|
g := &Game{
|
||||||
id: id,
|
id: id,
|
||||||
register: make(chan *player, maxPlayer),
|
register: make(chan *player, maxPlayer),
|
||||||
unregister: make(chan *player, maxPlayer),
|
unregister: make(chan *player, maxPlayer),
|
||||||
|
@ -141,7 +144,7 @@ func NewGame(id string, width, height float32, obstacles, tick, maxPoints int, m
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *game) tick(payload *Boardstate) {
|
func (g *Game) tick(payload *Boardstate) {
|
||||||
g.players_remaining = 0
|
g.players_remaining = 0
|
||||||
payload.Objects = MinifyObstacles(g.obstacles)
|
payload.Objects = MinifyObstacles(g.obstacles)
|
||||||
|
|
||||||
|
@ -196,7 +199,7 @@ func (g *game) tick(payload *Boardstate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *game) sendUpdate(payload *Boardstate) {
|
func (g *Game) sendUpdate(payload *Boardstate) {
|
||||||
// Ensure that the robots are always sent in a consistent order
|
// Ensure that the robots are always sent in a consistent order
|
||||||
sort.Sort(RobotSorter{Robots: payload.OtherRobots})
|
sort.Sort(RobotSorter{Robots: payload.OtherRobots})
|
||||||
sort.Sort(AllRobotSorter{Robots: payload.AllBots})
|
sort.Sort(AllRobotSorter{Robots: payload.AllBots})
|
||||||
|
@ -292,20 +295,20 @@ 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(conf.Tick) * time.Millisecond)
|
ticker := time.NewTicker(time.Duration(g.Conf.Tick) * time.Millisecond)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-g.kill:
|
case <-g.kill:
|
||||||
log.Printf("game %s: received kill signal, dying gracefully", g.id)
|
log.Printf("game %s: received kill signal, dying gracefully", g.id)
|
||||||
close(g.bw.Quit)
|
close(g.bw.Quit)
|
||||||
games.Lock()
|
g.Games.Lock()
|
||||||
for player := range g.players {
|
for player := range g.players {
|
||||||
close(player.send)
|
close(player.send)
|
||||||
}
|
}
|
||||||
delete(games.m, g.id)
|
delete(g.Games.M, g.id)
|
||||||
games.Unlock()
|
g.Games.Unlock()
|
||||||
return
|
return
|
||||||
case p := <-g.register:
|
case p := <-g.register:
|
||||||
g.players[p] = true
|
g.players[p] = true
|
||||||
|
@ -330,7 +333,7 @@ func (g *game) run() {
|
||||||
|
|
||||||
g.turn++
|
g.turn++
|
||||||
payload.Turn = g.turn
|
payload.Turn = g.turn
|
||||||
if *verbose {
|
if g.Verbose {
|
||||||
log.Printf("\033[2JTurn: %v", g.turn)
|
log.Printf("\033[2JTurn: %v", g.turn)
|
||||||
log.Printf("Players: %v", len(g.players))
|
log.Printf("Players: %v", len(g.players))
|
||||||
log.Printf("Projectiles: %v", len(g.projectiles))
|
log.Printf("Projectiles: %v", len(g.projectiles))
|
||||||
|
@ -346,7 +349,7 @@ func (g *game) run() {
|
||||||
g.mode.tick(g, payload)
|
g.mode.tick(g, payload)
|
||||||
|
|
||||||
t1 = time.Now()
|
t1 = time.Now()
|
||||||
if *verbose {
|
if g.Verbose {
|
||||||
log.Printf("Turn Processes %v\n", t1.Sub(t0))
|
log.Printf("Turn Processes %v\n", t1.Sub(t0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,14 +357,14 @@ func (g *game) run() {
|
||||||
g.sendUpdate(payload)
|
g.sendUpdate(payload)
|
||||||
|
|
||||||
t1 = time.Now()
|
t1 = time.Now()
|
||||||
if *verbose {
|
if g.Verbose {
|
||||||
log.Printf("Sent Payload %v\n", t1.Sub(t0))
|
log.Printf("Sent Payload %v\n", t1.Sub(t0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *game) sendGameOver(eg *GameOver) {
|
func (g *Game) sendGameOver(eg *GameOver) {
|
||||||
log.Printf("sending out game over message: %+v", eg)
|
log.Printf("sending out game over message: %+v", eg)
|
||||||
for p := range g.players {
|
for p := range g.players {
|
||||||
p.send <- eg
|
p.send <- eg
|
||||||
|
@ -373,7 +376,7 @@ func (g *game) sendGameOver(eg *GameOver) {
|
||||||
|
|
||||||
// returns a GameParam object popuplated by info from the game. This is
|
// returns a GameParam object popuplated by info from the game. This is
|
||||||
// used during client/server initial negociation.
|
// used during client/server initial negociation.
|
||||||
func (g *game) gameParam() *GameParam {
|
func (g *Game) gameParam() *GameParam {
|
||||||
return &GameParam{
|
return &GameParam{
|
||||||
BoardSize: BoardSize{
|
BoardSize: BoardSize{
|
||||||
Width: g.width,
|
Width: g.width,
|
||||||
|
|
2
id.go
2
id.go
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
8
melee.go
8
melee.go
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
@ -9,15 +9,15 @@ type melee struct {
|
||||||
respawn_timer float64
|
respawn_timer float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *melee) setup(gg *game) {
|
func (g *melee) setup(gg *Game) {
|
||||||
g.respawn_timer = 5000
|
g.respawn_timer = 5000
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *melee) gameOver(gg *game) (bool, *GameOver) {
|
func (g *melee) gameOver(gg *Game) (bool, *GameOver) {
|
||||||
return false, &GameOver{}
|
return false, &GameOver{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *melee) tick(gg *game, payload *Boardstate) {
|
func (g *melee) tick(gg *Game, payload *Boardstate) {
|
||||||
for p := range gg.players {
|
for p := range gg.players {
|
||||||
for _, r := range p.Robots {
|
for _, r := range p.Robots {
|
||||||
_, ok := g.respawn[r]
|
_, ok := g.respawn[r]
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
v "bitbucket.org/hackerbots/vector"
|
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
|
v "bitbucket.org/hackerbots/vector"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Obstacle struct {
|
type Obstacle struct {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
v "bitbucket.org/hackerbots/vector"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
v "bitbucket.org/hackerbots/vector"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Projectile struct {
|
type Projectile struct {
|
||||||
|
@ -13,12 +14,13 @@ type Projectile struct {
|
||||||
Speed float32 `json:"-"`
|
Speed float32 `json:"-"`
|
||||||
Damage int `json:"-"`
|
Damage int `json:"-"`
|
||||||
Owner *Robot `json:"-"`
|
Owner *Robot `json:"-"`
|
||||||
|
Delta float32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Projectile) Tick(g *game) {
|
func (p *Projectile) Tick(g *Game) {
|
||||||
vec := p.MoveTo.Sub(p.Position)
|
vec := p.MoveTo.Sub(p.Position)
|
||||||
v_norm := vec.Normalize()
|
v_norm := vec.Normalize()
|
||||||
v_scaled := v_norm.Scale(p.Speed * delta)
|
v_scaled := v_norm.Scale(p.Speed * p.Delta)
|
||||||
newPos := p.Position.Add(v_scaled)
|
newPos := p.Position.Add(v_scaled)
|
||||||
|
|
||||||
hit_player := false
|
hit_player := false
|
||||||
|
|
22
protocol.go
22
protocol.go
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
@ -143,7 +143,7 @@ func NewFailure(reason string) *Failure {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPlayer(ws *websocket.Conn) {
|
func (c *Controller) AddPlayer(ws *websocket.Conn) {
|
||||||
var gid GameID
|
var gid GameID
|
||||||
err := websocket.JSON.Receive(ws, &gid)
|
err := websocket.JSON.Receive(ws, &gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -151,16 +151,16 @@ func addPlayer(ws *websocket.Conn) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
game := games.get(gid.Id)
|
game := c.Games.get(gid.Id)
|
||||||
if game == nil {
|
if game == nil {
|
||||||
var err error
|
var err error
|
||||||
game, err = NewGame(
|
game, err = NewGame(
|
||||||
gid.Id,
|
gid.Id,
|
||||||
float32(conf.Width),
|
float32(c.Conf.Width),
|
||||||
float32(conf.Height),
|
float32(c.Conf.Height),
|
||||||
conf.Obstacles,
|
c.Conf.Obstacles,
|
||||||
conf.Tick,
|
c.Conf.Tick,
|
||||||
conf.MaxPoints,
|
c.Conf.MaxPoints,
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -169,10 +169,10 @@ func addPlayer(ws *websocket.Conn) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
go game.run()
|
go game.run()
|
||||||
games.add(game)
|
c.Games.add(game)
|
||||||
}
|
}
|
||||||
|
|
||||||
player_id := idg.Hash()
|
player_id := c.Idg.Hash()
|
||||||
err = websocket.JSON.Send(ws, NewPlayerID(player_id))
|
err = websocket.JSON.Send(ws, NewPlayerID(player_id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("game %s: unable to send player_id to player %s", gid.Id, player_id)
|
log.Printf("game %s: unable to send player_id to player %s", gid.Id, player_id)
|
||||||
|
@ -284,7 +284,7 @@ encodingLoops:
|
||||||
convertedStats[name] = dstat
|
convertedStats[name] = dstat
|
||||||
r := Robot{
|
r := Robot{
|
||||||
Stats: dstat,
|
Stats: dstat,
|
||||||
Id: idg.Hash(),
|
Id: c.Idg.Hash(),
|
||||||
Name: name,
|
Name: name,
|
||||||
Health: 10,
|
Health: 10,
|
||||||
Heading: v.Vector2d{1, 0},
|
Heading: v.Vector2d{1, 0},
|
||||||
|
|
37
robot.go
37
robot.go
|
@ -1,10 +1,11 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
v "bitbucket.org/hackerbots/vector"
|
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
|
v "bitbucket.org/hackerbots/vector"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Robot struct {
|
type Robot struct {
|
||||||
|
@ -30,6 +31,8 @@ type Robot struct {
|
||||||
Probe *v.Point2d `json:"probe"`
|
Probe *v.Point2d `json:"probe"`
|
||||||
ProbeResult *Collision `json:"probe_result"`
|
ProbeResult *Collision `json:"probe_result"`
|
||||||
gameStats *BotStats `json:-`
|
gameStats *BotStats `json:-`
|
||||||
|
Delta float32 `json:-`
|
||||||
|
Idg *IdGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
type Collision struct {
|
type Collision struct {
|
||||||
|
@ -172,7 +175,7 @@ type Instruction struct {
|
||||||
|
|
||||||
// returns collision, the intersection point, and the robot with whom r has
|
// returns collision, the intersection point, and the robot with whom r has
|
||||||
// collided, if this happened.
|
// collided, if this happened.
|
||||||
func (r *Robot) checkCollisions(g *game, probe v.Vector2d) (bool, *v.Point2d, *Robot) {
|
func (r *Robot) checkCollisions(g *Game, probe v.Vector2d) (bool, *v.Point2d, *Robot) {
|
||||||
finalCollision := false
|
finalCollision := false
|
||||||
collision := false
|
collision := false
|
||||||
closest := float32(math.Inf(1))
|
closest := float32(math.Inf(1))
|
||||||
|
@ -243,19 +246,19 @@ func (r *Robot) checkCollisions(g *game, probe v.Vector2d) (bool, *v.Point2d, *R
|
||||||
return finalCollision, intersection, finalRobot
|
return finalCollision, intersection, finalRobot
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Robot) Tick(g *game) {
|
func (r *Robot) Tick(g *Game) {
|
||||||
r.Collision = nil
|
r.Collision = nil
|
||||||
r.Hit = false
|
r.Hit = false
|
||||||
r.scan(g)
|
r.scan(g)
|
||||||
|
|
||||||
// Adjust Speed
|
// Adjust Speed
|
||||||
if r.Speed < r.TargetSpeed {
|
if r.Speed < r.TargetSpeed {
|
||||||
r.Speed += (r.Stats.Acceleration * delta)
|
r.Speed += (r.Stats.Acceleration * r.Delta)
|
||||||
if r.Speed > r.TargetSpeed {
|
if r.Speed > r.TargetSpeed {
|
||||||
r.Speed = r.TargetSpeed
|
r.Speed = r.TargetSpeed
|
||||||
}
|
}
|
||||||
} else if float32(math.Abs(float64(r.Speed-r.TargetSpeed))) > v.Epsilon {
|
} else if float32(math.Abs(float64(r.Speed-r.TargetSpeed))) > v.Epsilon {
|
||||||
r.Speed -= (r.Stats.Acceleration * delta)
|
r.Speed -= (r.Stats.Acceleration * r.Delta)
|
||||||
// Cap reverse to 1/2 speed
|
// Cap reverse to 1/2 speed
|
||||||
if r.Speed < (-0.5 * r.TargetSpeed) {
|
if r.Speed < (-0.5 * r.TargetSpeed) {
|
||||||
r.Speed = (-0.5 * r.TargetSpeed)
|
r.Speed = (-0.5 * r.TargetSpeed)
|
||||||
|
@ -292,15 +295,15 @@ func (r *Robot) Tick(g *game) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Max turn radius in this case is in degrees per second
|
// Max turn radius in this case is in degrees per second
|
||||||
if float32(math.Abs(float64(angle))) > (float32(r.Stats.TurnSpeed) * delta) {
|
if float32(math.Abs(float64(angle))) > (float32(r.Stats.TurnSpeed) * r.Delta) {
|
||||||
// New heading should be a little less, take current heading and
|
// New heading should be a little less, take current heading and
|
||||||
// rotate by the max turn radius per frame.
|
// rotate by the max turn radius per frame.
|
||||||
rot := (float32(r.Stats.TurnSpeed) * delta) * v.Deg2rad
|
rot := (float32(r.Stats.TurnSpeed) * r.Delta) * v.Deg2rad
|
||||||
|
|
||||||
new_heading = current_heading.Rotate(rot * float32(dir))
|
new_heading = current_heading.Rotate(rot * float32(dir))
|
||||||
}
|
}
|
||||||
|
|
||||||
move_vector := new_heading.Scale(r.Speed * delta)
|
move_vector := new_heading.Scale(r.Speed * r.Delta)
|
||||||
collision, intersection_point, hit_robot := r.checkCollisions(g, move_vector)
|
collision, intersection_point, hit_robot := r.checkCollisions(g, move_vector)
|
||||||
if collision {
|
if collision {
|
||||||
dmg := int(math.Abs(float64(r.Speed)) / 10.0)
|
dmg := int(math.Abs(float64(r.Speed)) / 10.0)
|
||||||
|
@ -352,7 +355,7 @@ func (r *Robot) Tick(g *game) {
|
||||||
|
|
||||||
// We only self repair when we're stopped
|
// We only self repair when we're stopped
|
||||||
if math.Abs(float64(r.Speed)) < v.Epsilon && r.RepairCounter > 0 {
|
if math.Abs(float64(r.Speed)) < v.Epsilon && r.RepairCounter > 0 {
|
||||||
r.RepairCounter -= delta
|
r.RepairCounter -= r.Delta
|
||||||
if r.RepairCounter < 0 {
|
if r.RepairCounter < 0 {
|
||||||
r.Health += g.repair_hp
|
r.Health += g.repair_hp
|
||||||
if r.Health > r.Stats.Hp {
|
if r.Health > r.Stats.Hp {
|
||||||
|
@ -364,9 +367,9 @@ func (r *Robot) Tick(g *game) {
|
||||||
|
|
||||||
// We are only allowed to scan when we're stopped
|
// We are only allowed to scan when we're stopped
|
||||||
if math.Abs(float64(r.Speed)) < v.Epsilon && r.ActiveScan {
|
if math.Abs(float64(r.Speed)) < v.Epsilon && r.ActiveScan {
|
||||||
r.ScanCounter += delta * float32(r.Stats.ScannerRadius) * 0.1
|
r.ScanCounter += r.Delta * float32(r.Stats.ScannerRadius) * 0.1
|
||||||
} else if r.ScanCounter > 0 {
|
} else if r.ScanCounter > 0 {
|
||||||
r.ScanCounter -= delta * float32(r.Stats.ScannerRadius) * 0.05
|
r.ScanCounter -= r.Delta * float32(r.Stats.ScannerRadius) * 0.05
|
||||||
if r.ScanCounter <= 0 {
|
if r.ScanCounter <= 0 {
|
||||||
r.ScanCounter = 0
|
r.ScanCounter = 0
|
||||||
}
|
}
|
||||||
|
@ -394,7 +397,7 @@ func (r *Robot) Tick(g *game) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Robot) scan(g *game) {
|
func (r *Robot) scan(g *Game) {
|
||||||
r.Scanners = r.Scanners[:0]
|
r.Scanners = r.Scanners[:0]
|
||||||
for player := range g.players {
|
for player := range g.players {
|
||||||
for _, bot := range player.Robots {
|
for _, bot := range player.Robots {
|
||||||
|
@ -440,9 +443,9 @@ func (r *Robot) scan(g *game) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Robot) fire(g *game) *Projectile {
|
func (r *Robot) fire(g *Game) *Projectile {
|
||||||
// Throttle the fire rate
|
// Throttle the fire rate
|
||||||
time_since_fired := (float32(g.turn) * (delta * 1000)) - (float32(r.LastFired) * (delta * 1000))
|
time_since_fired := (float32(g.turn) * (r.Delta * 1000)) - (float32(r.LastFired) * (r.Delta * 1000))
|
||||||
if time_since_fired < float32(r.Stats.FireRate) {
|
if time_since_fired < float32(r.Stats.FireRate) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -451,7 +454,7 @@ func (r *Robot) fire(g *game) *Projectile {
|
||||||
r.gameStats.Shots++
|
r.gameStats.Shots++
|
||||||
|
|
||||||
return &Projectile{
|
return &Projectile{
|
||||||
Id: idg.Hash(),
|
Id: r.Idg.Hash(),
|
||||||
Position: r.Position,
|
Position: r.Position,
|
||||||
MoveTo: *r.FireAt,
|
MoveTo: *r.FireAt,
|
||||||
Damage: r.Stats.WeaponDamage,
|
Damage: r.Stats.WeaponDamage,
|
||||||
|
@ -461,7 +464,7 @@ func (r *Robot) fire(g *game) *Projectile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Robot) reset(g *game) {
|
func (r *Robot) reset(g *Game) {
|
||||||
for {
|
for {
|
||||||
start_pos := v.Point2d{
|
start_pos := v.Point2d{
|
||||||
X: rand.Float32() * float32(g.width),
|
X: rand.Float32() * float32(g.width),
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
v "bitbucket.org/hackerbots/vector"
|
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
v "bitbucket.org/hackerbots/vector"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package botserv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
v "bitbucket.org/hackerbots/vector"
|
v "bitbucket.org/hackerbots/vector"
|
||||||
|
|
Loading…
Reference in New Issue