new files
This commit is contained in:
76
controllers/hub.go
Normal file
76
controllers/hub.go
Normal file
@@ -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))
|
||||
}
|
||||
187
main.go
187
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()
|
||||
}
|
||||
|
||||
6
models/message.go
Normal file
6
models/message.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package models
|
||||
|
||||
type Message struct {
|
||||
Type int8
|
||||
Payload interface{}
|
||||
}
|
||||
19
models/player.go
Normal file
19
models/player.go
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user