snengame/cmd/client/main.go

247 lines
6.2 KiB
Go
Raw Permalink Normal View History

2021-07-22 18:19:21 -04:00
package main
import (
"bufio"
2021-07-25 15:41:56 -04:00
"flag"
2021-07-22 18:19:21 -04:00
"fmt"
"log"
"os"
"os/signal"
2021-07-25 15:41:56 -04:00
"strconv"
2021-07-22 18:19:21 -04:00
"strings"
"time"
"unicode/utf8"
2021-07-22 18:19:21 -04:00
"git.saintnet.tech/stryan/snengame/internal/coordinator"
"git.saintnet.tech/stryan/snengame/internal/game"
2021-07-22 18:19:21 -04:00
"github.com/google/uuid"
"github.com/gorilla/websocket"
)
var done chan interface{}
var interrupt chan os.Signal
var pid int
var matchID uuid.UUID
2021-07-22 18:19:21 -04:00
2021-07-23 17:42:12 -04:00
func receiveHandler(connection *websocket.Conn, output chan string) {
2021-07-22 18:19:21 -04:00
defer close(done)
for {
var resp coordinator.SessionCommandResult
err := connection.ReadJSON(&resp)
if err != nil {
log.Println("Error in receive:", err)
}
2021-07-26 13:02:00 -04:00
switch resp.Result {
case coordinator.SessionRespJoined1:
pid = game.SentinalID
2021-07-23 17:42:12 -04:00
output <- "joined as sentinal"
2021-07-26 13:02:00 -04:00
case coordinator.SessionRespJoined2:
pid = game.ScourgeID
2021-07-23 17:42:12 -04:00
output <- "joined as scourge"
2021-07-26 13:02:00 -04:00
case coordinator.SessionRespFound:
matchID = resp.MatchID
2021-07-23 17:42:12 -04:00
output <- "game found"
2021-09-23 13:04:34 -04:00
case coordinator.SessionRespJoinError:
output <- "error joining game"
2021-07-26 13:02:00 -04:00
case coordinator.SessionRespPlayed:
if resp.GameResult != nil {
2021-07-26 13:02:00 -04:00
output <- "played succesfully"
switch resp.GameResult.ResultType {
case game.ActCmd:
2021-07-23 17:42:12 -04:00
output <- resp.GameResult.ActionResult.String()
case game.StateCmd:
2021-07-23 17:42:12 -04:00
output <- resp.GameResult.StateResult.String()
case game.DebugCmd:
2021-07-23 17:42:12 -04:00
output <- resp.GameResult.DebugResult.String()
}
2021-07-26 13:02:00 -04:00
} else {
output <- "error playing"
}
2021-07-26 13:02:00 -04:00
case coordinator.SessionRespLeft:
2021-07-23 17:42:12 -04:00
output <- "game left"
break
2021-07-26 13:02:00 -04:00
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!"
2021-07-29 14:48:36 -04:00
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"
2021-07-26 13:02:00 -04:00
case coordinator.SessionRespBroadcastNone:
case coordinator.SessionRespError:
output <- "generic error"
default:
output <- "Received a server response we don't know how to handle"
}
2021-07-22 18:19:21 -04:00
}
}
func main() {
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)
2021-07-23 17:42:12 -04:00
output := make(chan string)
2021-07-22 18:19:21 -04:00
signal.Notify(interrupt, os.Interrupt) // Notify the interrupt channel for SIGINT
2021-07-25 15:41:56 -04:00
hostname := flag.String("host", "localhost", "server hostname to connect to")
port := flag.Int("port", 7636, "port to connect to")
2021-07-22 18:19:21 -04:00
2021-07-25 15:41:56 -04:00
flag.Parse()
port_s := strconv.Itoa(*port)
socketUrl := "ws://" + *hostname + ":" + port_s + "/ws"
2021-07-22 18:19:21 -04:00
conn, _, err := websocket.DefaultDialer.Dial(socketUrl, nil)
id := uuid.New()
if err != nil {
log.Fatal("Error connecting to Websocket Server:", err)
}
defer conn.Close()
2021-07-23 17:42:12 -04:00
go receiveHandler(conn, output)
2021-07-22 18:19:21 -04:00
go GetCommand(id, cmd)
2021-07-26 13:02:00 -04:00
ticker := time.NewTicker(1 * time.Second)
2021-07-22 18:19:21 -04:00
// Our main loop for the client
// We send our relevant packets here
for {
var c coordinator.SessionCommand
2021-07-23 17:42:12 -04:00
var o string
2021-07-22 18:19:21 -04:00
select {
case c = <-cmd:
err := conn.WriteJSON(c)
if err != nil {
log.Println("Error during writing to websocket:", err)
return
}
2021-07-26 13:02:00 -04:00
if c.Command == coordinator.SessionCmdLeave {
break
}
2021-07-23 17:42:12 -04:00
case o = <-output:
fmt.Println(o)
2021-07-22 18:19:21 -04:00
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
2021-07-26 13:02:00 -04:00
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
}
}
2021-07-22 18:19:21 -04:00
}
}
}
func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand) {
for {
var cmd string
var t int
fmt.Print("> ")
_, err := fmt.Scanf("%d", &t)
if err != nil {
log.Println(err)
}
if t == -1 {
panic("quitting")
}
cmd, err = bufio.NewReader(os.Stdin).ReadString('\n')
2021-07-22 18:19:21 -04:00
if err != nil {
log.Println(err)
}
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,
2021-07-22 18:19:21 -04:00
Command: coordinator.SessionCmdJoin,
}
case coordinator.SessionCmdLeave:
resp <- coordinator.SessionCommand{
ID: uid,
MatchID: matchID,
2021-07-22 18:19:21 -04:00
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,
},
}
2021-07-22 18:19:21 -04:00
}
2021-07-22 18:19:21 -04:00
}
}
func trimFirstRune(s string) string {
_, i := utf8.DecodeRuneInString(s)
return s[i:]
}