Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

server: Made the game playable from the server #70

Merged
merged 1 commit into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,20 @@ build:
@go build -v ./...

.PHONY: test
test: ## Run the tests
test: wasm ## Run the tests
@xvfb-run go test ./...

.PHONY: serve
serve: wasm ## Starts the server
@go run . server

.PHONY: wa-build
wa-build: ## Build the wasm Game
@env GOOS=js GOARCH=wasm go build -o ./server/assets/wasm/maze-wars.wasm ./client/wasm

.PHONY: wa-copy
wa-copy: ## Copy the 'wasm_exec.js' to execute WebAssembly binary
@cp $$(go env GOROOT)/misc/wasm/wasm_exec.js ./server/assets/js/

.PHONY: wasm
wasm: wa-copy wa-build ## Runs all the WASM related commands to have the code ready to run
26 changes: 14 additions & 12 deletions action/action.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package action

import (
"github.com/gorilla/websocket"
"github.com/xescugc/ltw/utils"
"nhooyr.io/websocket"
)

type Action struct {
Expand Down Expand Up @@ -256,22 +256,24 @@ func NewJoinRoom(room, name string) *Action {
}

type AddPlayerPayload struct {
ID string
Name string
LineID int
Websocket *websocket.Conn
Room string
ID string
Name string
LineID int
Websocket *websocket.Conn
RemoteAddr string
Room string
}

func NewAddPlayer(r, id, name string, lid int, ws *websocket.Conn) *Action {
func NewAddPlayer(r, id, name string, lid int, ws *websocket.Conn, ra string) *Action {
return &Action{
Type: AddPlayer,
AddPlayer: &AddPlayerPayload{
ID: id,
Name: name,
LineID: lid,
Websocket: ws,
Room: r,
ID: id,
Name: name,
LineID: lid,
Websocket: ws,
RemoteAddr: ra,
Room: r,
},
}
}
Expand Down
9 changes: 5 additions & 4 deletions client/camera.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
zoomScale = 0.5
minZoom = 0
maxZoom = 2
leeway = 50
)

// NewCameraStore creates a new CameraState linked to the Dispatcher d
Expand Down Expand Up @@ -83,15 +84,15 @@ func (cs *CameraStore) Reduce(state, a interface{}) interface{} {
// it means the cursor is moving out of boundaries so we
// increase the camera X/Y at a ratio of the cameraSpeed
// so we move it around on the map
if float64(act.CursorMove.Y) >= cstate.H {
if float64(act.CursorMove.Y) >= (cstate.H - leeway) {
cstate.Y += cs.cameraSpeed
} else if act.CursorMove.Y <= 0 {
} else if act.CursorMove.Y <= (0 + leeway) {
cstate.Y -= cs.cameraSpeed
}

if float64(act.CursorMove.X) >= cstate.W {
if float64(act.CursorMove.X) >= (cstate.W - leeway) {
cstate.X += cs.cameraSpeed
} else if act.CursorMove.X <= 0 {
} else if act.CursorMove.X <= (0 + leeway) {
cstate.X -= cs.cameraSpeed
}

Expand Down
4 changes: 2 additions & 2 deletions client/hud.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ func (hs *HUDStore) Draw(screen *ebiten.Image) {
for _, u := range hst.Units {
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(u.Object.X, u.Object.Y)
if cp.CanSummonUnit(u.Unit.Type.String()) {
if !cp.CanSummonUnit(u.Unit.Type.String()) {
op.ColorM.Scale(2, 0.5, 0.5, 0.9)
}
screen.DrawImage(u.Unit.Faceset.(*ebiten.Image), op)
Expand All @@ -298,7 +298,7 @@ func (hs *HUDStore) Draw(screen *ebiten.Image) {
for _, t := range hst.Towers {
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(t.Object.X, t.Object.Y)
if cp.CanPlaceTower(t.Tower.Type.String()) {
if !cp.CanPlaceTower(t.Tower.Type.String()) {
op.ColorM.Scale(2, 0.5, 0.5, 0.9)
} else if hst.SelectedTower != nil && hst.SelectedTower.Type == t.Tower.Type.String() {
// Once the tower is selected we gray it out
Expand Down
26 changes: 17 additions & 9 deletions client/new.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package client

import (
"context"
"fmt"
"log"
"math/rand"
"net/url"
"time"

"github.com/gorilla/websocket"
"github.com/hajimehoshi/ebiten/v2"
"github.com/xescugc/ltw/action"
"github.com/xescugc/ltw/assets"
"golang.org/x/image/font"
"golang.org/x/image/font/opentype"
"nhooyr.io/websocket"
"nhooyr.io/websocket/wsjson"
)

var (
Expand Down Expand Up @@ -55,7 +57,7 @@ func init() {
}
}

func New(ad *ActionDispatcher, rs *RouterStore, opt Options) error {
func New(ctx context.Context, ad *ActionDispatcher, rs *RouterStore, opt Options) error {
ebiten.SetWindowTitle("LTW")
ebiten.SetWindowSize(opt.ScreenW*2, opt.ScreenH*2)
ebiten.SetWindowResizingMode(ebiten.WindowResizingModeEnabled)
Expand All @@ -67,18 +69,21 @@ func New(ad *ActionDispatcher, rs *RouterStore, opt Options) error {
u := url.URL{Scheme: "ws", Host: opt.HostURL, Path: "/ws"}

var err error
wsc, _, err = websocket.DefaultDialer.Dial(u.String(), nil)

wsc, _, err = websocket.Dial(ctx, u.String(), nil)
if err != nil {
return fmt.Errorf("failed to dial the server %q: %w", u.String(), err)
}
defer wsc.Close()

go wsHandler()
wsc.SetReadLimit(-1)

err = wsc.WriteJSON(action.NewJoinRoom(opt.Room, opt.Name))
err = wsjson.Write(ctx, wsc, action.NewJoinRoom(opt.Room, opt.Name))
if err != nil {
return fmt.Errorf("failed to write JSON: %w", err)
}
defer wsc.CloseNow()

go wsHandler(ctx)

err = ebiten.RunGame(rs)
if err != nil {
Expand All @@ -88,10 +93,13 @@ func New(ad *ActionDispatcher, rs *RouterStore, opt Options) error {
return nil
}

func wsHandler() {
func run(ctx context.Context, rs *RouterStore, u string, opt Options) {
}

func wsHandler(ctx context.Context) {
for {
var act *action.Action
err := wsc.ReadJSON(&act)
err := wsjson.Read(ctx, wsc, &act)
if err != nil {
// TODO remove from the Room
log.Fatal(err)
Expand All @@ -103,7 +111,7 @@ func wsHandler() {

func wsSend(a *action.Action) {
a.Room = room
err := wsc.WriteJSON(a)
err := wsjson.Write(context.Background(), wsc, a)
if err != nil {
log.Fatal(err)
}
Expand Down
88 changes: 88 additions & 0 deletions client/wasm/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//go:build js && wasm

package main

import (
"context"
"fmt"
"log"
"syscall/js"

"github.com/xescugc/go-flux"
"github.com/xescugc/ltw/client"
"github.com/xescugc/ltw/inputer"
"github.com/xescugc/ltw/store"
)

func main() {
js.Global().Set("new_client", NewClient())
select {}
}

func NewClient() js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) any {
if len(args) != 2 || (args[0].String() == "" || args[1].String() == "") {
return fmt.Errorf("requires 2 parameters: room and name")
}
var (
err error
room = args[0].String()
name = args[1].String()
hostURL = "localhost:5555"
screenW = 288
screenH = 240
)

d := flux.NewDispatcher()
ad := client.NewActionDispatcher(d)

s := store.NewStore(d)

g := &client.Game{
Store: s,
}

i := inputer.NewEbiten()

// TODO: Change this to pass the specific store needed instead of all the game object
cs := client.NewCameraStore(d, s, screenW, screenH)
g.Camera = cs
g.Units, err = client.NewUnits(g)
if err != nil {
return fmt.Errorf("failed to initialize Units: %w", err)
}

g.Towers, err = client.NewTowers(g)
if err != nil {
return fmt.Errorf("failed to initialize Towers: %w", err)
}

g.HUD, err = client.NewHUDStore(d, i, g)
if err != nil {
return fmt.Errorf("failed to initialize HUDStore: %w", err)
}

l, err := client.NewLobbyStore(d, i, s, cs)
if err != nil {
return fmt.Errorf("failed to initialize LobbyStore: %w", err)
}
rs := client.NewRouterStore(d, g, l)

ctx := context.Background()
// We need to run this in a goroutine so when it's compiled to WASM
// it does not block the main thread https://github.com/golang/go/issues/41310
go func() {
err = client.New(ctx, ad, rs, client.Options{
HostURL: hostURL,
Room: room,
Name: name,
ScreenW: screenW,
ScreenH: screenH,
})
if err != nil {
log.Fatal(err)
}
}()
return nil
})
}
4 changes: 3 additions & 1 deletion cmd/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"context"
"fmt"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -56,8 +57,9 @@ var (
return fmt.Errorf("failed to initialize LobbyStore: %w", err)
}
rs := client.NewRouterStore(d, g, l)
ctx := context.Background()

err = client.New(ad, rs, client.Options{
err = client.New(ctx, ad, rs, client.Options{
HostURL: hostURL,
Room: room,
Name: name,
Expand Down
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
module github.com/xescugc/ltw

go 1.17
go 1.21

require (
github.com/davecgh/go-spew v1.1.0
github.com/gofrs/uuid v4.4.0+incompatible
github.com/golang/mock v1.6.0
github.com/gorilla/websocket v1.5.0
github.com/gorilla/handlers v1.5.2
github.com/gorilla/mux v1.8.1
github.com/hajimehoshi/ebiten/v2 v2.5.9
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.7.0
github.com/xescugc/go-flux v1.0.1
golang.org/x/image v0.10.0
nhooyr.io/websocket v1.8.10
)

require (
github.com/ebitengine/purego v0.4.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jezek/xgb v1.1.0 // indirect
Expand Down
Loading