Files
back-hokm/internal/ws/protocol.go
T

167 lines
5.7 KiB
Go

package ws
import "hakemsho/internal/game"
// inboundMsg پیام دریافتی از کلاینت.
type inboundMsg struct {
Type string `json:"type"` // join_queue | choose_trump | play_card | leave | create_table | join_table | start_table | leave_table
Mode string `json:"mode"` // برای join_queue
Tier string `json:"tier"` // برای join_queue: نوع میز (beginner/pro/...)
Suit string `json:"suit"` // برای choose_trump: hearts|spades|diamonds|clubs
Card string `json:"card"` // برای play_card: مثل "AS"
Code string `json:"code"` // برای join_table: شماره میز خصوصی
Hands int `json:"hands"` // برای start_table: تعداد دستِ بازیِ خصوصی (۳/۵/۷)
Dir int `json:"dir"` // برای rotate_table: جهتِ چرخشِ جایگاه‌ها (+۱/−۱)
}
// lobbyPlayer یک بازیکن در اتاق انتظارِ میز خصوصی.
type lobbyPlayer struct {
Name string `json:"name"`
Host bool `json:"host"`
Seat int `json:"seat"` // جایگاهِ مطلق (۰..۳)
}
// tableLobbyMsg وضعیت اتاق انتظارِ میز خصوصی (دورهمی).
type tableLobbyMsg struct {
Type string `json:"type"` // "table_lobby"
Code string `json:"code"`
Players []lobbyPlayer `json:"players"`
Host bool `json:"host"` // آیا گیرنده میزبان است
YouSeat int `json:"you_seat"` // جایگاهِ مطلقِ گیرنده (برای چیدمانِ صحنه)
Remaining int `json:"remaining"` // باقیمانده‌ی میزهای رایگانِ گیرنده
Unlimited bool `json:"unlimited"`
}
// countdownMsg شمارش معکوس پیش از شروع بازیِ خصوصی.
type countdownMsg struct {
Type string `json:"type"` // "countdown"
Seconds int `json:"seconds"`
}
// tableClosedMsg انحلالِ میز خصوصی پیش از شروع (میزبان خارج شد).
type tableClosedMsg struct {
Type string `json:"type"` // "table_closed"
Reason string `json:"reason"`
}
// PlayerInfo اطلاعات عمومی یک بازیکن سر میز.
type PlayerInfo struct {
Seat int `json:"seat"`
Name string `json:"name"`
Bot bool `json:"bot"`
Connected bool `json:"connected"`
}
// matchedMsg به کلاینت پس از تشکیل میز.
type matchedMsg struct {
Type string `json:"type"` // "matched"
Room string `json:"room"`
Seat int `json:"seat"`
Players []PlayerInfo `json:"players"`
}
// trickView یک کارت روی زمین.
type trickView struct {
Seat int `json:"seat"`
Card string `json:"card"`
}
// stateMsg نمای مجاز بازی برای یک بازیکن خاص.
type stateMsg struct {
Type string `json:"type"` // "state"
Room string `json:"room"`
Phase string `json:"phase"`
YourSeat int `json:"your_seat"`
Hakem int `json:"hakem"`
Turn int `json:"turn"`
Trump string `json:"trump,omitempty"` // فقط پس از انتخاب حکم
TrickDone bool `json:"trick_done"` // دستِ کامل در حال نمایش (بازی ممنوع)
YourHand []string `json:"your_hand"`
HandCounts [4]int `json:"hand_counts"`
Trick []trickView `json:"trick"`
LeadSuit string `json:"lead_suit,omitempty"`
TricksWon [2]int `json:"tricks_won"`
Scores [2]int `json:"scores"`
TargetScore int `json:"target_score"`
TurnTimeoutMs int `json:"turn_timeout_ms"` // مهلتِ نوبتِ انسان (برای شمارنده‌ی کلاینت)
Players []PlayerInfo `json:"players"`
}
// handOverMsg نتیجه یک هَند.
type handOverMsg struct {
Type string `json:"type"` // "hand_over"
WinnerTeam int `json:"winner_team"`
Kot bool `json:"kot"`
HakemKot bool `json:"hakem_kot"`
Points int `json:"points"`
Scores [2]int `json:"scores"`
}
// gameOverMsg پایان بازی.
type gameOverMsg struct {
Type string `json:"type"` // "game_over"
WinnerTeam int `json:"winner_team"`
Scores [2]int `json:"scores"`
}
// errorMsg خطا برای کلاینت.
type errorMsg struct {
Type string `json:"type"` // "error"
Message string `json:"message"`
}
// playerLeftMsg خروج دائمی یک بازیکن (تبدیل به بات).
type playerLeftMsg struct {
Type string `json:"type"` // "player_left"
Seat int `json:"seat"`
}
// playerStatusMsg تغییر وضعیت اتصال یک بازیکن (موقت).
type playerStatusMsg struct {
Type string `json:"type"` // "player_disconnected" | "player_reconnected"
Seat int `json:"seat"`
}
// buildState نمای بازی را برای جایگاه seat می‌سازد (کارت بقیه مخفی می‌ماند).
func buildState(g *game.Game, roomID string, seat int, players []PlayerInfo, turnTimeoutMs int) stateMsg {
hand := g.Hand(seat)
handStr := make([]string, len(hand))
for i, c := range hand {
handStr[i] = c.String()
}
var counts [4]int
for s := 0; s < 4; s++ {
counts[s] = g.HandCount(s)
}
trick := make([]trickView, 0, len(g.Trick))
for _, tc := range g.Trick {
trick = append(trick, trickView{Seat: tc.Seat, Card: tc.Card.String()})
}
st := stateMsg{
Type: "state",
Room: roomID,
Phase: g.Phase.String(),
TrickDone: g.TrickDone,
YourSeat: seat,
Hakem: g.Hakem,
Turn: g.Turn,
YourHand: handStr,
HandCounts: counts,
Trick: trick,
TricksWon: g.TricksWon,
Scores: g.Scores,
TargetScore: g.TargetScore,
Players: players,
}
if g.TrumpChosen {
st.Trump = g.Trump.String()
}
if len(g.Trick) > 0 {
st.LeadSuit = g.LeadSuit.String()
}
return st
}