diff --git a/controllers/connection.go b/controllers/connection.go index 74265b7..3baa611 100644 --- a/controllers/connection.go +++ b/controllers/connection.go @@ -8,17 +8,17 @@ import ( ) func (h *Hub) readLoop(conn *websocket.Conn) { - handMessage := models.Message{Type: MSG_WELCOME} - _ = conn.WriteMessage(websocket.BinaryMessage, handMessage.Encode()) - - var player *models.Player + var id uint32 + log.Println("client ws connected") defer func() { - if player != nil { - h.removePlayer(player.ID) - log.Println("Player left:", player.ID) - } conn.Close() + if id != 0 { + h.removeEntity(id) + log.Println("entity [player] removed:", id) + } + + log.Println("client ws disconnected") }() for { @@ -36,20 +36,32 @@ func (h *Hub) readLoop(conn *websocket.Conn) { switch msg.Type { case MSG_WELCOME: - if player != nil { - continue + reader := models.NewReader(msg.Payload) + log.Println("MSG_WELCOME received", &msg.Payload) + id = reader.ReadU32() + name := reader.ReadString() + + if h.Entities[id] != nil { + h.ErrorMsg("Entity already exists", conn) } - player = h.handShake(msg.Payload, conn) - log.Println("Player joined:", player.ID) + + player := &models.Player{ + BaseEntity: models.BaseEntity{ID: id}, + Name: name, + } + + h.addEntity(id, player) + h.Clients[id] = conn + log.Println("entity [player] added:", id) case MSG_INPUT: - if player == nil { - continue - } reader := models.NewReader(msg.Payload) + id := reader.ReadU32() x := reader.ReadF32() y := reader.ReadF32() - h.updatePosition(x, y, player) + z := reader.ReadF32() + h.updateEntityPosition(x, y, z, id) + log.Println(h.Entities) } } } diff --git a/controllers/entities.go b/controllers/entities.go new file mode 100644 index 0000000..d0c0919 --- /dev/null +++ b/controllers/entities.go @@ -0,0 +1,31 @@ +package controllers + +import "server/models" + +func (h *Hub) addEntity(id uint32, entity models.Entity) { + h.Mu.Lock() + defer h.Mu.Unlock() + + h.Entities[id] = entity +} + +func (h *Hub) updateEntityPosition(x, y, z float32, entity_id uint32) { + h.Mu.Lock() + defer h.Mu.Unlock() + + h.Entities[entity_id].SetPosition(x, y, z) +} + +func (h *Hub) updateEntityRotation(yaw float32, entity_id uint32) { + h.Mu.Lock() + defer h.Mu.Unlock() + + h.Entities[entity_id].SetYaw(yaw) +} + +func (h *Hub) removeEntity(id uint32) { + h.Mu.Lock() + defer h.Mu.Unlock() + + delete(h.Entities, id) +} diff --git a/controllers/hub.go b/controllers/hub.go index 396e709..884e5ad 100644 --- a/controllers/hub.go +++ b/controllers/hub.go @@ -5,16 +5,20 @@ import ( "net/http" "server/models" "sync" + + "github.com/gorilla/websocket" ) type Hub struct { - Players map[uint32]*models.Player - Mu sync.RWMutex + Entities map[uint32]models.Entity + Clients map[uint32]*websocket.Conn + Mu sync.RWMutex } func NewHub() *Hub { return &Hub{ - Players: make(map[uint32]*models.Player), + Entities: make(map[uint32]models.Entity), + Clients: make(map[uint32]*websocket.Conn), } } diff --git a/controllers/msg.go b/controllers/msg.go new file mode 100644 index 0000000..3fe855a --- /dev/null +++ b/controllers/msg.go @@ -0,0 +1,14 @@ +package controllers + +import ( + "server/models" + + "github.com/gorilla/websocket" +) + +func (h *Hub) ErrorMsg(msg string, conn *websocket.Conn) { + wr := models.Writer{} + wr.WriteString(msg) + errMsg := &models.Message{Type: 9, Version: 1, Payload: wr.Bytes()} + conn.WriteMessage(websocket.BinaryMessage, errMsg.Encode()) +} diff --git a/controllers/players.go b/controllers/players.go deleted file mode 100644 index 74bffbc..0000000 --- a/controllers/players.go +++ /dev/null @@ -1,43 +0,0 @@ -package controllers - -import ( - "server/models" - - "github.com/gorilla/websocket" -) - -func (h *Hub) handShake(msg []byte, conn *websocket.Conn) *models.Player { - reader := models.NewReader(msg) - newID := reader.ReadU32() - name := reader.ReadString() - - player := &models.Player{ - Entity: models.Entity{ - Type: models.EntityPlayer, - ID: newID, - }, - Name: name, - Conn: conn, - } - - h.Mu.Lock() - h.Players[player.ID] = player - h.Mu.Unlock() - - return player -} - -func (h *Hub) updatePosition(x, y float32, player *models.Player) { - h.Mu.Lock() - defer h.Mu.Unlock() - - player.X = x - player.Y = y -} - -func (h *Hub) removePlayer(id uint32) { - h.Mu.Lock() - defer h.Mu.Unlock() - - delete(h.Players, id) -} diff --git a/controllers/protocol.go b/controllers/protocol.go index 92d1a59..3eede1e 100644 --- a/controllers/protocol.go +++ b/controllers/protocol.go @@ -4,4 +4,5 @@ const ( MSG_WELCOME = 0 MSG_INPUT = 1 MSG_SNAPSHOT = 2 + MSG_EVENT = 3 ) diff --git a/controllers/world.go b/controllers/world.go index fdb014e..6d73257 100644 --- a/controllers/world.go +++ b/controllers/world.go @@ -12,15 +12,16 @@ func (h *Hub) broadcastSnapshot() { defer h.Mu.RUnlock() w := models.Writer{} - w.WriteU16(uint16(len(h.Players))) + w.WriteU16(uint16(len(h.Entities))) - for _, p := range h.Players { - w.WriteU32(p.ID) - w.WriteU8(uint8(models.EntityPlayer)) - w.WriteF32(p.X) - w.WriteF32(p.Y) - w.WriteF32(p.Z) - w.WriteF32(p.Yaw) + for _, e := range h.Entities { + w.WriteU32(e.GetID()) + w.WriteU8(uint8(e.GetType())) + x, y, z := e.GetPosition() + w.WriteF32(x) + w.WriteF32(y) + w.WriteF32(z) + w.WriteF32(e.GetYaw()) } msg := models.Message{ @@ -29,9 +30,9 @@ func (h *Hub) broadcastSnapshot() { Payload: w.Bytes(), } - for _, p := range h.Players { - if p.Conn != nil { - _ = p.Conn.WriteMessage(websocket.BinaryMessage, msg.Encode()) + for _, conn := range h.Clients { + if conn != nil { + _ = conn.WriteMessage(websocket.BinaryMessage, msg.Encode()) } } } diff --git a/models/client.go b/models/client.go new file mode 100644 index 0000000..12701ec --- /dev/null +++ b/models/client.go @@ -0,0 +1,8 @@ +package models + +import "github.com/gorilla/websocket" + +type Client struct { + ID uint32 + Conn *websocket.Conn +} diff --git a/models/entity.go b/models/entity.go index 4f99584..3403112 100644 --- a/models/entity.go +++ b/models/entity.go @@ -8,12 +8,44 @@ const ( EntityBullet EntityType = 3 ) -type Entity struct { - ID uint32 - Type EntityType - - X float32 - Y float32 - Z float32 - Yaw float32 +type Entity interface { + GetID() uint32 + GetType() EntityType + GetPosition() (float32, float32, float32) + SetPosition(float32, float32, float32) + GetYaw() float32 + SetYaw(float32) +} + +type BaseEntity struct { + ID uint32 + Type EntityType + X, Y, Z float32 + Yaw float32 +} + +func (e *BaseEntity) GetID() uint32 { + return e.ID +} + +func (e *BaseEntity) GetType() EntityType { + return e.Type +} + +func (e *BaseEntity) GetPosition() (float32, float32, float32) { + return e.X, e.Y, e.Z +} + +func (e *BaseEntity) SetPosition(x, y, z float32) { + e.X = x + e.Y = y + e.Z = z +} + +func (e *BaseEntity) GetYaw() float32 { + return e.Yaw +} + +func (e *BaseEntity) SetYaw(yaw float32) { + e.Yaw = yaw } diff --git a/models/player.go b/models/player.go index 66c6060..ffe98e5 100644 --- a/models/player.go +++ b/models/player.go @@ -1,9 +1,20 @@ package models -import "github.com/gorilla/websocket" - type Player struct { - Entity + BaseEntity Name string - Conn *websocket.Conn +} + +func NewPlayer(id uint32, name string) *Player { + return &Player{ + BaseEntity: BaseEntity{ + ID: id, + Type: EntityPlayer, + X: 0, + Y: 0, + Z: 0, + Yaw: 0, + }, + Name: name, + } }