- commit
- 0574812fb1feeffe28f527332833eb2eea539a48
- parent
- 752095b992d18b0e77e9d3ed9fa4aa1978c26676
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2024-09-21 08:00
split go code into separate files
Diffstat
| M | .gitignore | 2 | +- |
| M | Makefile | 10 | +++++----- |
| R | laneya.go -> game.go | 229 | +++++++++---------------------------------------------------- |
| A | geo.go | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | server.go | 134 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
5 files changed, 219 insertions, 204 deletions
diff --git a/.gitignore b/.gitignore
@@ -1 +1 @@1 -1 laneya-1 1 server
diff --git a/Makefile b/Makefile
@@ -1,13 +1,13 @@ 1 1 .PHONY: live 2 2 live:3 -1 echo laneya.go | entr -r make lint run-1 3 find . -name '*.go' | entr -r make lint run 4 4 5 5 .PHONY: run6 -1 run: laneya7 -1 ./laneya -v -s-1 6 run: server -1 7 ./server -v -s 8 89 -1 laneya: laneya.go10 -1 go build $<-1 9 server: *.go -1 10 go build 11 11 12 12 .PHONY: lint 13 13 lint:
diff --git a/laneya.go b/game.go
@@ -1,38 +1,12 @@ 1 1 package main 2 2 3 3 import (4 -1 "context"5 -1 "flag"6 -1 "fmt"7 4 "log"8 -1 "math/rand"9 -1 "net"10 -1 "net/http"11 -1 "os"12 -1 "os/signal"13 5 "sync"14 -1 "syscall"15 -1 "time"16 6 17 7 "github.com/gorilla/websocket" 18 8 ) 19 920 -1 var upgrader = websocket.Upgrader{}21 -1 var verbose = false22 -1 var static = false23 -124 -1 type Point struct {25 -1 X int `json:"x"`26 -1 Y int `json:"y"`27 -1 }28 -129 -1 type Rect struct {30 -1 X1 int `json:"x1"`31 -1 Y1 int `json:"y1"`32 -1 X2 int `json:"x2"`33 -1 Y2 int `json:"y2"`34 -1 }35 -136 10 type Message map[string]interface{} 37 11 38 12 type Player struct { @@ -60,55 +34,12 @@ type Game struct { 60 34 Ladder Point 61 35 } 62 36 -1 37 var verbose = false -1 38 var static = false -1 39 63 40 var mux = &sync.RWMutex{} 64 41 var games = make(map[string]*Game) 65 4266 -1 func makeRect(x1 int, y1 int, x2 int, y2 int) Rect {67 -1 if x1 > x2 {68 -1 x1, x2 = x2, x169 -1 }70 -1 if y1 > y2 {71 -1 y1, y2 = y2, y172 -1 }73 -1 return Rect{x1, y1, x2, y2}74 -1 }75 -176 -1 func randomRect(n int) Rect {77 -1 x1 := rand.Intn(2*n) - n78 -1 x2 := rand.Intn(2*n) - n79 -1 y1 := rand.Intn(2*n) - n80 -1 y2 := rand.Intn(2*n) - n81 -1 return makeRect(x1, y1, x2, y2)82 -1 }83 -184 -1 func (game *Game) generateMap() {85 -1 prev := Rect{-5, -5, 5, 5}86 -187 -1 game.Rects = []Rect{prev}88 -1 lines := []Rect{}89 -190 -1 for i := 1; i <= 12; i++ {91 -1 rect := randomRect(50)92 -1 if rect.Area() < 250 {93 -1 game.Rects = append(game.Rects, rect)94 -195 -1 p1 := prev.Center()96 -1 p2 := rect.Center()97 -198 -1 lines = append(lines, makeRect(p1.X, p1.Y, p2.X, p1.Y))99 -1 lines = append(lines, makeRect(p2.X, p1.Y, p2.X, p2.Y))100 -1101 -1 prev = rect102 -1 }103 -1 }104 -1105 -1 game.Ladder = prev.Center()106 -1107 -1 for _, line := range lines {108 -1 game.Rects = append(game.Rects, line)109 -1 }110 -1 }111 -1112 43 func getGame(id string) *Game { 113 44 mux.RLock() 114 45 game, ok := games[id] @@ -134,21 +65,6 @@ func getGame(id string) *Game { 134 65 return game 135 66 } 136 67137 -1 func (rect *Rect) Contains(x int, y int) bool {138 -1 return x >= rect.X1 && x <= rect.X2 && y >= rect.Y1 && y <= rect.Y2139 -1 }140 -1141 -1 func (rect *Rect) Area() int {142 -1 return (rect.X2 - rect.X1) * (rect.Y2 - rect.Y1)143 -1 }144 -1145 -1 func (rect *Rect) Center() Point {146 -1 return Point{147 -1 (rect.X2 + rect.X1) / 2,148 -1 (rect.Y2 + rect.Y1) / 2,149 -1 }150 -1 }151 -1152 68 func (game *Game) broadcast(msgs []Message) { 153 69 for player, _ := range game.Players { 154 70 player.Send <- msgs @@ -160,6 +76,34 @@ func (game *Game) createId() int { 160 76 return game.lastId 161 77 } 162 78 -1 79 func (game *Game) generateMap() { -1 80 prev := Rect{-5, -5, 5, 5} -1 81 -1 82 game.Rects = []Rect{prev} -1 83 lines := []Rect{} -1 84 -1 85 for i := 1; i <= 12; i++ { -1 86 rect := randomRect(50) -1 87 if rect.Area() < 250 { -1 88 game.Rects = append(game.Rects, rect) -1 89 -1 90 p1 := prev.Center() -1 91 p2 := rect.Center() -1 92 -1 93 lines = append(lines, makeRect(p1.X, p1.Y, p2.X, p1.Y)) -1 94 lines = append(lines, makeRect(p2.X, p1.Y, p2.X, p2.Y)) -1 95 -1 96 prev = rect -1 97 } -1 98 } -1 99 -1 100 game.Ladder = prev.Center() -1 101 -1 102 for _, line := range lines { -1 103 game.Rects = append(game.Rects, line) -1 104 } -1 105 } -1 106 163 107 func (game *Game) IsFree(x int, y int) bool { 164 108 for _, rect := range game.Rects { 165 109 if rect.Contains(x, y) { @@ -279,114 +223,3 @@ func (game *Game) run() { 279 223 } 280 224 } 281 225 }282 -1283 -1 func (player *Player) readPump() {284 -1 defer func() {285 -1 player.Game.unregister <- player286 -1 player.conn.Close()287 -1 }()288 -1289 -1 for {290 -1 msg := Message{}291 -1 err := player.conn.ReadJSON(&msg)292 -1 if err != nil {293 -1 return294 -1 }295 -1 player.Game.Msg <- PlayerMessage{player, msg}296 -1 }297 -1 }298 -1299 -1 func (player *Player) writePump() {300 -1 defer player.conn.Close()301 -1 ticker := time.NewTicker(60 * time.Second)302 -1 defer ticker.Stop()303 -1304 -1 for {305 -1 select {306 -1 case data := <-player.Send:307 -1 err := player.conn.WriteJSON(data)308 -1 if err != nil {309 -1 return310 -1 }311 -1 case <-ticker.C:312 -1 if !player.alive {313 -1 return314 -1 }315 -1 player.alive = false316 -1 err := player.conn.WriteMessage(websocket.PingMessage, nil)317 -1 if err != nil {318 -1 return319 -1 }320 -1 }321 -1 }322 -1 }323 -1324 -1 func serveWs(w http.ResponseWriter, r *http.Request) {325 -1 conn, err := upgrader.Upgrade(w, r, nil)326 -1 if err != nil {327 -1 log.Println(err)328 -1 return329 -1 }330 -1331 -1 game := getGame(r.PathValue("id"))332 -1333 -1 player := &Player{334 -1 Game: game,335 -1 Send: make(chan []Message),336 -1 conn: conn,337 -1 alive: true,338 -1 Id: game.createId(),339 -1 Pos: Point{0, 0},340 -1 }341 -1 conn.SetPongHandler(func(string) error {342 -1 player.alive = true343 -1 return nil344 -1 })345 -1 game.register <- player346 -1347 -1 go player.writePump()348 -1 go player.readPump()349 -1 }350 -1351 -1 func main() {352 -1 flag.Usage = func() {353 -1 fmt.Fprintf(os.Stderr, "laneya [-v] [-s] [port]\n")354 -1 flag.PrintDefaults()355 -1 }356 -1357 -1 flag.BoolVar(&verbose, "v", false, "enable verbose logs")358 -1 flag.BoolVar(&static, "s", false, "serve static files (for development)")359 -1 flag.Parse()360 -1361 -1 addr := "localhost:8000"362 -1 if len(flag.Args()) > 0 {363 -1 addr = fmt.Sprintf("localhost:%s", flag.Args()[0])364 -1 }365 -1366 -1 if static {367 -1 http.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {368 -1 http.ServeFile(w, r, "index.html")369 -1 })370 -1 http.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))371 -1 }372 -1 http.HandleFunc("GET /ws/{id}", serveWs)373 -1374 -1 ctx, unregisterSignals := signal.NotifyContext(375 -1 context.Background(), os.Interrupt, syscall.SIGTERM,376 -1 )377 -1 ctxFactory := func(l net.Listener) context.Context { return ctx }378 -1 server := &http.Server{Addr: addr, BaseContext: ctxFactory}379 -1380 -1 go func() {381 -1 log.Printf("Serving on http://%s", addr)382 -1 err := server.ListenAndServe()383 -1 if err != http.ErrServerClosed {384 -1 log.Fatal(err)385 -1 }386 -1 }()387 -1388 -1 <-ctx.Done()389 -1 unregisterSignals()390 -1 log.Println("Shutting down server…")391 -1 server.Shutdown(context.Background())392 -1 }
diff --git a/geo.go b/geo.go
@@ -0,0 +1,48 @@
-1 1 package main
-1 2
-1 3 import "math/rand"
-1 4
-1 5 type Point struct {
-1 6 X int `json:"x"`
-1 7 Y int `json:"y"`
-1 8 }
-1 9
-1 10 type Rect struct {
-1 11 X1 int `json:"x1"`
-1 12 Y1 int `json:"y1"`
-1 13 X2 int `json:"x2"`
-1 14 Y2 int `json:"y2"`
-1 15 }
-1 16
-1 17 func makeRect(x1 int, y1 int, x2 int, y2 int) Rect {
-1 18 if x1 > x2 {
-1 19 x1, x2 = x2, x1
-1 20 }
-1 21 if y1 > y2 {
-1 22 y1, y2 = y2, y1
-1 23 }
-1 24 return Rect{x1, y1, x2, y2}
-1 25 }
-1 26
-1 27 func randomRect(n int) Rect {
-1 28 x1 := rand.Intn(2*n) - n
-1 29 x2 := rand.Intn(2*n) - n
-1 30 y1 := rand.Intn(2*n) - n
-1 31 y2 := rand.Intn(2*n) - n
-1 32 return makeRect(x1, y1, x2, y2)
-1 33 }
-1 34
-1 35 func (rect *Rect) Area() int {
-1 36 return (rect.X2 - rect.X1) * (rect.Y2 - rect.Y1)
-1 37 }
-1 38
-1 39 func (rect *Rect) Contains(x int, y int) bool {
-1 40 return x >= rect.X1 && x <= rect.X2 && y >= rect.Y1 && y <= rect.Y2
-1 41 }
-1 42
-1 43 func (rect *Rect) Center() Point {
-1 44 return Point{
-1 45 (rect.X2 + rect.X1) / 2,
-1 46 (rect.Y2 + rect.Y1) / 2,
-1 47 }
-1 48 }
diff --git a/server.go b/server.go
@@ -0,0 +1,134 @@
-1 1 package main
-1 2
-1 3 import (
-1 4 "context"
-1 5 "flag"
-1 6 "fmt"
-1 7 "log"
-1 8 "net"
-1 9 "net/http"
-1 10 "os"
-1 11 "os/signal"
-1 12 "syscall"
-1 13 "time"
-1 14
-1 15 "github.com/gorilla/websocket"
-1 16 )
-1 17
-1 18 var upgrader = websocket.Upgrader{}
-1 19
-1 20 func (player *Player) readPump() {
-1 21 defer func() {
-1 22 player.Game.unregister <- player
-1 23 player.conn.Close()
-1 24 }()
-1 25
-1 26 for {
-1 27 msg := Message{}
-1 28 err := player.conn.ReadJSON(&msg)
-1 29 if err != nil {
-1 30 return
-1 31 }
-1 32 player.Game.Msg <- PlayerMessage{player, msg}
-1 33 }
-1 34 }
-1 35
-1 36 func (player *Player) writePump() {
-1 37 defer player.conn.Close()
-1 38 ticker := time.NewTicker(60 * time.Second)
-1 39 defer ticker.Stop()
-1 40
-1 41 for {
-1 42 select {
-1 43 case data := <-player.Send:
-1 44 err := player.conn.WriteJSON(data)
-1 45 if err != nil {
-1 46 return
-1 47 }
-1 48 case <-ticker.C:
-1 49 if !player.alive {
-1 50 return
-1 51 }
-1 52 player.alive = false
-1 53 err := player.conn.WriteMessage(websocket.PingMessage, nil)
-1 54 if err != nil {
-1 55 return
-1 56 }
-1 57 }
-1 58 }
-1 59 }
-1 60
-1 61 func serveWs(w http.ResponseWriter, r *http.Request) {
-1 62 conn, err := upgrader.Upgrade(w, r, nil)
-1 63 if err != nil {
-1 64 log.Println(err)
-1 65 return
-1 66 }
-1 67
-1 68 game := getGame(r.PathValue("id"))
-1 69
-1 70 player := &Player{
-1 71 Game: game,
-1 72 Send: make(chan []Message),
-1 73 conn: conn,
-1 74 alive: true,
-1 75 Id: game.createId(),
-1 76 Pos: Point{0, 0},
-1 77 }
-1 78 conn.SetPongHandler(func(string) error {
-1 79 player.alive = true
-1 80 return nil
-1 81 })
-1 82 game.register <- player
-1 83
-1 84 go player.writePump()
-1 85 go player.readPump()
-1 86 }
-1 87
-1 88 func serve(addr string) {
-1 89 http.HandleFunc("GET /ws/{id}", serveWs)
-1 90
-1 91 ctx, unregisterSignals := signal.NotifyContext(
-1 92 context.Background(), os.Interrupt, syscall.SIGTERM,
-1 93 )
-1 94 ctxFactory := func(l net.Listener) context.Context { return ctx }
-1 95 server := &http.Server{Addr: addr, BaseContext: ctxFactory}
-1 96
-1 97 go func() {
-1 98 log.Printf("Serving on http://%s", addr)
-1 99 err := server.ListenAndServe()
-1 100 if err != http.ErrServerClosed {
-1 101 log.Fatal(err)
-1 102 }
-1 103 }()
-1 104
-1 105 <-ctx.Done()
-1 106 unregisterSignals()
-1 107 log.Println("Shutting down server…")
-1 108 server.Shutdown(context.Background())
-1 109 }
-1 110
-1 111 func main() {
-1 112 flag.Usage = func() {
-1 113 fmt.Fprintf(os.Stderr, "laneya [-v] [-s] [port]\n")
-1 114 flag.PrintDefaults()
-1 115 }
-1 116
-1 117 flag.BoolVar(&verbose, "v", false, "enable verbose logs")
-1 118 flag.BoolVar(&static, "s", false, "serve static files (for development)")
-1 119 flag.Parse()
-1 120
-1 121 addr := "localhost:8000"
-1 122 if len(flag.Args()) > 0 {
-1 123 addr = fmt.Sprintf("localhost:%s", flag.Args()[0])
-1 124 }
-1 125
-1 126 if static {
-1 127 http.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
-1 128 http.ServeFile(w, r, "index.html")
-1 129 })
-1 130 http.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
-1 131 }
-1 132
-1 133 serve(addr)
-1 134 }