more broadcasts, tui client running

This commit is contained in:
stryan 2021-07-29 14:48:36 -04:00
parent 379719a2e2
commit f06754fcfe
10 changed files with 305 additions and 95 deletions

View File

@ -6,10 +6,12 @@ ifeq ($(PREFIX),) # PREFIX is environment variable, but if it is not set, then s
PREFIX := /usr/local PREFIX := /usr/local
endif endif
all: client server engine all: client client2 server engine
client: $(GAMEFILES) $(wildcard cmd/client/*.go) client: $(GAMEFILES) $(wildcard cmd/client/*.go)
go build -ldflags "-X main.GitCommit=$(GIT_COMMIT)" ./cmd/client go build -ldflags "-X main.GitCommit=$(GIT_COMMIT)" ./cmd/client
client2: $(GAMEFILES) $(wildcard cmd/client2/*.go)
go build -ldflags "-X main.GitCommit=$(GIT_COMMIT)" ./cmd/client2
server: $(GAMEFILES) $(COORDFILEs) $(wildcard cmd/server/*.go) server: $(GAMEFILES) $(COORDFILEs) $(wildcard cmd/server/*.go)
go build -ldflags "-X main.GitCommit=$(GIT_COMMIT)" ./cmd/server go build -ldflags "-X main.GitCommit=$(GIT_COMMIT)" ./cmd/server
engine: $(GAMEFILES) engine: $(GAMEFILES)

View File

@ -66,6 +66,20 @@ func receiveHandler(connection *websocket.Conn, output chan string) {
output <- "Sentinal wins!" output <- "Sentinal wins!"
case coordinator.SessionRespBroadcastScoWin: case coordinator.SessionRespBroadcastScoWin:
output <- "Scourge wins!" output <- "Scourge wins!"
case coordinator.SessionRespBroadcastUpdate:
//we don't handle updates
case coordinator.SessionRespBroadcastScoJoin:
output <- "Scourge has joined the game"
case coordinator.SessionRespBroadcastSenJoin:
output <- "Sentinal has joined the game"
case coordinator.SessionRespBroadcastScoLeft:
output <- "Scourge has left the game"
case coordinator.SessionRespBroadcastSenLeft:
output <- "Sentinal has left the game"
case coordinator.SessionRespBroadcastSenReady:
output <- "Sentinal is ready"
case coordinator.SessionRespBroadcastScoReady:
output <- "scourge is ready"
case coordinator.SessionRespBroadcastNone: case coordinator.SessionRespBroadcastNone:
case coordinator.SessionRespError: case coordinator.SessionRespError:

View File

@ -10,7 +10,6 @@ import (
"time" "time"
"unicode/utf8" "unicode/utf8"
"code.rocketnine.space/tslocum/cview"
"git.saintnet.tech/stryan/snengame/internal/coordinator" "git.saintnet.tech/stryan/snengame/internal/coordinator"
"git.saintnet.tech/stryan/snengame/internal/game" "git.saintnet.tech/stryan/snengame/internal/game"
"github.com/google/uuid" "github.com/google/uuid"
@ -22,7 +21,7 @@ var interrupt chan os.Signal
var pid int var pid int
var matchID uuid.UUID var matchID uuid.UUID
func receiveHandler(connection *websocket.Conn, output chan string) { func receiveHandler(connection *websocket.Conn, container *UIContainer) {
defer close(done) defer close(done)
for { for {
var resp coordinator.SessionCommandResult var resp coordinator.SessionCommandResult
@ -33,54 +32,67 @@ func receiveHandler(connection *websocket.Conn, output chan string) {
switch resp.Result { switch resp.Result {
case coordinator.SessionRespJoined1: case coordinator.SessionRespJoined1:
pid = game.SentinalID pid = game.SentinalID
output <- "joined as sentinal" container.Output <- "joined as sentinal"
case coordinator.SessionRespJoined2: case coordinator.SessionRespJoined2:
pid = game.ScourgeID pid = game.ScourgeID
output <- "joined as scourge" container.Output <- "joined as scourge"
case coordinator.SessionRespFound: case coordinator.SessionRespFound:
matchID = resp.MatchID matchID = resp.MatchID
output <- "game found" container.Output <- "game found"
case coordinator.SessionRespPlayed: case coordinator.SessionRespPlayed:
if resp.GameResult != nil { if resp.GameResult != nil {
output <- "played succesfully"
switch resp.GameResult.ResultType { switch resp.GameResult.ResultType {
case game.ActCmd: case game.ActCmd:
output <- resp.GameResult.ActionResult.String() container.Output <- resp.GameResult.ActionResult.String()
case game.StateCmd: case game.StateCmd:
output <- resp.GameResult.StateResult.String() container.State = resp.GameResult.StateResult
container.Updated <- true
case game.DebugCmd: case game.DebugCmd:
output <- resp.GameResult.DebugResult.String() container.Output <- resp.GameResult.DebugResult.String()
} }
} else { } else {
output <- "error playing" container.Output <- "error playing"
} }
case coordinator.SessionRespLeft: case coordinator.SessionRespLeft:
output <- "game left" container.Output <- "game left"
break break
case coordinator.SessionRespBroadcastSenTurn: case coordinator.SessionRespBroadcastSenTurn:
output <- "Sentinal may take their turn" container.Output <- "Sentinal may take their turn"
case coordinator.SessionRespBroadcastScoTrun: case coordinator.SessionRespBroadcastScoTrun:
output <- "Scourge may take their turn" container.Output <- "Scourge may take their turn"
case coordinator.SessionRespBroadcastSenWin: case coordinator.SessionRespBroadcastSenWin:
output <- "Sentinal wins!" container.Output <- "Sentinal wins!"
case coordinator.SessionRespBroadcastScoWin: case coordinator.SessionRespBroadcastScoWin:
output <- "Scourge wins!" container.Output <- "Scourge wins!"
case coordinator.SessionRespBroadcastUpdate:
container.GetUpdate <- true
case coordinator.SessionRespBroadcastScoJoin:
container.Output <- "Scourge has joined the game"
case coordinator.SessionRespBroadcastSenJoin:
container.Output <- "Sentinal has joined the game"
case coordinator.SessionRespBroadcastScoLeft:
container.Output <- "Scourge has left the game"
case coordinator.SessionRespBroadcastSenLeft:
container.Output <- "Sentinal has left the game"
case coordinator.SessionRespBroadcastSenReady:
container.Output <- "Sentinal is ready"
case coordinator.SessionRespBroadcastScoReady:
container.Output <- "scourge is ready"
case coordinator.SessionRespBroadcastNone: case coordinator.SessionRespBroadcastNone:
case coordinator.SessionRespError: case coordinator.SessionRespError:
output <- "generic error" container.Output <- "generic error"
default: default:
output <- "Received a server response we don't know how to handle" container.Output <- "Received a server response we don't know how to handle"
} }
} }
} }
func backend(input chan string, outputview *cview.TextView) { func backend(container *UIContainer) {
done = make(chan interface{}) // Channel to indicate that the receiverHandler is done done = make(chan interface{}) // Channel to indicate that the receiverHandler is done
interrupt = make(chan os.Signal) // Channel to listen for interrupt signal to terminate gracefully interrupt = make(chan os.Signal) // Channel to listen for interrupt signal to terminate gracefully
cmd := make(chan coordinator.SessionCommand) cmd := make(chan coordinator.SessionCommand)
output := make(chan string)
signal.Notify(interrupt, os.Interrupt) // Notify the interrupt channel for SIGINT signal.Notify(interrupt, os.Interrupt) // Notify the interrupt channel for SIGINT
hostname := flag.String("host", "localhost", "server hostname to connect to") hostname := flag.String("host", "localhost", "server hostname to connect to")
@ -89,21 +101,20 @@ func backend(input chan string, outputview *cview.TextView) {
flag.Parse() flag.Parse()
port_s := strconv.Itoa(*port) port_s := strconv.Itoa(*port)
socketUrl := "ws://" + *hostname + ":" + port_s + "/ws" socketUrl := "ws://" + *hostname + ":" + port_s + "/ws"
conn, _, err := websocket.DefaultDialer.Dial(socketUrl, nil)
id := uuid.New() id := uuid.New()
conn, _, err := websocket.DefaultDialer.Dial(socketUrl, nil)
if err != nil { if err != nil {
log.Fatal("Error connecting to Websocket Server:", err) log.Fatal("Error connecting to Websocket Server:", err)
} }
defer conn.Close() defer conn.Close()
go receiveHandler(conn, output) go receiveHandler(conn, container)
go GetCommand(id, cmd, input) go GetCommand(id, cmd, container)
ticker := time.NewTicker(1 * time.Second) ticker := time.NewTicker(2 * time.Second)
// Our main loop for the client // Our main loop for the client
// We send our relevant packets here // We send our relevant packets here
for { for {
var c coordinator.SessionCommand var c coordinator.SessionCommand
var o string
select { select {
case c = <-cmd: case c = <-cmd:
err := conn.WriteJSON(c) err := conn.WriteJSON(c)
@ -114,8 +125,25 @@ func backend(input chan string, outputview *cview.TextView) {
if c.Command == coordinator.SessionCmdLeave { if c.Command == coordinator.SessionCmdLeave {
break break
} }
case o = <-output: case <-container.GetUpdate:
outputview.SetText(o) if container.State != nil {
err = conn.WriteJSON(&coordinator.SessionCommand{
ID: id,
MatchID: matchID,
Command: coordinator.SessionCmdPlay,
GameCommand: &game.Command{
PlayerID: pid,
Type: game.StateCmd,
Cmd: "g",
},
})
if err != nil {
log.Println("Error during writing to websocker:", err)
return
}
container.Updated <- true
}
case <-interrupt: case <-interrupt:
// We received a SIGINT (Ctrl + C). Terminate gracefully... // We received a SIGINT (Ctrl + C). Terminate gracefully...
log.Println("Received SIGINT interrupt signal. Closing all pending connections") log.Println("Received SIGINT interrupt signal. Closing all pending connections")
@ -153,11 +181,11 @@ func backend(input chan string, outputview *cview.TextView) {
} }
} }
func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand, inputchan chan string) { func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand, container *UIContainer) {
for { for {
var cmd string var cmd string
var t int var t int
input := <-inputchan input := <-container.Input
input_s := strings.Split(input, " ") input_s := strings.Split(input, " ")
t, err := strconv.Atoi(input_s[0]) t, err := strconv.Atoi(input_s[0])
if err != nil { if err != nil {

View File

@ -1,20 +1,32 @@
package main package main
import ( import (
"fmt"
"code.rocketnine.space/tslocum/cview" "code.rocketnine.space/tslocum/cview"
"git.saintnet.tech/stryan/snengame/internal/game"
"github.com/gdamore/tcell/v2" "github.com/gdamore/tcell/v2"
) )
type UIContainer struct {
State *game.GameView
Updated chan bool
Output chan string
Input chan string
GetUpdate chan bool
}
func main() { func main() {
app := cview.NewApplication() app := cview.NewApplication()
app.EnableMouse(true) app.EnableMouse(true)
newPrimitive := func(text string) cview.Primitive { container := &UIContainer{
tv := cview.NewTextView() State: nil,
tv.SetTextAlign(cview.AlignCenter) Updated: make(chan bool),
tv.SetText(text) Output: make(chan string),
return tv Input: make(chan string),
GetUpdate: make(chan bool),
} }
inputchan := make(chan string)
grid := cview.NewGrid() grid := cview.NewGrid()
grid.SetRows(3, 0, 0, 3, 3) grid.SetRows(3, 0, 0, 3, 3)
grid.SetColumns(30, 0, 30) grid.SetColumns(30, 0, 30)
@ -22,55 +34,95 @@ func main() {
board := cview.NewTable() board := cview.NewTable()
board.SetBorders(true) board.SetBorders(true)
cols, rows := 4, 2
for r := 0; r < rows; r++ {
for c := 0; c < cols; c++ {
color := tcell.ColorWhite.TrueColor()
if c < 1 || r < 1 {
color = tcell.ColorYellow.TrueColor()
}
cell := cview.NewTableCell("test")
cell.SetTextColor(color)
cell.SetAlign(cview.AlignCenter)
board.SetCell(r, c, cell)
}
}
rows = 1
hand := cview.NewTable() hand := cview.NewTable()
hand.SetBorders(true) hand.SetBorders(true)
for r := 0; r < rows; r++ { playerside := cview.NewTextView()
for c := 0; c < cols; c++ { playerside.SetText("Game has not started")
color := tcell.ColorWhite.TrueColor() playerside.SetTextAlign(cview.AlignCenter)
if c < 1 || r < 1 {
color = tcell.ColorYellow.TrueColor()
}
cell := cview.NewTableCell("test")
cell.SetTextColor(color)
cell.SetAlign(cview.AlignCenter)
hand.SetCell(r, c, cell)
}
}
playerside := newPrimitive("Player")
oppside := newPrimitive("Opponent")
commandinput := cview.NewInputField() commandinput := cview.NewInputField()
commandoutput := cview.NewTextView() commandoutput := cview.NewTextView()
commandinput.SetDoneFunc(func(key tcell.Key) { commandinput.SetDoneFunc(func(key tcell.Key) {
inputchan <- commandinput.GetText() container.Input <- commandinput.GetText()
commandinput.SetText("") commandinput.SetText("")
}) })
commandoutput.SetChangedFunc(func() { commandoutput.SetChangedFunc(func() {
app.Draw() app.Draw()
}) })
playerside.SetChangedFunc(func() {
app.Draw()
})
go func() {
for {
select {
case <-container.Updated:
playerside.Clear()
var pv string
if container.State != nil && container.State.Player != nil {
ct := "Noone"
if container.State.CurrentTurn == game.SentinalID {
ct = "Sentinal"
} else if container.State.CurrentTurn == game.ScourgeID {
ct = "Scourge"
}
pv = fmt.Sprintf("Your Life: %v\nEnemy Life: %v\nEnemy Hand size: %v\nEnemy Deck Size: %v\n\nCT:%v CD: %v, HD %v, Status: %v\n", container.State.Player.Life, container.State.EnemyLife, container.State.EnemyHandSize, container.State.EnemyDeckSize, ct, container.State.CanDraw, container.State.HasDrawn, container.State.Status)
} else {
pv = fmt.Sprintf("%v", "Awaiting player info")
}
fmt.Fprintf(playerside, "%v", pv)
for c := 0; c < 4; c++ {
color := tcell.ColorWhite.TrueColor()
be := "_"
if container.State != nil && container.State.Board != nil {
be = container.State.Board.Sentinal[c].String()
}
cell := cview.NewTableCell(be)
cell.SetTextColor(color)
cell.SetAlign(cview.AlignCenter)
board.SetCell(0, c, cell)
}
for c := 0; c < 4; c++ {
color := tcell.ColorWhite.TrueColor()
be := "_"
if container.State != nil && container.State.Board != nil {
be = container.State.Board.Scourge[c].String()
}
cell := cview.NewTableCell(be)
cell.SetTextColor(color)
cell.SetAlign(cview.AlignCenter)
board.SetCell(1, c, cell)
}
cols := 0
if container.State != nil && container.State.Player != nil && container.State.Player.Hand != nil {
cols = len(container.State.Player.Hand)
}
for c := 0; c < cols; c++ {
color := tcell.ColorWhite.TrueColor()
ce := "_"
if container.State != nil && container.State.Player != nil && container.State.Player.Hand != nil {
ce = container.State.Player.Hand[c].String()
}
cell := cview.NewTableCell(ce)
cell.SetTextColor(color)
cell.SetAlign(cview.AlignCenter)
hand.SetCell(0, c, cell)
}
app.Draw()
case o := <-container.Output:
commandoutput.Clear()
fmt.Fprintf(commandoutput, "Result: %v", o)
}
}
}()
grid.AddItem(playerside, 1, 0, 2, 1, 0, 100, false) grid.AddItem(playerside, 1, 0, 2, 1, 0, 100, false)
grid.AddItem(board, 1, 1, 1, 1, 0, 100, false) grid.AddItem(board, 1, 1, 1, 1, 0, 100, false)
grid.AddItem(hand, 2, 1, 1, 1, 0, 100, false) grid.AddItem(hand, 2, 1, 1, 1, 0, 100, false)
grid.AddItem(oppside, 1, 2, 2, 1, 0, 100, false)
grid.AddItem(commandinput, 3, 0, 1, 3, 0, 0, true) grid.AddItem(commandinput, 3, 0, 1, 3, 0, 0, true)
grid.AddItem(commandoutput, 4, 0, 1, 3, 0, 0, false) grid.AddItem(commandoutput, 4, 0, 1, 3, 0, 0, false)
go backend(inputchan, commandoutput) container.Updated <- true
go backend(container)
app.SetRoot(grid, true) app.SetRoot(grid, true)
if err := app.Run(); err != nil { if err := app.Run(); err != nil {
panic(err) panic(err)

2
go.mod
View File

@ -3,6 +3,8 @@ module git.saintnet.tech/stryan/snengame
go 1.16 go 1.16
require ( require (
code.rocketnine.space/tslocum/cview v1.5.6 // indirect
github.com/gdamore/tcell/v2 v2.4.0 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
) )

34
go.sum
View File

@ -1,4 +1,38 @@
code.rocketnine.space/tslocum/cbind v0.1.5 h1:i6NkeLLNPNMS4NWNi3302Ay3zSU6MrqOT+yJskiodxE=
code.rocketnine.space/tslocum/cbind v0.1.5/go.mod h1:LtfqJTzM7qhg88nAvNhx+VnTjZ0SXBJtxBObbfBWo/M=
code.rocketnine.space/tslocum/cview v1.5.6 h1:W0HJFIIgly3LzYoTitZIIaYDDqW0u/qmA0B6jWzw6R0=
code.rocketnine.space/tslocum/cview v1.5.6/go.mod h1:RogJMObbKuGiP8+9WsFsHpPeQQqgkCXgvTLxh7IH5eE=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.2.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/gdamore/tcell/v2 v2.3.11 h1:ECO6WqHGbKZ3HrSL7bG/zArMCmLaNr5vcjjMVnLHpzc=
github.com/gdamore/tcell/v2 v2.3.11/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM=
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -148,10 +148,29 @@ func (c *Coordinator) Coordinate(cmd *SessionCommand) *SessionCommandResult {
func MatchWatcher(m *Session) { func MatchWatcher(m *Session) {
ticker := time.NewTicker(1 * time.Second) ticker := time.NewTicker(1 * time.Second)
old_turn := -1 old_turn := -1
var old_board *game.Board
old_sen_hand := -1
old_sco_hand := -1
old_sen_life := -1
old_sco_life := -1
sen_ready := false
sco_ready := false
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
if m.Active && m.Game != nil { if m.Active && m.Game != nil {
if m.Game.Status == game.StatusLobby && !sen_ready && m.Game.SentinalPlayer.Ready {
for _, v := range m.Broadcasts {
v <- SessionRespBroadcastSenReady
}
sen_ready = true
}
if m.Game.Status == game.StatusLobby && !sco_ready && m.Game.ScourgePlayer.Ready {
for _, v := range m.Broadcasts {
v <- SessionRespBroadcastScoReady
}
sco_ready = true
}
if m.Game.Status == game.StatusSentinalWin { if m.Game.Status == game.StatusSentinalWin {
for _, v := range m.Broadcasts { for _, v := range m.Broadcasts {
v <- SessionRespBroadcastSenWin v <- SessionRespBroadcastSenWin
@ -162,6 +181,33 @@ func MatchWatcher(m *Session) {
v <- SessionRespBroadcastScoWin v <- SessionRespBroadcastScoWin
} }
} }
if m.p1 == uuid.Nil && sen_ready {
for _, v := range m.Broadcasts {
v <- SessionRespBroadcastSenLeft
}
sen_ready = false
}
if m.p2 == uuid.Nil && sco_ready {
for _, v := range m.Broadcasts {
v <- SessionRespBroadcastScoLeft
}
sco_ready = false
}
if old_board == nil || old_board.Sentinal != m.Game.GameBoard.Sentinal || old_board.Scourge != m.Game.GameBoard.Scourge || old_sen_hand != len(m.Game.SentinalPlayer.Hand) || old_sco_hand != len(m.Game.ScourgePlayer.Hand) || old_sen_life != m.Game.SentinalPlayer.Life || old_sco_life != m.Game.ScourgePlayer.Life {
if old_board == nil {
old_board = m.Game.GameBoard
} else {
old_board.Sentinal = m.Game.GameBoard.Sentinal
old_board.Scourge = m.Game.GameBoard.Scourge
}
old_sen_hand = len(m.Game.SentinalPlayer.Hand)
old_sco_hand = len(m.Game.ScourgePlayer.Hand)
old_sen_life = m.Game.SentinalPlayer.Life
old_sco_life = m.Game.ScourgePlayer.Life
for _, v := range m.Broadcasts {
v <- SessionRespBroadcastUpdate
}
}
if old_turn != m.Game.CurrentTurn { if old_turn != m.Game.CurrentTurn {
old_turn = m.Game.CurrentTurn old_turn = m.Game.CurrentTurn
if old_turn == game.SentinalID { if old_turn == game.SentinalID {

View File

@ -30,6 +30,13 @@ const (
SessionRespBroadcastScoTrun = "Scourge turn" SessionRespBroadcastScoTrun = "Scourge turn"
SessionRespBroadcastSenWin = "Sentinal wins" SessionRespBroadcastSenWin = "Sentinal wins"
SessionRespBroadcastScoWin = "Scourge wins" SessionRespBroadcastScoWin = "Scourge wins"
SessionRespBroadcastUpdate = "update"
SessionRespBroadcastSenJoin = "Sentinal joined"
SessionRespBroadcastScoJoin = "Scourge joined"
SessionRespBroadcastSenReady = "Sentinal player is ready"
SessionRespBroadcastScoReady = "Scourge player is ready"
SessionRespBroadcastSenLeft = "Sentinal player has left"
SessionRespBroadcastScoLeft = "Scourge player has left"
SessionRespBroadcastNone = "" SessionRespBroadcastNone = ""
) )
@ -61,11 +68,17 @@ func (s *Session) Join(id uuid.UUID) SessionResp {
if s.p1 == uuid.Nil { if s.p1 == uuid.Nil {
s.p1 = id s.p1 = id
s.pMap[id] = game.SentinalID s.pMap[id] = game.SentinalID
for _, v := range s.Broadcasts {
v <- SessionRespBroadcastSenJoin
}
s.Broadcasts[id] = make(chan SessionResp) s.Broadcasts[id] = make(chan SessionResp)
return SessionRespJoined1 return SessionRespJoined1
} else if s.p2 == uuid.Nil { } else if s.p2 == uuid.Nil {
s.p2 = id s.p2 = id
s.pMap[id] = game.ScourgeID s.pMap[id] = game.ScourgeID
for _, v := range s.Broadcasts {
v <- SessionRespBroadcastScoJoin
}
s.Broadcasts[id] = make(chan SessionResp) s.Broadcasts[id] = make(chan SessionResp)
return SessionRespJoined2 return SessionRespJoined2
} else { } else {
@ -79,6 +92,7 @@ func (s *Session) Leave(id uuid.UUID) {
} else if id == s.p2 { } else if id == s.p2 {
s.p2 = uuid.Nil s.p2 = uuid.Nil
} }
delete(s.Broadcasts, id)
if s.p1 == uuid.Nil && s.p2 == uuid.Nil { if s.p1 == uuid.Nil && s.p2 == uuid.Nil {
s.Game = nil s.Game = nil
} else if s.Game.Status != game.StatusDraw || s.Game.Status != game.StatusScourgeWin || s.Game.Status != game.StatusSentinalWin { } else if s.Game.Status != game.StatusDraw || s.Game.Status != game.StatusScourgeWin || s.Game.Status != game.StatusSentinalWin {

View File

@ -158,18 +158,34 @@ func (g *Game) PlayerStateAct(id int, cmd string) *GameView {
return NewView(id, g) return NewView(id, g)
case "b": case "b":
//begin game //begin game
if g.SentinalPlayer.Ready && g.ScourgePlayer.Ready && g.Status == StatusLobby {
g.Status = StatusReady g.Status = StatusReady
//TODO check for ready on both accounts first if id == SentinalID {
g.SentinalPlayer.Hand = g.SentinalDeck.Cards[len(g.SentinalDeck.Cards)-5 : len(g.SentinalDeck.Cards)] g.SentinalPlayer.Hand = g.SentinalDeck.Cards[len(g.SentinalDeck.Cards)-5 : len(g.SentinalDeck.Cards)]
g.SentinalDeck.Cards = g.SentinalDeck.Cards[0 : len(g.SentinalDeck.Cards)-5] g.SentinalDeck.Cards = g.SentinalDeck.Cards[0 : len(g.SentinalDeck.Cards)-5]
g.ScourgePlayer.Hand = g.ScourgeDeck.Cards[len(g.ScourgeDeck.Cards)-6 : len(g.ScourgeDeck.Cards)]
g.ScourgeDeck.Cards = g.ScourgeDeck.Cards[0 : len(g.ScourgeDeck.Cards)-6]
g.CurrentTurn = SentinalID
} else {
g.SentinalPlayer.Hand = g.SentinalDeck.Cards[len(g.SentinalDeck.Cards)-6 : len(g.SentinalDeck.Cards)]
g.SentinalDeck.Cards = g.SentinalDeck.Cards[0 : len(g.SentinalDeck.Cards)-6]
g.ScourgePlayer.Hand = g.ScourgeDeck.Cards[len(g.ScourgeDeck.Cards)-5 : len(g.ScourgeDeck.Cards)] g.ScourgePlayer.Hand = g.ScourgeDeck.Cards[len(g.ScourgeDeck.Cards)-5 : len(g.ScourgeDeck.Cards)]
g.ScourgeDeck.Cards = g.ScourgeDeck.Cards[0 : len(g.ScourgeDeck.Cards)-5] g.ScourgeDeck.Cards = g.ScourgeDeck.Cards[0 : len(g.ScourgeDeck.Cards)-5]
g.CurrentTurn = ScourgeID
}
} else {
if id == SentinalID {
g.SentinalPlayer.Ready = true
} else if id == ScourgeID {
g.ScourgePlayer.Ready = true
}
}
case "s": case "s":
//start turn //start turn
if g.Status == StatusReady { //first turn if g.Status == StatusReady { //first turn
g.Status = StatusPlaying g.Status = StatusPlaying
g.CurrentTurn = id
} }
g.CanDraw = true g.CanDraw = true
g.HasDrawn = false g.HasDrawn = false

View File

@ -5,6 +5,7 @@ type Player struct {
Id int `json:"id"` Id int `json:"id"`
Hand []*Card `json:"hand"` Hand []*Card `json:"hand"`
Life int `json:"life"` Life int `json:"life"`
Ready bool `json:"ready"`
} }
func NewPlayer(name string, id int) *Player { func NewPlayer(name string, id int) *Player {
@ -13,5 +14,6 @@ func NewPlayer(name string, id int) *Player {
Id: id, Id: id,
Hand: []*Card{}, Hand: []*Card{},
Life: 3, Life: 3,
Ready: false,
} }
} }