mirror of
https://github.com/tiennm99/noitu.git
synced 2026-10-12 16:15:29 +00:00
room.go was 1919 lines with every room concern in one file. Pure moves, no signature or behaviour changes: room.go keeps the struct, its constructor, the input loop and the small seat-authority helpers; room_inputs.go the message types; room_lobby.go seating and the lobby between games; room_game.go everything that touches a running game; room_presence.go the reconnect window and resume; room_chat.go the room's own conversation; bot_board.go the bot's frozen view of a position. session.go was two unrelated halves in one 762-line file: the socket (session.go, kept) and the protocol (dispatch.go, new) — dispatch and the handshake/resume flow it routes into. Verified with go build, go vet, golangci-lint and go test -race, and by counting: every one of the 89 room.go and 27 session.go top-level declarations appears in the split exactly once.
126 lines
3.9 KiB
Go
126 lines
3.9 KiB
Go
package wsapi
|
|
|
|
import (
|
|
"github.com/tiennm99dev/noitu/server/internal/bot"
|
|
"github.com/tiennm99dev/noitu/server/internal/game"
|
|
)
|
|
|
|
// Room input messages. Everything that can change a room or a game arrives
|
|
// as one of these on room.inputs, which is what makes the engine safe
|
|
// without a lock: the room goroutine is its only reader.
|
|
|
|
// createInput and startBotInput seat the first player. Seating is a message
|
|
// rather than a direct write so that every touch of room state — seats and
|
|
// engine alike — happens on the room goroutine, which makes the ownership
|
|
// invariant provable by reading run() rather than by reasoning about which
|
|
// writes happened before `go r.run()`.
|
|
type createInput struct {
|
|
sess *session
|
|
// autoStart marks a room a quick match opened rather than a player asking
|
|
// for a code: once both seats are filled and connected, the room begins
|
|
// its own first game instead of waiting on readiness and StartGame.
|
|
autoStart bool
|
|
}
|
|
|
|
type startBotInput struct {
|
|
sess *session
|
|
difficulty bot.Difficulty
|
|
}
|
|
|
|
type joinInput struct {
|
|
sess *session
|
|
}
|
|
|
|
// submitInput and resignInput carry the connection that sent them, not just
|
|
// the seat it claims. A room code is a shared secret — it is pasted into group
|
|
// chats by design — so holding one must not be enough to act as a player who
|
|
// is already seated.
|
|
type submitInput struct {
|
|
sess *session
|
|
player game.PlayerID
|
|
word string
|
|
turnSeq uint32
|
|
}
|
|
|
|
// lobbyAction is one thing a player does to the room rather than to a game.
|
|
type lobbyAction uint8
|
|
|
|
const (
|
|
lobbyReady lobbyAction = iota
|
|
lobbyStart
|
|
lobbyKick
|
|
lobbyLeave
|
|
)
|
|
|
|
// lobbyInput is one lobby action. They share a type because they share every
|
|
// authorization step — the seat, the room's mode, and whether a game is
|
|
// running — and splitting them would mean four copies of those checks.
|
|
type lobbyInput struct {
|
|
sess *session
|
|
player game.PlayerID
|
|
action lobbyAction
|
|
// ready is the value a lobbyReady is setting. Explicit rather than a
|
|
// toggle: a toggle applied to a state the client is a frame behind on sets
|
|
// the opposite of what the player clicked.
|
|
ready bool
|
|
// target is the seat a lobbyKick names. A room holds up to four people, so
|
|
// "the other one" stopped being an answer.
|
|
target game.PlayerID
|
|
}
|
|
|
|
// chatInput is one line of text from a seated player. It carries the
|
|
// connection, not just the seat it claims, for the same reason submitInput
|
|
// does: a room code is a shared secret, and a connection the room has retired
|
|
// must not be able to speak as the seat it used to hold.
|
|
type chatInput struct {
|
|
sess *session
|
|
player game.PlayerID
|
|
text string
|
|
}
|
|
|
|
type resignInput struct {
|
|
sess *session
|
|
player game.PlayerID
|
|
}
|
|
|
|
// claimDeadEndInput is the player to act saying the syllable has no answer
|
|
// left. Carries the connection, not just the claimed seat, for the same
|
|
// reason resignInput does.
|
|
type claimDeadEndInput struct {
|
|
sess *session
|
|
player game.PlayerID
|
|
}
|
|
|
|
// reportWordInput is a word the session has already validated as reportable —
|
|
// long enough, and within its own per-session cap — waiting only on the room
|
|
// for the context a report is logged with: the syllable in play, if any.
|
|
type reportWordInput struct {
|
|
sess *session
|
|
word string
|
|
}
|
|
|
|
type disconnectInput struct {
|
|
player game.PlayerID
|
|
// sess identifies which connection dropped. A player who already
|
|
// reconnected has a different session, and that stale notice must not
|
|
// evict the seat the new connection just took.
|
|
sess *session
|
|
}
|
|
|
|
type resumeInput struct {
|
|
player game.PlayerID
|
|
sess *session
|
|
// prior is the connection being replaced. The room retires it only once it
|
|
// has decided the resume is allowed, because closing it on a refusal would
|
|
// end the very game the client was trying to rejoin.
|
|
prior *session
|
|
}
|
|
|
|
type botMoveInput struct {
|
|
word string
|
|
err error
|
|
// turnSeq the bot was thinking about. If the game moved on — a resign
|
|
// landed while it thought — the move is stale and dropped.
|
|
turnSeq uint32
|
|
}
|