diff --git a/commands.go b/commands.go index bbf50d3..b1c1441 100644 --- a/commands.go +++ b/commands.go @@ -13,13 +13,6 @@ type Command struct { handler func(*Connection, ...string) } -// var scanCommand = &Command{ -// name: "scan", -// help: "scans for resources", -// handler: func(conn *Connection, args ...string) { -// }, -// } - var infoCommand = &Command{ name: "info", help: "gives you some info about your current position", @@ -80,18 +73,24 @@ var commandsCommand = &Command{ }, } -// var superscanCommand = &Command{ -// name: "super-scan", -// help: "super duper scan", -// handler: func(conn *Connection, args ...string) { -// for id, _ := range index { -// if id == conn.System().id { -// continue -// } -// -// } -// }, -// } +var scanCommand = &Command{ + name: "scan", + help: "super duper scan", + handler: func(conn *Connection, args ...string) { + system := conn.System() + log_info("scan sent from %s", system.name) + for id, _ := range index { + if id == system.id { + continue + } + delay := system.TimeTo(index[id]) + id2 := id + After(delay, func() { + scanSystem(id2, system.id) + }) + } + }, +} func isCommand(name string) bool { _, ok := commandRegistry[name] @@ -117,4 +116,5 @@ func init() { registerCommand(helpCommand) registerCommand(infoCommand) registerCommand(nearbyCommand) + registerCommand(scanCommand) } diff --git a/main.go b/main.go index 588b22f..c41162c 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,6 @@ import ( "net" "os" "strings" - "sync" "time" ) @@ -35,8 +34,6 @@ func bail(status int, template string, args ...interface{}) { } func handleConnection(conn *Connection) { - var mu sync.Mutex - defer conn.Close() conn.Login() @@ -69,20 +66,6 @@ func handleConnection(conn *Connection) { } switch parts[0] { - case "scan": - for _, otherSystem := range index { - if otherSystem.name == system.name { - continue - } - go func(p *System) { - dist := system.DistanceTo(p) - delay := time.Duration(int64(dist * 100000000)) - time.Sleep(delay) - mu.Lock() - fmt.Fprintf(conn, "PONG from system %s (%v)\n", p.name, delay) - mu.Unlock() - }(otherSystem) - } case "broadcast": msg := strings.Join(parts[1:], " ") log_info("player %s is broadcasting message %s", conn.PlayerName(), msg) @@ -101,18 +84,6 @@ func handleConnection(conn *Connection) { }) }(otherSystem) } - // case "nearby": - // neighbors, err := system.Nearby(25) - // fmt.Fprintf(conn, "fetching nearby star systems\n") - // if err != nil { - // log_error("%v", err) - // break - // } - // fmt.Fprintf(conn, "found %d nearby systems\n", len(neighbors)) - // for _, neighbor := range neighbors { - // other := index[neighbor.id] - // fmt.Fprintf(conn, "%s: %v\n", other.name, neighbor.distance) - // } case "quit": return default: @@ -130,6 +101,7 @@ func main() { if err != nil { bail(E_No_Port, "unable to start server: %v", err) } + go RunQueue() for { conn, err := listener.Accept() if err != nil { diff --git a/system.go b/system.go index 6253c2d..8f87435 100644 --- a/system.go +++ b/system.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "math/rand" + "time" ) var ( @@ -65,6 +66,10 @@ func (s *System) DistanceTo(other *System) float64 { return dist3d(s.x, s.y, s.z, other.x, other.y, other.z) } +func (s *System) TimeTo(other *System) time.Duration { + return time.Duration(int64(s.DistanceTo(other) * 100000000)) +} + func (e System) String() string { return fmt.Sprintf("", e.name, e.x, e.y, e.z, e.planets) } @@ -144,3 +149,20 @@ func randomSystem() (*System, error) { planet := index[pick] return planet, nil } + +func scanSystem(id int, reply int) { + system := index[id] + source := index[reply] + delay := system.TimeTo(source) + log_info("scan hit %s from %s after traveling for %v", system.name, source.name, delay) + After(delay, func() { + deliverReply(source.id, system.id) + }) +} + +func deliverReply(id int, echo int) { + system := index[id] + source := index[echo] + delay := system.TimeTo(source) + log_info("echo received at %s reflected from %s after traveling for %v", system.name, source.name, delay) +} diff --git a/work.go b/work.go new file mode 100644 index 0000000..dc28e4a --- /dev/null +++ b/work.go @@ -0,0 +1,74 @@ +package main + +import ( + "container/heap" + "time" +) + +var queue = make(Queue, 0, 32) + +type Future struct { + ts time.Time + index int + work func() +} + +type Queue []*Future + +func (q Queue) Len() int { return len(q) } + +func (q Queue) Less(i, j int) bool { + return q[i].ts.Before(q[j].ts) +} + +func (q Queue) Swap(i, j int) { + q[i], q[j] = q[j], q[i] + q[i].index = j + q[j].index = i +} + +func (q *Queue) Push(v interface{}) { + n := len(*q) + future := v.(*Future) + future.index = n + *q = append(*q, future) +} + +func (q *Queue) Pop() interface{} { + old := *q + n := len(old) + future := old[n-1] + future.index = -1 + *q = old[0 : n-1] + return future +} + +func At(ts time.Time, work func()) { + heap.Push(&queue, &Future{ts: ts, work: work}) +} + +func After(delay time.Duration, work func()) { + heap.Push(&queue, &Future{ts: time.Now().Add(delay), work: work}) +} + +func RunQueue() { + defer log_info("Queue runner done.") + heap.Init(&queue) + for { + if len(queue) == 0 { + time.Sleep(100 * time.Microsecond) + continue + } + future, ok := heap.Pop(&queue).(*Future) + if !ok { + log_error("there's shit on the work heap") + continue + } + log_info("we have a work item with delay %v", time.Since(future.ts)) + if future.ts.After(time.Now()) { + time.Sleep(future.ts.Sub(time.Now())) + } + log_info("performing work") + future.work() + } +}