From d3a19d5066e7f8cbb278d92f67c6f53ba3f93c19 Mon Sep 17 00:00:00 2001 From: Smile Rex Date: Wed, 14 Jan 2026 11:34:03 +0300 Subject: [PATCH] new files --- controllers/hub.go | 76 ++++++++++++++++++ main.go | 187 +-------------------------------------------- models/message.go | 6 ++ models/player.go | 19 +++++ 4 files changed, 105 insertions(+), 183 deletions(-) create mode 100644 controllers/hub.go create mode 100644 models/message.go create mode 100644 models/player.go diff --git a/controllers/hub.go b/controllers/hub.go new file mode 100644 index 0000000..0e64d8c --- /dev/null +++ b/controllers/hub.go @@ -0,0 +1,76 @@ +package controllers + +import ( + "bytes" + "encoding/binary" + "log" + "net/http" + "server/models" + + "github.com/gorilla/websocket" +) + +type Hub struct { + Players map[uint32]*models.Player + ServerBuffer []byte +} + +func NewHub() *Hub { + return &Hub{ + Players: make(map[uint32]*models.Player), + } +} + +func (h *Hub) readLoop(conn *websocket.Conn) { + p := &models.Player{ + Conn: conn, + InputX: 0, + InputZ: 0, + } + log.Println("Player connected:", p.ID) + + h.Players[p.ID] = p + + defer func() { + delete(h.Players, p.ID) + + p.Conn.Close() + log.Println("Player disconnected:", p.ID) + }() + + for { + _, data, err := p.Conn.ReadMessage() + if err != nil { + return + } + + if len(data) < 8 { + continue + } + + buf := bytes.NewReader(data) + binary.Read(buf, binary.LittleEndian, &p.InputX) + binary.Read(buf, binary.LittleEndian, &p.InputZ) + } +} + +func (h *Hub) StartWS(w http.ResponseWriter, r *http.Request) { + upgrader := websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { return true }, + } + + for { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Println(err) + continue + } + + go h.readLoop(conn) + } +} + +func (h *Hub) Start() { + http.HandleFunc("/ws", h.StartWS) + log.Fatal(http.ListenAndServe(":8080", nil)) +} diff --git a/main.go b/main.go index cb61870..38b5d4e 100644 --- a/main.go +++ b/main.go @@ -1,191 +1,12 @@ package main import ( - "bytes" - "encoding/binary" "log" - "math/rand" - "net/http" - "sync" - "time" - - "github.com/gorilla/websocket" -) - -const ( - PacketHandshake uint8 = 0 - PacketWorld uint8 = 1 - - TickRate = 30 - Speed = 5.0 - - SpawnMinX = -5.0 - SpawnMaxX = 5.0 - SpawnMinZ = -5.0 - SpawnMaxZ = 5.0 - SpawnRadius = 1.5 -) - -type Player struct { - ID uint32 - - X float32 - Y float32 - Z float32 - - InputX float32 - InputZ float32 - - Conn *websocket.Conn -} - -var ( - upgrader = websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { return true }, - } - - players = make(map[uint32]*Player) - playersMu sync.Mutex - nextID uint32 = 1 + "server/controllers" ) func main() { - rand.Seed(time.Now().UnixNano()) - - http.HandleFunc("/ws", handleWS) - - go gameLoop() - - log.Println("Server running on :8080") - log.Fatal(http.ListenAndServe(":8080", nil)) -} - -func handleWS(w http.ResponseWriter, r *http.Request) { - conn, err := upgrader.Upgrade(w, r, nil) - if err != nil { - return - } - - playersMu.Lock() - id := nextID - nextID++ - - x, z := randomSpawnPosition() - - player := &Player{ - ID: id, - X: x, - Y: 0, - Z: z, - Conn: conn, - } - players[id] = player - playersMu.Unlock() - - { - buf := new(bytes.Buffer) - binary.Write(buf, binary.LittleEndian, PacketHandshake) - binary.Write(buf, binary.LittleEndian, id) - conn.WriteMessage(websocket.BinaryMessage, buf.Bytes()) - } - - log.Println("Player connected:", id, "spawn at", x, z) - - go readLoop(player) -} - -func randomSpawnPosition() (float32, float32) { - for i := 0; i < 20; i++ { - x := rand.Float32()*(SpawnMaxX-SpawnMinX) + SpawnMinX - z := rand.Float32()*(SpawnMaxZ-SpawnMinZ) + SpawnMinZ - - if isSpawnFree(x, z) { - return x, z - } - } - - // fallback - return 0, 0 -} - -func isSpawnFree(x, z float32) bool { - for _, p := range players { - dx := p.X - x - dz := p.Z - z - if dx*dx+dz*dz < SpawnRadius*SpawnRadius { - return false - } - } - return true -} - -func readLoop(p *Player) { - defer func() { - playersMu.Lock() - delete(players, p.ID) - playersMu.Unlock() - - p.Conn.Close() - log.Println("Player disconnected:", p.ID) - }() - - for { - _, data, err := p.Conn.ReadMessage() - if err != nil { - return - } - - if len(data) < 8 { - continue - } - - buf := bytes.NewReader(data) - binary.Read(buf, binary.LittleEndian, &p.InputX) - binary.Read(buf, binary.LittleEndian, &p.InputZ) - } -} - -func gameLoop() { - ticker := time.NewTicker(time.Second / TickRate) - defer ticker.Stop() - - dt := float32(1.0 / TickRate) - - for range ticker.C { - update(dt) - broadcast() - } -} - -func update(dt float32) { - playersMu.Lock() - defer playersMu.Unlock() - - for _, p := range players { - p.X += p.InputX * Speed * dt - p.Z += p.InputZ * Speed * dt - } -} - -func broadcast() { - playersMu.Lock() - defer playersMu.Unlock() - - buf := new(bytes.Buffer) - - binary.Write(buf, binary.LittleEndian, PacketWorld) - binary.Write(buf, binary.LittleEndian, uint16(len(players))) - - for _, p := range players { - binary.Write(buf, binary.LittleEndian, p.ID) - binary.Write(buf, binary.LittleEndian, p.X) - binary.Write(buf, binary.LittleEndian, p.Y) - binary.Write(buf, binary.LittleEndian, p.Z) - } - - data := buf.Bytes() - - for _, p := range players { - p.Conn.WriteMessage(websocket.BinaryMessage, data) - } + hub := controllers.NewHub() + log.Println("Server listening websocket on :8080") + hub.Start() } diff --git a/models/message.go b/models/message.go new file mode 100644 index 0000000..ba0052d --- /dev/null +++ b/models/message.go @@ -0,0 +1,6 @@ +package models + +type Message struct { + Type int8 + Payload interface{} +} diff --git a/models/player.go b/models/player.go new file mode 100644 index 0000000..997063a --- /dev/null +++ b/models/player.go @@ -0,0 +1,19 @@ +package models + +import "github.com/gorilla/websocket" + +type Player struct { + ID uint32 + + X float32 + Y float32 + Z float32 + + InputX float32 + InputZ float32 + + Name string + PhotoURL string + + Conn *websocket.Conn +}