6 Commits

Author SHA1 Message Date
Smile Rex
cb586cd5ce add hsh responce
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m4s
2026-01-21 14:50:28 +03:00
Smile Rex
1bb1e3bfd4 fix
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 3m25s
2026-01-21 13:10:15 +03:00
Smile Rex
9cd779fbea cors fix
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m9s
2026-01-21 12:36:25 +03:00
Smile Rex
3c989c33f8 new server
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m19s
2026-01-17 16:38:45 +03:00
Smile Rex
1c60264d1d add readme
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m8s
2026-01-15 11:55:05 +03:00
61b7754c5c Merge pull request 'hub_feauture' (#1) from hub_feauture into main
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m8s
Reviewed-on: #1
2026-01-14 23:11:26 +03:00
10 changed files with 158 additions and 85 deletions

View File

@@ -8,17 +8,17 @@ import (
) )
func (h *Hub) readLoop(conn *websocket.Conn) { func (h *Hub) readLoop(conn *websocket.Conn) {
handMessage := models.Message{Type: MSG_WELCOME} var id uint32
_ = conn.WriteMessage(websocket.BinaryMessage, handMessage.Encode()) log.Println("client ws connected")
var player *models.Player
defer func() { defer func() {
if player != nil {
h.removePlayer(player.ID)
log.Println("Player left:", player.ID)
}
conn.Close() conn.Close()
if id != 0 {
h.removeEntity(id)
log.Println("entity [player] removed:", id)
}
log.Println("client ws disconnected")
}() }()
for { for {
@@ -36,20 +36,34 @@ func (h *Hub) readLoop(conn *websocket.Conn) {
switch msg.Type { switch msg.Type {
case MSG_WELCOME: case MSG_WELCOME:
if player != nil { reader := models.NewReader(msg.Payload)
continue 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)
confimMessage := models.Message{Type: MSG_WELCOME, Payload: []byte{}}
conn.WriteMessage(websocket.BinaryMessage, confimMessage.Encode())
case MSG_INPUT: case MSG_INPUT:
if player == nil {
continue
}
reader := models.NewReader(msg.Payload) reader := models.NewReader(msg.Payload)
id := reader.ReadU32()
x := reader.ReadF32() x := reader.ReadF32()
y := reader.ReadF32() y := reader.ReadF32()
h.updatePosition(x, y, player) z := reader.ReadF32()
h.updateEntityPosition(x, y, z, id)
log.Println(h.Entities)
} }
} }
} }

31
controllers/entities.go Normal file
View File

@@ -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)
}

View File

@@ -5,16 +5,20 @@ import (
"net/http" "net/http"
"server/models" "server/models"
"sync" "sync"
"github.com/gorilla/websocket"
) )
type Hub struct { type Hub struct {
Players map[uint32]*models.Player Entities map[uint32]models.Entity
Clients map[uint32]*websocket.Conn
Mu sync.RWMutex Mu sync.RWMutex
} }
func NewHub() *Hub { func NewHub() *Hub {
return &Hub{ return &Hub{
Players: make(map[uint32]*models.Player), Entities: make(map[uint32]models.Entity),
Clients: make(map[uint32]*websocket.Conn),
} }
} }

14
controllers/msg.go Normal file
View File

@@ -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())
}

View File

@@ -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)
}

View File

@@ -4,4 +4,5 @@ const (
MSG_WELCOME = 0 MSG_WELCOME = 0
MSG_INPUT = 1 MSG_INPUT = 1
MSG_SNAPSHOT = 2 MSG_SNAPSHOT = 2
MSG_EVENT = 3
) )

View File

@@ -12,15 +12,16 @@ func (h *Hub) broadcastSnapshot() {
defer h.Mu.RUnlock() defer h.Mu.RUnlock()
w := models.Writer{} w := models.Writer{}
w.WriteU16(uint16(len(h.Players))) w.WriteU16(uint16(len(h.Entities)))
for _, p := range h.Players { for _, e := range h.Entities {
w.WriteU32(p.ID) w.WriteU32(e.GetID())
w.WriteU8(uint8(models.EntityPlayer)) w.WriteU8(uint8(e.GetType()))
w.WriteF32(p.X) x, y, z := e.GetPosition()
w.WriteF32(p.Y) w.WriteF32(x)
w.WriteF32(p.Z) w.WriteF32(y)
w.WriteF32(p.Yaw) w.WriteF32(z)
w.WriteF32(e.GetYaw())
} }
msg := models.Message{ msg := models.Message{
@@ -29,9 +30,9 @@ func (h *Hub) broadcastSnapshot() {
Payload: w.Bytes(), Payload: w.Bytes(),
} }
for _, p := range h.Players { for _, conn := range h.Clients {
if p.Conn != nil { if conn != nil {
_ = p.Conn.WriteMessage(websocket.BinaryMessage, msg.Encode()) _ = conn.WriteMessage(websocket.BinaryMessage, msg.Encode())
} }
} }
} }

8
models/client.go Normal file
View File

@@ -0,0 +1,8 @@
package models
import "github.com/gorilla/websocket"
type Client struct {
ID uint32
Conn *websocket.Conn
}

View File

@@ -8,12 +8,44 @@ const (
EntityBullet EntityType = 3 EntityBullet EntityType = 3
) )
type Entity struct { type Entity interface {
GetID() uint32
GetType() EntityType
GetPosition() (float32, float32, float32)
SetPosition(float32, float32, float32)
GetYaw() float32
SetYaw(float32)
}
type BaseEntity struct {
ID uint32 ID uint32
Type EntityType Type EntityType
X, Y, Z float32
X float32
Y float32
Z float32
Yaw 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
}

View File

@@ -1,9 +1,20 @@
package models package models
import "github.com/gorilla/websocket"
type Player struct { type Player struct {
Entity BaseEntity
Name string 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,
}
} }