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
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
botserv
|
||||
bserv/bserv
|
||||
*.swp
|
||||
tags
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
"bitbucket.org/hackerbots/botserv"
|
||||
|
||||
"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 idg *IdGenerator
|
||||
var conf Config
|
||||
|
||||
// This is the main, global collection of games
|
||||
var games MapLock
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
|
||||
log.Printf("Starting Server...")
|
||||
@ -49,10 +44,7 @@ func main() {
|
||||
log.Println("serving profile info at http://localhost:8667/debug/pprof/")
|
||||
}
|
||||
|
||||
games = MapLock{m: make(map[string]*game)}
|
||||
idg = NewIdGenerator()
|
||||
|
||||
conf, err = loadConfig(*config)
|
||||
conf, err := botserv.LoadConfig(*config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -61,14 +53,24 @@ func main() {
|
||||
|
||||
sm := http.NewServeMux()
|
||||
|
||||
sm.Handle("/", JsonHandler(index))
|
||||
sm.Handle("/ws/", websocket.Handler(addPlayer))
|
||||
sm.Handle("/game/start/", JsonHandler(startGame))
|
||||
sm.Handle("/game/list/", JsonHandler(listGames))
|
||||
sm.Handle("/game/stats/", JsonHandler(gameStats))
|
||||
sm.Handle("/game/bw/", JsonHandler(bw))
|
||||
sm.Handle("/game/stop/", JsonHandler(stopGame))
|
||||
sm.HandleFunc("/fuck/shit/up/", killServer)
|
||||
c := botserv.Controller{
|
||||
Idg: botserv.NewIdGenerator(),
|
||||
Conf: conf,
|
||||
Games: botserv.MapLock{
|
||||
M: make(map[string]*botserv.Game),
|
||||
},
|
||||
Memprofile: *mprofile,
|
||||
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)
|
||||
if err != nil {
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -31,7 +31,7 @@ const (
|
||||
DEFAULT_MODE = "deathmatch"
|
||||
)
|
||||
|
||||
func loadConfig(filename string) (Config, error) {
|
||||
func LoadConfig(filename string) (Config, error) {
|
||||
c := Config{
|
||||
Tick: TICK,
|
||||
Timescale: TIMESCALE,
|
||||
|
74
control.go
74
control.go
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -19,13 +19,21 @@ func (h JsonHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
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")
|
||||
|
||||
requested_game_name := idg.Hash()
|
||||
width, height := float32(conf.Width), float32(conf.Height)
|
||||
requested_game_name := c.Idg.Hash()
|
||||
width, height := float32(c.Conf.Width), float32(c.Conf.Height)
|
||||
obstacles := 0
|
||||
maxPoints := conf.MaxPoints
|
||||
maxPoints := c.Conf.MaxPoints
|
||||
mode := "deathmatch"
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
g := games.get(requested_game_name)
|
||||
g := c.Games.get(requested_game_name)
|
||||
if g == nil {
|
||||
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 {
|
||||
log.Printf("problem creating game: %s: %s", requested_game_name, err)
|
||||
b, _ := json.Marshal(NewFailure("game creation failure"))
|
||||
@ -66,7 +74,7 @@ func startGame(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
go g.run()
|
||||
games.add(g)
|
||||
c.Games.add(g)
|
||||
} else {
|
||||
log.Printf("Game '%s' already exists: %p", requested_game_name, g)
|
||||
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")
|
||||
games.RLock()
|
||||
defer games.RUnlock()
|
||||
c.Games.RLock()
|
||||
defer c.Games.RUnlock()
|
||||
type pout struct {
|
||||
Name string `json:"name"`
|
||||
Id string `json:"id"`
|
||||
@ -97,7 +105,7 @@ func listGames(w http.ResponseWriter, req *http.Request) {
|
||||
Players []pout `json:"players"`
|
||||
}
|
||||
ids := make([]gl, 0)
|
||||
for id, g := range games.m {
|
||||
for id, g := range c.Games.M {
|
||||
players := make([]pout, 0)
|
||||
// TODO - players instead of robots?
|
||||
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
|
||||
// url? Look at gorilla routing?
|
||||
key, err := getGameId(req.URL.Path)
|
||||
key, err := c.getGameId(req.URL.Path)
|
||||
if err != nil {
|
||||
b, _ := json.Marshal(NewFailure(err.Error()))
|
||||
http.Error(w, string(b), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
log.Printf("requested stats for game: %s", key)
|
||||
games.RLock()
|
||||
g, ok := games.m[key]
|
||||
games.RUnlock()
|
||||
c.Games.RLock()
|
||||
g, ok := c.Games.M[key]
|
||||
c.Games.RUnlock()
|
||||
if !ok {
|
||||
b, _ := json.Marshal(NewFailure("game not found"))
|
||||
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
|
||||
// url? Look at gorilla routing?
|
||||
key, err := getGameId(req.URL.Path)
|
||||
key, err := c.getGameId(req.URL.Path)
|
||||
if err != nil {
|
||||
b, _ := json.Marshal(NewFailure(err.Error()))
|
||||
http.Error(w, string(b), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
log.Printf("requested bandwidth for game: %s", key)
|
||||
games.RLock()
|
||||
g, ok := games.m[key]
|
||||
games.RUnlock()
|
||||
c.Games.RLock()
|
||||
g, ok := c.Games.M[key]
|
||||
c.Games.RUnlock()
|
||||
if !ok {
|
||||
b, _ := json.Marshal(NewFailure("game not found"))
|
||||
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) {
|
||||
key, err := getGameId(req.URL.Path)
|
||||
func (c *Controller) StopGame(w http.ResponseWriter, req *http.Request) {
|
||||
key, err := c.getGameId(req.URL.Path)
|
||||
if err != nil {
|
||||
b, _ := json.Marshal(NewFailure(err.Error()))
|
||||
http.Error(w, string(b), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
games.Lock()
|
||||
g, ok := games.m[key]
|
||||
defer games.Unlock()
|
||||
c.Games.Lock()
|
||||
g, ok := c.Games.M[key]
|
||||
defer c.Games.Unlock()
|
||||
if !ok {
|
||||
http.NotFound(w, req)
|
||||
return
|
||||
@ -197,15 +205,15 @@ func stopGame(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func killServer(w http.ResponseWriter, req *http.Request) {
|
||||
if *profile != "" {
|
||||
func (c *Controller) KillServer(w http.ResponseWriter, req *http.Request) {
|
||||
if c.Profile != "" {
|
||||
log.Print("trying to stop cpu profile")
|
||||
pprof.StopCPUProfile()
|
||||
log.Print("stopped cpu profile")
|
||||
}
|
||||
if *mprofile != "" {
|
||||
if c.Memprofile != "" {
|
||||
log.Print("trying to dump memory profile")
|
||||
f, err := os.Create(*mprofile)
|
||||
f, err := os.Create(c.Memprofile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -216,7 +224,7 @@ func killServer(w http.ResponseWriter, req *http.Request) {
|
||||
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")
|
||||
version := struct {
|
||||
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
|
||||
trimmed := strings.Trim(path, "/")
|
||||
fullPath := strings.Split(trimmed, "/")
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
"log"
|
||||
@ -7,10 +7,10 @@ import (
|
||||
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
|
||||
var stats *GameOver
|
||||
|
||||
@ -41,5 +41,5 @@ func (g *deathmatch) gameOver(gg *game) (bool, *GameOver) {
|
||||
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
|
||||
|
||||
@ -24,23 +24,23 @@ type Scanner struct {
|
||||
}
|
||||
|
||||
type MapLock struct {
|
||||
m map[string]*game
|
||||
M map[string]*Game
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// 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
|
||||
// the string you pass) send "" for id.
|
||||
func (ml *MapLock) get(id string) *game {
|
||||
func (ml *MapLock) get(id string) *Game {
|
||||
ml.Lock()
|
||||
g, _ := ml.m[id]
|
||||
g, _ := ml.M[id]
|
||||
ml.Unlock()
|
||||
return g
|
||||
}
|
||||
|
||||
func (ml *MapLock) add(g *game) {
|
||||
func (ml *MapLock) add(g *Game) {
|
||||
ml.Lock()
|
||||
ml.m[g.id] = g
|
||||
ml.M[g.id] = g
|
||||
ml.Unlock()
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ type GameStats struct {
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
type game struct {
|
||||
type Game struct {
|
||||
id string
|
||||
players map[*player]bool
|
||||
projectiles map[*Projectile]bool
|
||||
@ -87,15 +87,18 @@ type game struct {
|
||||
stats GameStats
|
||||
mode GameMode
|
||||
bw *bandwidth.Bandwidth
|
||||
Conf Config
|
||||
Games *MapLock
|
||||
Verbose bool
|
||||
}
|
||||
|
||||
type GameMode interface {
|
||||
setup(g *game)
|
||||
tick(gg *game, payload *Boardstate)
|
||||
gameOver(gg *game) (bool, *GameOver)
|
||||
setup(g *Game)
|
||||
tick(gg *Game, payload *Boardstate)
|
||||
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(
|
||||
[]int{1, 10, 60},
|
||||
1*time.Second,
|
||||
@ -105,7 +108,7 @@ func NewGame(id string, width, height float32, obstacles, tick, maxPoints int, m
|
||||
return nil, err
|
||||
}
|
||||
go bw.Run()
|
||||
g := &game{
|
||||
g := &Game{
|
||||
id: id,
|
||||
register: 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
|
||||
}
|
||||
|
||||
func (g *game) tick(payload *Boardstate) {
|
||||
func (g *Game) tick(payload *Boardstate) {
|
||||
g.players_remaining = 0
|
||||
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
|
||||
sort.Sort(RobotSorter{Robots: payload.OtherRobots})
|
||||
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
|
||||
ticker := time.NewTicker(time.Duration(conf.Tick) * time.Millisecond)
|
||||
ticker := time.NewTicker(time.Duration(g.Conf.Tick) * time.Millisecond)
|
||||
for {
|
||||
select {
|
||||
case <-g.kill:
|
||||
log.Printf("game %s: received kill signal, dying gracefully", g.id)
|
||||
close(g.bw.Quit)
|
||||
games.Lock()
|
||||
g.Games.Lock()
|
||||
for player := range g.players {
|
||||
close(player.send)
|
||||
}
|
||||
delete(games.m, g.id)
|
||||
games.Unlock()
|
||||
delete(g.Games.M, g.id)
|
||||
g.Games.Unlock()
|
||||
return
|
||||
case p := <-g.register:
|
||||
g.players[p] = true
|
||||
@ -330,7 +333,7 @@ func (g *game) run() {
|
||||
|
||||
g.turn++
|
||||
payload.Turn = g.turn
|
||||
if *verbose {
|
||||
if g.Verbose {
|
||||
log.Printf("\033[2JTurn: %v", g.turn)
|
||||
log.Printf("Players: %v", len(g.players))
|
||||
log.Printf("Projectiles: %v", len(g.projectiles))
|
||||
@ -346,7 +349,7 @@ func (g *game) run() {
|
||||
g.mode.tick(g, payload)
|
||||
|
||||
t1 = time.Now()
|
||||
if *verbose {
|
||||
if g.Verbose {
|
||||
log.Printf("Turn Processes %v\n", t1.Sub(t0))
|
||||
}
|
||||
|
||||
@ -354,14 +357,14 @@ func (g *game) run() {
|
||||
g.sendUpdate(payload)
|
||||
|
||||
t1 = time.Now()
|
||||
if *verbose {
|
||||
if g.Verbose {
|
||||
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)
|
||||
for p := range g.players {
|
||||
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
|
||||
// used during client/server initial negociation.
|
||||
func (g *game) gameParam() *GameParam {
|
||||
func (g *Game) gameParam() *GameParam {
|
||||
return &GameParam{
|
||||
BoardSize: BoardSize{
|
||||
Width: g.width,
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
8
melee.go
8
melee.go
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
"log"
|
||||
@ -9,15 +9,15 @@ type melee struct {
|
||||
respawn_timer float64
|
||||
}
|
||||
|
||||
func (g *melee) setup(gg *game) {
|
||||
func (g *melee) setup(gg *Game) {
|
||||
g.respawn_timer = 5000
|
||||
}
|
||||
|
||||
func (g *melee) gameOver(gg *game) (bool, *GameOver) {
|
||||
func (g *melee) gameOver(gg *Game) (bool, *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 _, r := range p.Robots {
|
||||
_, ok := g.respawn[r]
|
||||
|
@ -1,9 +1,10 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
v "bitbucket.org/hackerbots/vector"
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
v "bitbucket.org/hackerbots/vector"
|
||||
)
|
||||
|
||||
type Obstacle struct {
|
||||
|
@ -1,8 +1,9 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
v "bitbucket.org/hackerbots/vector"
|
||||
"log"
|
||||
|
||||
v "bitbucket.org/hackerbots/vector"
|
||||
)
|
||||
|
||||
type Projectile struct {
|
||||
@ -13,12 +14,13 @@ type Projectile struct {
|
||||
Speed float32 `json:"-"`
|
||||
Damage int `json:"-"`
|
||||
Owner *Robot `json:"-"`
|
||||
Delta float32
|
||||
}
|
||||
|
||||
func (p *Projectile) Tick(g *game) {
|
||||
func (p *Projectile) Tick(g *Game) {
|
||||
vec := p.MoveTo.Sub(p.Position)
|
||||
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)
|
||||
|
||||
hit_player := false
|
||||
|
22
protocol.go
22
protocol.go
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
"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
|
||||
err := websocket.JSON.Receive(ws, &gid)
|
||||
if err != nil {
|
||||
@ -151,16 +151,16 @@ func addPlayer(ws *websocket.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
game := games.get(gid.Id)
|
||||
game := c.Games.get(gid.Id)
|
||||
if game == nil {
|
||||
var err error
|
||||
game, err = NewGame(
|
||||
gid.Id,
|
||||
float32(conf.Width),
|
||||
float32(conf.Height),
|
||||
conf.Obstacles,
|
||||
conf.Tick,
|
||||
conf.MaxPoints,
|
||||
float32(c.Conf.Width),
|
||||
float32(c.Conf.Height),
|
||||
c.Conf.Obstacles,
|
||||
c.Conf.Tick,
|
||||
c.Conf.MaxPoints,
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
@ -169,10 +169,10 @@ func addPlayer(ws *websocket.Conn) {
|
||||
return
|
||||
}
|
||||
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))
|
||||
if err != nil {
|
||||
log.Printf("game %s: unable to send player_id to player %s", gid.Id, player_id)
|
||||
@ -284,7 +284,7 @@ encodingLoops:
|
||||
convertedStats[name] = dstat
|
||||
r := Robot{
|
||||
Stats: dstat,
|
||||
Id: idg.Hash(),
|
||||
Id: c.Idg.Hash(),
|
||||
Name: name,
|
||||
Health: 10,
|
||||
Heading: v.Vector2d{1, 0},
|
||||
|
37
robot.go
37
robot.go
@ -1,10 +1,11 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
v "bitbucket.org/hackerbots/vector"
|
||||
"log"
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
v "bitbucket.org/hackerbots/vector"
|
||||
)
|
||||
|
||||
type Robot struct {
|
||||
@ -30,6 +31,8 @@ type Robot struct {
|
||||
Probe *v.Point2d `json:"probe"`
|
||||
ProbeResult *Collision `json:"probe_result"`
|
||||
gameStats *BotStats `json:-`
|
||||
Delta float32 `json:-`
|
||||
Idg *IdGenerator
|
||||
}
|
||||
|
||||
type Collision struct {
|
||||
@ -172,7 +175,7 @@ type Instruction struct {
|
||||
|
||||
// returns collision, the intersection point, and the robot with whom r has
|
||||
// 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
|
||||
collision := false
|
||||
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
|
||||
}
|
||||
|
||||
func (r *Robot) Tick(g *game) {
|
||||
func (r *Robot) Tick(g *Game) {
|
||||
r.Collision = nil
|
||||
r.Hit = false
|
||||
r.scan(g)
|
||||
|
||||
// Adjust Speed
|
||||
if r.Speed < r.TargetSpeed {
|
||||
r.Speed += (r.Stats.Acceleration * delta)
|
||||
r.Speed += (r.Stats.Acceleration * r.Delta)
|
||||
if r.Speed > r.TargetSpeed {
|
||||
r.Speed = r.TargetSpeed
|
||||
}
|
||||
} 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
|
||||
if 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
|
||||
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
|
||||
// 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))
|
||||
}
|
||||
|
||||
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)
|
||||
if collision {
|
||||
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
|
||||
if math.Abs(float64(r.Speed)) < v.Epsilon && r.RepairCounter > 0 {
|
||||
r.RepairCounter -= delta
|
||||
r.RepairCounter -= r.Delta
|
||||
if r.RepairCounter < 0 {
|
||||
r.Health += g.repair_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
|
||||
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 {
|
||||
r.ScanCounter -= delta * float32(r.Stats.ScannerRadius) * 0.05
|
||||
r.ScanCounter -= r.Delta * float32(r.Stats.ScannerRadius) * 0.05
|
||||
if 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]
|
||||
for player := range g.players {
|
||||
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
|
||||
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) {
|
||||
return nil
|
||||
}
|
||||
@ -451,7 +454,7 @@ func (r *Robot) fire(g *game) *Projectile {
|
||||
r.gameStats.Shots++
|
||||
|
||||
return &Projectile{
|
||||
Id: idg.Hash(),
|
||||
Id: r.Idg.Hash(),
|
||||
Position: r.Position,
|
||||
MoveTo: *r.FireAt,
|
||||
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 {
|
||||
start_pos := v.Point2d{
|
||||
X: rand.Float32() * float32(g.width),
|
||||
|
@ -1,10 +1,11 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
v "bitbucket.org/hackerbots/vector"
|
||||
"log"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
v "bitbucket.org/hackerbots/vector"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package botserv
|
||||
|
||||
import (
|
||||
v "bitbucket.org/hackerbots/vector"
|
||||
|
Loading…
Reference in New Issue
Block a user