You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
2.5 KiB
Go
134 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
"github.com/gobwas/ws"
|
|
"github.com/gobwas/ws/wsutil"
|
|
)
|
|
|
|
type Point2d struct {
|
|
X float64 `json:"x"`
|
|
Y float64 `json:"y"`
|
|
}
|
|
|
|
type Player struct {
|
|
Nickname string
|
|
Connection net.Conn
|
|
|
|
Position Point2d
|
|
}
|
|
|
|
type clientState Point2d
|
|
|
|
type serverState struct {
|
|
Entities []Point2d `json:"entities"`
|
|
}
|
|
|
|
func main() {
|
|
r := chi.NewRouter()
|
|
r.Use(middleware.Logger)
|
|
r.Use(middleware.Recoverer)
|
|
|
|
players := map[string]*Player{}
|
|
|
|
r.Get("/api/ws", func(w http.ResponseWriter, r *http.Request) {
|
|
username := r.URL.Query().Get("username")
|
|
|
|
conn, _, _, err := ws.UpgradeHTTP(r, w)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
players[username] = &Player{
|
|
Nickname: username,
|
|
Connection: conn,
|
|
|
|
Position: Point2d{0, 0},
|
|
}
|
|
|
|
go func() {
|
|
log.Printf(`[%s] logged in`, username)
|
|
|
|
ctx, cancelComms := context.WithCancel(context.Background())
|
|
|
|
go func() {
|
|
defer cancelComms()
|
|
|
|
for {
|
|
serverMsg := &serverState{
|
|
Entities: []Point2d{},
|
|
}
|
|
|
|
// generate custom message for this client
|
|
for name, player := range players {
|
|
if name != username {
|
|
serverMsg.Entities = append(serverMsg.Entities, player.Position)
|
|
}
|
|
}
|
|
|
|
rawServerMsg, err := json.Marshal(serverMsg)
|
|
if err != nil {
|
|
log.Print(err)
|
|
return
|
|
}
|
|
|
|
if err := wsutil.WriteServerText(conn, rawServerMsg); err != nil {
|
|
log.Print(err)
|
|
return
|
|
}
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-time.NewTimer(1000 / 30 * time.Millisecond).C:
|
|
}
|
|
}
|
|
}()
|
|
go func() {
|
|
defer cancelComms()
|
|
|
|
for {
|
|
rawClientMsg, err := wsutil.ReadClientText(conn)
|
|
if err != nil {
|
|
log.Print(err)
|
|
return
|
|
}
|
|
|
|
var clientMsg clientState
|
|
if err := json.Unmarshal(rawClientMsg, &clientMsg); err != nil {
|
|
log.Print(err)
|
|
return
|
|
}
|
|
|
|
// log.Printf(`[%v] Server received: %s`, username, repr.String(clientMsg))
|
|
players[username].Position = Point2d(clientMsg)
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-time.NewTimer(1000 / 30 * time.Millisecond).C:
|
|
}
|
|
}
|
|
}()
|
|
|
|
<-ctx.Done()
|
|
log.Printf(`[%s] left the session`, username)
|
|
|
|
delete(players, username)
|
|
conn.Close()
|
|
}()
|
|
})
|
|
|
|
log.Printf(`Starting server on :4000...`)
|
|
log.Fatal(http.ListenAndServe(":4000", r))
|
|
}
|