From daaf81ae931654e20f882fbc6bbc4a02cbfc0273 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 28 Jul 2024 20:09:09 +0900 Subject: feat(backend): partially implement gaming --- backend/game/message.go | 122 ++++++++++++++---------------------------------- 1 file changed, 36 insertions(+), 86 deletions(-) (limited to 'backend/game/message.go') diff --git a/backend/game/message.go b/backend/game/message.go index 7d1a166..23774ce 100644 --- a/backend/game/message.go +++ b/backend/game/message.go @@ -3,102 +3,52 @@ package game import ( "encoding/json" "fmt" -) - -type MessageWithClient struct { - Client *GameClient - Message *Message -} - -type Message struct { - Type string `json:"type"` - Data MessageData `json:"data"` -} - -type MessageData interface{} -type MessageDataConnect struct { -} - -type MessageDataPrepare struct { - Problem string `json:"problem"` -} - -type MessageDataReady struct { -} - -type MessageDataStart struct { - StartTime string `json:"startTime"` -} + "github.com/nsfisis/iosdc-2024-albatross/backend/api" +) -type MessageDataCode struct { - Code string `json:"code"` -} +const ( + playerMessageTypeS2CPrepare = "player:s2c:prepare" + playerMessageTypeS2CStart = "player:s2c:start" + playerMessageTypeC2SEntry = "player:c2s:entry" + playerMessageTypeC2SReady = "player:c2s:ready" +) -type MessageDataScore struct { - Score int `json:"score"` +type playerMessageC2SWithClient struct { + client *playerClient + message playerMessageC2S } -type MessageDataFinish struct { - YourScore *int `json:"yourScore"` - OpponentScore *int `json:"opponentScore"` -} +type playerMessage = api.GamePlayerMessage -type MessageDataWatch struct { - Problem string `json:"problem"` - ScoreA *int `json:"scoreA"` - CodeA string `json:"codeA"` - ScoreB *int `json:"scoreB"` - CodeB string `json:"codeB"` -} +type playerMessageS2C = interface{} +type playerMessageS2CPrepare = api.GamePlayerMessageS2CPrepare +type playerMessageS2CPreparePayload = api.GamePlayerMessageS2CPreparePayload +type playerMessageS2CStart = api.GamePlayerMessageS2CStart +type playerMessageS2CStartPayload = api.GamePlayerMessageS2CStartPayload -func (m *Message) UnmarshalJSON(data []byte) error { - var raw map[string]json.RawMessage - if err := json.Unmarshal(data, &raw); err != nil { - return err - } +type playerMessageC2S = interface{} +type playerMessageC2SEntry = api.GamePlayerMessageC2SEntry +type playerMessageC2SReady = api.GamePlayerMessageC2SReady - if err := json.Unmarshal(raw["type"], &m.Type); err != nil { - return err +func asPlayerMessageC2S(raw map[string]json.RawMessage) (playerMessageC2S, error) { + var typ string + if err := json.Unmarshal(raw["type"], &typ); err != nil { + return nil, err } - var err error - switch m.Type { - case "connect": - var data MessageDataConnect - err = json.Unmarshal(raw["data"], &data) - m.Data = data - case "prepare": - var data MessageDataPrepare - err = json.Unmarshal(raw["data"], &data) - m.Data = data - case "ready": - var data MessageDataReady - err = json.Unmarshal(raw["data"], &data) - m.Data = data - case "start": - var data MessageDataStart - err = json.Unmarshal(raw["data"], &data) - m.Data = data - case "code": - var data MessageDataCode - err = json.Unmarshal(raw["data"], &data) - m.Data = data - case "score": - var data MessageDataScore - err = json.Unmarshal(raw["data"], &data) - m.Data = data - case "finish": - var data MessageDataFinish - err = json.Unmarshal(raw["data"], &data) - m.Data = data - case "watch": - var data MessageDataWatch - err = json.Unmarshal(raw["data"], &data) - m.Data = data + switch typ { + case playerMessageTypeC2SEntry: + return &playerMessageC2SEntry{ + Type: playerMessageTypeC2SEntry, + }, nil + case playerMessageTypeC2SReady: + return &playerMessageC2SReady{ + Type: playerMessageTypeC2SReady, + }, nil default: - err = fmt.Errorf("unknown message type: %s", m.Type) + return nil, fmt.Errorf("unknown message type: %s", typ) } - - return err } + +type watcherMessageS2C = interface{} -- cgit v1.2.3-70-g09d2 From 161d82bee9f9e65680516a9cfd392e0cf297eadf Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 29 Jul 2024 02:58:54 +0900 Subject: feat: handle code and execresult messages --- backend/game/hub.go | 27 +++++++++++++++++++++++++-- backend/game/message.go | 23 +++++++++++++++++++---- frontend/app/components/GolfPlayApp.tsx | 17 ++++++++++++++--- 3 files changed, 58 insertions(+), 9 deletions(-) (limited to 'backend/game/message.go') diff --git a/backend/game/hub.go b/backend/game/hub.go index 170f142..c61f2bb 100644 --- a/backend/game/hub.go +++ b/backend/game/hub.go @@ -68,7 +68,7 @@ func (hub *gameHub) run() { hub.closeWatcherClient(watcher) } case message := <-hub.playerC2SMessages: - switch message.message.(type) { + switch msg := message.message.(type) { case *playerMessageC2SEntry: log.Printf("entry: %v", message.message) // TODO: assert state is waiting_entries @@ -142,11 +142,34 @@ func (hub *gameHub) run() { } hub.game.state = gameStateStarting } + case *playerMessageC2SCode: + // TODO: assert game state is gaming + log.Printf("code: %v", message.message) + code := msg.Data.Code + score := len(code) + message.client.s2cMessages <- &playerMessageS2CExecResult{ + Type: playerMessageTypeS2CExecResult, + Data: playerMessageS2CExecResultPayload{ + Score: &score, + Status: api.Success, + }, + } default: log.Fatalf("unexpected message type: %T", message.message) } case <-ticker.C: - if hub.game.state == gameStateGaming { + if hub.game.state == gameStateStarting { + if time.Now().After(*hub.game.startedAt) { + err := hub.q.UpdateGameState(hub.ctx, db.UpdateGameStateParams{ + GameID: int32(hub.game.gameID), + State: string(gameStateGaming), + }) + if err != nil { + log.Fatalf("failed to set game state: %v", err) + } + hub.game.state = gameStateGaming + } + } else if hub.game.state == gameStateGaming { if time.Now().After(hub.game.startedAt.Add(time.Duration(hub.game.durationSeconds) * time.Second)) { err := hub.q.UpdateGameState(hub.ctx, db.UpdateGameStateParams{ GameID: int32(hub.game.gameID), diff --git a/backend/game/message.go b/backend/game/message.go index 23774ce..9116bde 100644 --- a/backend/game/message.go +++ b/backend/game/message.go @@ -8,10 +8,12 @@ import ( ) const ( - playerMessageTypeS2CPrepare = "player:s2c:prepare" - playerMessageTypeS2CStart = "player:s2c:start" - playerMessageTypeC2SEntry = "player:c2s:entry" - playerMessageTypeC2SReady = "player:c2s:ready" + playerMessageTypeS2CPrepare = "player:s2c:prepare" + playerMessageTypeS2CStart = "player:s2c:start" + playerMessageTypeS2CExecResult = "player:s2c:execreslut" + playerMessageTypeC2SEntry = "player:c2s:entry" + playerMessageTypeC2SReady = "player:c2s:ready" + playerMessageTypeC2SCode = "player:c2s:code" ) type playerMessageC2SWithClient struct { @@ -26,10 +28,14 @@ type playerMessageS2CPrepare = api.GamePlayerMessageS2CPrepare type playerMessageS2CPreparePayload = api.GamePlayerMessageS2CPreparePayload type playerMessageS2CStart = api.GamePlayerMessageS2CStart type playerMessageS2CStartPayload = api.GamePlayerMessageS2CStartPayload +type playerMessageS2CExecResult = api.GamePlayerMessageS2CExecResult +type playerMessageS2CExecResultPayload = api.GamePlayerMessageS2CExecResultPayload type playerMessageC2S = interface{} type playerMessageC2SEntry = api.GamePlayerMessageC2SEntry type playerMessageC2SReady = api.GamePlayerMessageC2SReady +type playerMessageC2SCode = api.GamePlayerMessageC2SCode +type playerMessageC2SCodePayload = api.GamePlayerMessageC2SCodePayload func asPlayerMessageC2S(raw map[string]json.RawMessage) (playerMessageC2S, error) { var typ string @@ -46,6 +52,15 @@ func asPlayerMessageC2S(raw map[string]json.RawMessage) (playerMessageC2S, error return &playerMessageC2SReady{ Type: playerMessageTypeC2SReady, }, nil + case playerMessageTypeC2SCode: + var payload playerMessageC2SCodePayload + if err := json.Unmarshal(raw["data"], &payload); err != nil { + return nil, err + } + return &playerMessageC2SCode{ + Type: playerMessageTypeC2SCode, + Data: payload, + }, nil default: return nil, fmt.Errorf("unknown message type: %s", typ) } diff --git a/frontend/app/components/GolfPlayApp.tsx b/frontend/app/components/GolfPlayApp.tsx index 31d1c44..c6c20d4 100644 --- a/frontend/app/components/GolfPlayApp.tsx +++ b/frontend/app/components/GolfPlayApp.tsx @@ -69,8 +69,11 @@ export default function GolfPlayApp({ game }: { game: Game }) { void setCurrentScore; const onCodeChange = useDebouncedCallback((code: string) => { - void code; - // sendJsonMessage({}); + console.log("player:c2s:code"); + sendJsonMessage({ + type: "player:c2s:code", + data: { code }, + }); }, 1000); if (readyState === ReadyState.UNINSTANTIATED) { @@ -104,6 +107,14 @@ export default function GolfPlayApp({ game }: { game: Game }) { setTimeLeftSeconds(start_at - nowSec); setGameState("starting"); } + } else if (lastJsonMessage.type === "player:s2c:execresult") { + const { score } = lastJsonMessage.data; + if ( + score !== null && + (currentScore === null || score < currentScore) + ) { + setCurrentScore(score); + } } } else { setGameState("waiting"); @@ -111,7 +122,7 @@ export default function GolfPlayApp({ game }: { game: Game }) { sendJsonMessage({ type: "player:c2s:entry" }); } } - }, [sendJsonMessage, lastJsonMessage, readyState, gameState]); + }, [sendJsonMessage, lastJsonMessage, readyState, gameState, currentScore]); if (gameState === "connecting") { return ; -- cgit v1.2.3-70-g09d2