Stephen McQuay
9a4b76f610
This finalizes the work on getting the server to support multiple encodings for players and spectators.
201 lines
3.7 KiB
Go
201 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/gob"
|
|
"encoding/json"
|
|
"log"
|
|
|
|
"bitbucket.org/smcquay/bandwidth"
|
|
"code.google.com/p/go.net/websocket"
|
|
)
|
|
|
|
const maxMessageSize = 1024
|
|
|
|
type encoder interface {
|
|
Encode(v interface{}) error
|
|
}
|
|
|
|
type decoder interface {
|
|
Decode(v interface{}) error
|
|
}
|
|
|
|
type streamCounter struct {
|
|
ws *websocket.Conn
|
|
bw *bandwidth.Bandwidth
|
|
}
|
|
|
|
func (sc *streamCounter) Read(p []byte) (n int, err error) {
|
|
n, err = sc.ws.Read(p)
|
|
sc.bw.AddRx <- n
|
|
return n, err
|
|
}
|
|
|
|
func (sc *streamCounter) Write(p []byte) (n int, err error) {
|
|
n, err = sc.ws.Write(p)
|
|
sc.bw.AddTx <- n
|
|
return n, err
|
|
}
|
|
|
|
func (sc *streamCounter) Close() error {
|
|
return sc.ws.Close()
|
|
}
|
|
|
|
type protoTalker struct {
|
|
enc encoder
|
|
dec decoder
|
|
counter *streamCounter
|
|
send chan Message
|
|
Id string
|
|
}
|
|
|
|
func NewProtoTalker(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth, encoding string) *protoTalker {
|
|
var enc encoder
|
|
var dec decoder
|
|
comptroller := &streamCounter{
|
|
ws: ws,
|
|
bw: bw,
|
|
}
|
|
if encoding == "json" {
|
|
enc = json.NewEncoder(comptroller)
|
|
dec = json.NewDecoder(comptroller)
|
|
} else {
|
|
enc = gob.NewEncoder(comptroller)
|
|
dec = gob.NewDecoder(comptroller)
|
|
}
|
|
return &protoTalker{
|
|
send: make(chan Message, 16),
|
|
enc: enc,
|
|
dec: dec,
|
|
counter: comptroller,
|
|
Id: id,
|
|
}
|
|
}
|
|
|
|
func (pt *protoTalker) sender() {
|
|
log.Printf("%s: client launched", pt.Id)
|
|
for things := range pt.send {
|
|
err := pt.enc.Encode(things)
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
pt.counter.Close()
|
|
log.Printf("%s: spectator sender close", pt.Id)
|
|
}
|
|
|
|
type player struct {
|
|
Robots []*Robot
|
|
Instruction Instruction
|
|
protoTalker
|
|
}
|
|
|
|
func NewPlayer(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth, encoding string) *player {
|
|
return &player{
|
|
Robots: []*Robot{},
|
|
protoTalker: *NewProtoTalker(id, ws, bw, encoding),
|
|
}
|
|
}
|
|
|
|
func (p *player) recv() {
|
|
for {
|
|
var msgs map[string]Instruction
|
|
err := p.dec.Decode(&msgs)
|
|
if err != nil {
|
|
log.Printf("%s: %s", p.Id, err)
|
|
break
|
|
}
|
|
|
|
for _, r := range p.Robots {
|
|
|
|
msg, ok := msgs[r.Id]
|
|
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
if msg.Repair != nil && *msg.Repair == true {
|
|
r.ActiveScan = false
|
|
r.TargetSpeed = 0
|
|
r.FireAt = nil
|
|
r.MoveTo = nil
|
|
if r.RepairCounter <= 0 {
|
|
r.RepairCounter = 3.0
|
|
}
|
|
} else if msg.Scan != nil && *msg.Scan == true {
|
|
r.RepairCounter = 0
|
|
r.TargetSpeed = 0
|
|
r.FireAt = nil
|
|
r.MoveTo = nil
|
|
r.ActiveScan = true
|
|
} else {
|
|
r.RepairCounter = 0
|
|
r.ActiveScan = false
|
|
|
|
// Reapiring halts all other activity
|
|
if msg.MoveTo != nil {
|
|
r.MoveTo = msg.MoveTo
|
|
}
|
|
if msg.Heading != nil {
|
|
r.DesiredHeading = msg.Heading
|
|
}
|
|
if msg.FireAt != nil {
|
|
r.FireAt = msg.FireAt
|
|
} else {
|
|
r.FireAt = nil
|
|
}
|
|
|
|
if msg.TargetSpeed != nil {
|
|
r.TargetSpeed = float32(*msg.TargetSpeed)
|
|
} else {
|
|
r.TargetSpeed = r.Stats.Speed
|
|
}
|
|
}
|
|
|
|
if msg.Probe != nil {
|
|
r.Probe = msg.Probe
|
|
r.ProbeResult = nil
|
|
} else {
|
|
r.Probe = nil
|
|
}
|
|
|
|
if msg.Message != nil {
|
|
r.Message = *msg.Message
|
|
}
|
|
}
|
|
}
|
|
|
|
log.Printf("%s: recv close", p.Id)
|
|
p.counter.Close()
|
|
}
|
|
|
|
type Spectator struct {
|
|
protoTalker
|
|
}
|
|
|
|
func NewSpectator(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth, encoding string) *Spectator {
|
|
return &Spectator{
|
|
protoTalker: *NewProtoTalker(id, ws, bw, encoding),
|
|
}
|
|
}
|
|
|
|
func (s *Spectator) recv() {
|
|
for {
|
|
var msgs interface{}
|
|
err := s.dec.Decode(&msgs)
|
|
if err != nil {
|
|
log.Printf("%s: %s", s.Id, err)
|
|
break
|
|
}
|
|
|
|
// After the first bit of handshaking, the rest of the messages should
|
|
// only be "{}" for spectators, and the following could hold true:
|
|
//
|
|
// if string(buff[:n]) != "{}" {
|
|
// log.Printf("protocol breach!!")
|
|
// break
|
|
// }
|
|
}
|
|
log.Printf("%s: recv close", s.Id)
|
|
s.counter.Close()
|
|
}
|