begin tui client
This commit is contained in:
parent
d8777b0dda
commit
379719a2e2
225
cmd/client2/backend.go
Normal file
225
cmd/client2/backend.go
Normal file
@ -0,0 +1,225 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"code.rocketnine.space/tslocum/cview"
|
||||
"git.saintnet.tech/stryan/snengame/internal/coordinator"
|
||||
"git.saintnet.tech/stryan/snengame/internal/game"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
var done chan interface{}
|
||||
var interrupt chan os.Signal
|
||||
var pid int
|
||||
var matchID uuid.UUID
|
||||
|
||||
func receiveHandler(connection *websocket.Conn, output chan string) {
|
||||
defer close(done)
|
||||
for {
|
||||
var resp coordinator.SessionCommandResult
|
||||
err := connection.ReadJSON(&resp)
|
||||
if err != nil {
|
||||
log.Println("Error in receive:", err)
|
||||
}
|
||||
switch resp.Result {
|
||||
case coordinator.SessionRespJoined1:
|
||||
pid = game.SentinalID
|
||||
output <- "joined as sentinal"
|
||||
case coordinator.SessionRespJoined2:
|
||||
pid = game.ScourgeID
|
||||
output <- "joined as scourge"
|
||||
case coordinator.SessionRespFound:
|
||||
matchID = resp.MatchID
|
||||
output <- "game found"
|
||||
case coordinator.SessionRespPlayed:
|
||||
if resp.GameResult != nil {
|
||||
output <- "played succesfully"
|
||||
switch resp.GameResult.ResultType {
|
||||
case game.ActCmd:
|
||||
output <- resp.GameResult.ActionResult.String()
|
||||
case game.StateCmd:
|
||||
output <- resp.GameResult.StateResult.String()
|
||||
case game.DebugCmd:
|
||||
output <- resp.GameResult.DebugResult.String()
|
||||
}
|
||||
} else {
|
||||
output <- "error playing"
|
||||
}
|
||||
case coordinator.SessionRespLeft:
|
||||
output <- "game left"
|
||||
break
|
||||
case coordinator.SessionRespBroadcastSenTurn:
|
||||
output <- "Sentinal may take their turn"
|
||||
case coordinator.SessionRespBroadcastScoTrun:
|
||||
output <- "Scourge may take their turn"
|
||||
case coordinator.SessionRespBroadcastSenWin:
|
||||
output <- "Sentinal wins!"
|
||||
case coordinator.SessionRespBroadcastScoWin:
|
||||
output <- "Scourge wins!"
|
||||
case coordinator.SessionRespBroadcastNone:
|
||||
|
||||
case coordinator.SessionRespError:
|
||||
output <- "generic error"
|
||||
|
||||
default:
|
||||
output <- "Received a server response we don't know how to handle"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func backend(input chan string, outputview *cview.TextView) {
|
||||
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
|
||||
cmd := make(chan coordinator.SessionCommand)
|
||||
output := make(chan string)
|
||||
|
||||
signal.Notify(interrupt, os.Interrupt) // Notify the interrupt channel for SIGINT
|
||||
hostname := flag.String("host", "localhost", "server hostname to connect to")
|
||||
port := flag.Int("port", 7636, "port to connect to")
|
||||
|
||||
flag.Parse()
|
||||
port_s := strconv.Itoa(*port)
|
||||
socketUrl := "ws://" + *hostname + ":" + port_s + "/ws"
|
||||
conn, _, err := websocket.DefaultDialer.Dial(socketUrl, nil)
|
||||
id := uuid.New()
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("Error connecting to Websocket Server:", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
go receiveHandler(conn, output)
|
||||
go GetCommand(id, cmd, input)
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
// Our main loop for the client
|
||||
// We send our relevant packets here
|
||||
for {
|
||||
var c coordinator.SessionCommand
|
||||
var o string
|
||||
select {
|
||||
case c = <-cmd:
|
||||
err := conn.WriteJSON(c)
|
||||
if err != nil {
|
||||
log.Println("Error during writing to websocket:", err)
|
||||
return
|
||||
}
|
||||
if c.Command == coordinator.SessionCmdLeave {
|
||||
break
|
||||
}
|
||||
case o = <-output:
|
||||
outputview.SetText(o)
|
||||
case <-interrupt:
|
||||
// We received a SIGINT (Ctrl + C). Terminate gracefully...
|
||||
log.Println("Received SIGINT interrupt signal. Closing all pending connections")
|
||||
|
||||
// Close our websocket connection
|
||||
err := conn.WriteJSON(coordinator.SessionCommand{
|
||||
ID: id,
|
||||
Command: coordinator.SessionCmdLeave,
|
||||
})
|
||||
if err != nil {
|
||||
log.Println("Error during closing websocket:", err)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
log.Println("Receiver Channel Closed! Exiting....")
|
||||
case <-time.After(time.Duration(1) * time.Second):
|
||||
log.Println("Timeout in closing receiving channel. Exiting....")
|
||||
}
|
||||
return
|
||||
case <-ticker.C:
|
||||
if matchID != uuid.Nil {
|
||||
err := conn.WriteJSON(coordinator.SessionCommand{
|
||||
ID: id,
|
||||
MatchID: matchID,
|
||||
Command: coordinator.SessionCmdPoll,
|
||||
})
|
||||
if err != nil {
|
||||
log.Println("Error writing to websocket:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand, inputchan chan string) {
|
||||
for {
|
||||
var cmd string
|
||||
var t int
|
||||
input := <-inputchan
|
||||
input_s := strings.Split(input, " ")
|
||||
t, err := strconv.Atoi(input_s[0])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
cmd = trimFirstRune(input)
|
||||
|
||||
cmd = strings.TrimSpace(cmd)
|
||||
switch t {
|
||||
case 0:
|
||||
//session
|
||||
switch coordinator.SessionCmd(cmd) {
|
||||
case coordinator.SessionCmdQuery:
|
||||
resp <- coordinator.SessionCommand{
|
||||
ID: uid,
|
||||
Command: coordinator.SessionCmdQuery,
|
||||
}
|
||||
case coordinator.SessionCmdJoin:
|
||||
resp <- coordinator.SessionCommand{
|
||||
ID: uid,
|
||||
MatchID: matchID,
|
||||
Command: coordinator.SessionCmdJoin,
|
||||
}
|
||||
case coordinator.SessionCmdLeave:
|
||||
resp <- coordinator.SessionCommand{
|
||||
ID: uid,
|
||||
MatchID: matchID,
|
||||
Command: coordinator.SessionCmdLeave,
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
case 1:
|
||||
//state
|
||||
resp <- coordinator.SessionCommand{
|
||||
ID: uid,
|
||||
MatchID: matchID,
|
||||
Command: coordinator.SessionCmdPlay,
|
||||
GameCommand: &game.Command{
|
||||
PlayerID: pid,
|
||||
Type: game.StateCmd,
|
||||
Cmd: cmd,
|
||||
},
|
||||
}
|
||||
case 2:
|
||||
//action
|
||||
resp <- coordinator.SessionCommand{
|
||||
ID: uid,
|
||||
MatchID: matchID,
|
||||
Command: coordinator.SessionCmdPlay,
|
||||
GameCommand: &game.Command{
|
||||
PlayerID: pid,
|
||||
Type: game.ActCmd,
|
||||
Cmd: cmd,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func trimFirstRune(s string) string {
|
||||
_, i := utf8.DecodeRuneInString(s)
|
||||
return s[i:]
|
||||
}
|
78
cmd/client2/main.go
Normal file
78
cmd/client2/main.go
Normal file
@ -0,0 +1,78 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"code.rocketnine.space/tslocum/cview"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := cview.NewApplication()
|
||||
app.EnableMouse(true)
|
||||
newPrimitive := func(text string) cview.Primitive {
|
||||
tv := cview.NewTextView()
|
||||
tv.SetTextAlign(cview.AlignCenter)
|
||||
tv.SetText(text)
|
||||
return tv
|
||||
}
|
||||
inputchan := make(chan string)
|
||||
grid := cview.NewGrid()
|
||||
grid.SetRows(3, 0, 0, 3, 3)
|
||||
grid.SetColumns(30, 0, 30)
|
||||
grid.SetBorders(true)
|
||||
|
||||
board := cview.NewTable()
|
||||
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.SetBorders(true)
|
||||
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)
|
||||
hand.SetCell(r, c, cell)
|
||||
}
|
||||
}
|
||||
|
||||
playerside := newPrimitive("Player")
|
||||
oppside := newPrimitive("Opponent")
|
||||
commandinput := cview.NewInputField()
|
||||
commandoutput := cview.NewTextView()
|
||||
commandinput.SetDoneFunc(func(key tcell.Key) {
|
||||
inputchan <- commandinput.GetText()
|
||||
commandinput.SetText("")
|
||||
})
|
||||
commandoutput.SetChangedFunc(func() {
|
||||
app.Draw()
|
||||
})
|
||||
|
||||
grid.AddItem(playerside, 1, 0, 2, 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(oppside, 1, 2, 2, 1, 0, 100, false)
|
||||
grid.AddItem(commandinput, 3, 0, 1, 3, 0, 0, true)
|
||||
grid.AddItem(commandoutput, 4, 0, 1, 3, 0, 0, false)
|
||||
go backend(inputchan, commandoutput)
|
||||
|
||||
app.SetRoot(grid, true)
|
||||
if err := app.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user