You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
2.1 KiB
Go
103 lines
2.1 KiB
Go
4 years ago
|
package sim
|
||
|
|
||
4 years ago
|
import (
|
||
|
"time"
|
||
|
|
||
4 years ago
|
"github.com/jordanorelli/astro-domu/internal/wire"
|
||
4 years ago
|
"github.com/jordanorelli/blammo"
|
||
|
)
|
||
|
|
||
|
// World is the entire simulated world. A world consists of many rooms.
|
||
4 years ago
|
type World struct {
|
||
4 years ago
|
*blammo.Log
|
||
4 years ago
|
Inbox chan Request
|
||
|
|
||
4 years ago
|
rooms []room
|
||
|
done chan bool
|
||
|
lastEntityID int
|
||
4 years ago
|
players map[string]*player
|
||
4 years ago
|
}
|
||
|
|
||
|
func NewWorld(log *blammo.Log) *World {
|
||
4 years ago
|
foyer := room{
|
||
4 years ago
|
Log: log.Child("foyer"),
|
||
|
name: "foyer",
|
||
|
origin: point{0, 0},
|
||
|
width: 10,
|
||
|
height: 10,
|
||
|
tiles: make([]tile, 100),
|
||
|
players: make(map[string]*player),
|
||
4 years ago
|
}
|
||
4 years ago
|
foyer.tiles[55].here = &Entity{
|
||
|
ID: 777,
|
||
|
Position: [2]int{5, 5},
|
||
|
Glyph: 'd',
|
||
|
behavior: doNothing{},
|
||
|
}
|
||
4 years ago
|
return &World{
|
||
4 years ago
|
Log: log,
|
||
|
rooms: []room{foyer},
|
||
|
done: make(chan bool),
|
||
|
Inbox: make(chan Request),
|
||
|
players: make(map[string]*player),
|
||
4 years ago
|
}
|
||
|
}
|
||
|
|
||
|
func (w *World) Run(hz int) {
|
||
4 years ago
|
defer w.Info("simulation has exited run loop")
|
||
|
|
||
4 years ago
|
period := time.Second / time.Duration(hz)
|
||
|
w.Info("starting world with a tick rate of %dhz, frame duration of %v", hz, period)
|
||
|
ticker := time.NewTicker(period)
|
||
|
lastTick := time.Now()
|
||
4 years ago
|
|
||
4 years ago
|
for {
|
||
|
select {
|
||
4 years ago
|
case req := <-w.Inbox:
|
||
|
w.Info("read from inbox: %v", req)
|
||
4 years ago
|
|
||
4 years ago
|
if req.From == "" {
|
||
4 years ago
|
w.Error("request has no from: %v", req)
|
||
4 years ago
|
break
|
||
|
}
|
||
4 years ago
|
|
||
|
if spawn, ok := req.Wants.(*SpawnPlayer); ok {
|
||
|
if _, ok := w.players[req.From]; ok {
|
||
|
spawn.Outbox <- wire.ErrorResponse(req.Seq, "a player is already logged in as %q", req.From)
|
||
|
break
|
||
|
}
|
||
4 years ago
|
spawn.exec(&w.rooms[0], nil, req.Seq)
|
||
|
p := w.rooms[0].players[req.From]
|
||
|
w.players[req.From] = p
|
||
4 years ago
|
break
|
||
|
}
|
||
|
|
||
4 years ago
|
p, ok := w.players[req.From]
|
||
|
if !ok {
|
||
4 years ago
|
w.Error("received non login request of type %T from unknown player %q", req.Wants, req.From)
|
||
4 years ago
|
}
|
||
4 years ago
|
|
||
4 years ago
|
p.pending = append(p.pending, req)
|
||
|
|
||
4 years ago
|
case <-ticker.C:
|
||
|
w.tick(time.Since(lastTick))
|
||
|
lastTick = time.Now()
|
||
4 years ago
|
|
||
4 years ago
|
case <-w.done:
|
||
|
return
|
||
4 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
4 years ago
|
func (w *World) Stop() error {
|
||
|
w.Info("stopping simulation")
|
||
|
w.done <- true
|
||
|
return nil
|
||
|
}
|
||
|
|
||
4 years ago
|
func (w *World) tick(d time.Duration) {
|
||
4 years ago
|
for _, r := range w.rooms {
|
||
|
r.update(d)
|
||
|
}
|
||
4 years ago
|
}
|