From 69902a800937f3079c963343dd47fb7f4868f750 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Tue, 27 Oct 2020 01:39:41 +0000 Subject: [PATCH] entities tickingggg --- internal/server/server.go | 3 ++ internal/server/session.go | 11 ++++---- internal/sim/entity.go | 2 ++ internal/sim/player.go | 15 ++++++++++ internal/sim/room.go | 18 ++++++++++++ internal/sim/tile.go | 28 +++++++++++++++++-- internal/sim/world.go | 56 ++++++++++++++++++++++++++++++-------- 7 files changed, 115 insertions(+), 18 deletions(-) diff --git a/internal/server/server.go b/internal/server/server.go index 90a2ef6..be2bbc9 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -94,6 +94,7 @@ func (s *Server) createSession(conn *websocket.Conn) *session { } s.waitOnSessions.Add(1) s.sessions[sn.id] = sn + sn.entityID = s.world.SpawnPlayer(sn.id) s.Info("created session %d, %d sessions active", sn.id, len(s.sessions)) return sn } @@ -106,6 +107,7 @@ func (s *Server) dropSession(sn *session) { close(sn.done) delete(s.sessions, sn.id) + s.world.DespawnPlayer(sn.entityID) s.waitOnSessions.Add(-1) s.Info("dropped session %d after %v time connected, %d sessions active", sn.id, time.Since(sn.start), len(s.sessions)) @@ -146,6 +148,7 @@ func (s *Server) Shutdown() { go func() { defer wg.Done() + log := s.Child("http") log.Info("shutting down http server") if err := s.http.Shutdown(context.Background()); err != nil { diff --git a/internal/server/session.go b/internal/server/session.go index 29c1d89..55c265a 100644 --- a/internal/server/session.go +++ b/internal/server/session.go @@ -12,11 +12,12 @@ import ( type session struct { *blammo.Log - id int - start time.Time - conn *websocket.Conn - outbox chan wire.Response - done chan bool + id int + entityID int + start time.Time + conn *websocket.Conn + outbox chan wire.Response + done chan bool } // run is the session run loop. diff --git a/internal/sim/entity.go b/internal/sim/entity.go index 11238d2..4aaa1dc 100644 --- a/internal/sim/entity.go +++ b/internal/sim/entity.go @@ -4,6 +4,8 @@ import "time" // entity is any entity that can be simulated. type entity interface { + id() int + // update is the standard tick function update(time.Duration) } diff --git a/internal/sim/player.go b/internal/sim/player.go index 625af19..33db8bb 100644 --- a/internal/sim/player.go +++ b/internal/sim/player.go @@ -1,5 +1,20 @@ package sim +import ( + "time" + + "github.com/jordanorelli/blammo" +) + // player represents a player character in the simulation type player struct { + *blammo.Log + sessionID int + entityID int } + +func (p *player) update(dt time.Duration) { + p.Info("tick") +} + +func (p *player) id() int { return p.entityID } diff --git a/internal/sim/room.go b/internal/sim/room.go index 94b1d04..cfbeabe 100644 --- a/internal/sim/room.go +++ b/internal/sim/room.go @@ -1,7 +1,25 @@ package sim +import ( + "time" + + "github.com/jordanorelli/blammo" +) + type room struct { + *blammo.Log + name string origin point width int height int + tiles []tile +} + +func (r *room) update(dt time.Duration) { + r.Info("updating room") + for _, t := range r.tiles { + for _, e := range t.contents { + e.update(dt) + } + } } diff --git a/internal/sim/tile.go b/internal/sim/tile.go index 0977bb2..0a9bc37 100644 --- a/internal/sim/tile.go +++ b/internal/sim/tile.go @@ -1,6 +1,30 @@ package sim +// tile is an individual cell within the world simulation. Everything happens +// on a tile. type tile struct { - floor floor - contents []entity + // floor is the surface for the tile. All things sit atop the floor. The + // floor informs clients how to draw the tile in the event that the tile's + // contents are empty. The floor also determins whether or not the tile is + // traversable. + floor floor + + // contents is all of the entities on this tile. A given tile may have many + // entities. + contents map[int]entity +} + +func (t *tile) addEntity(e entity) { + if t.contents == nil { + t.contents = make(map[int]entity) + } + t.contents[e.id()] = e +} + +func (t *tile) removeEntity(id int) entity { + if e, here := t.contents[id]; here { + delete(t.contents, id) + return e + } + return nil } diff --git a/internal/sim/world.go b/internal/sim/world.go index 723f538..d8ba618 100644 --- a/internal/sim/world.go +++ b/internal/sim/world.go @@ -1,6 +1,7 @@ package sim import ( + "strconv" "time" "github.com/jordanorelli/blammo" @@ -9,21 +10,24 @@ import ( // World is the entire simulated world. A world consists of many rooms. type World struct { *blammo.Log - rooms []room - done chan bool + rooms []room + done chan bool + lastEntityID int } func NewWorld(log *blammo.Log) *World { + foyer := room{ + Log: log.Child("foyer"), + name: "foyer", + origin: point{0, 0}, + width: 10, + height: 10, + tiles: make([]tile, 100), + } return &World{ - Log: log, - rooms: []room{ - room{ - origin: point{0, 0}, - width: 10, - height: 10, - }, - }, - done: make(chan bool), + Log: log, + rooms: []room{foyer}, + done: make(chan bool), } } @@ -51,6 +55,36 @@ func (w *World) Stop() error { return nil } +func (w *World) SpawnPlayer(id int) int { + w.lastEntityID++ + r := w.rooms[0] + w.Info("spawning player with id: %d into room %q", id, r.name) + t := &r.tiles[0] + p := player{ + Log: w.Child("players").Child(strconv.Itoa(id)), + sessionID: id, + entityID: w.lastEntityID, + } + t.addEntity(&p) + return p.entityID +} + +func (w *World) DespawnPlayer(id int) { + w.Info("despawning player with id: %d", id) + for _, r := range w.rooms { + for _, t := range r.tiles { + if e := t.removeEntity(id); e != nil { + w.Info("player removed from room %q", r.name) + return + } + } + } + w.Error("player was not found in any room") +} + func (w *World) tick(d time.Duration) { w.Info("tick. elapsed: %v", d) + for _, r := range w.rooms { + r.update(d) + } }