Get desktop application:
View/edit binary Protocol Buffers messages
time to live, in seconds
Used in:
Used in:
Sent when the annotation state of games within a broadcast changes (e.g. a game is claimed or unclaimed). Clients invalidate GetBroadcastGames only.
Sent when a live broadcast's feed data has been updated (scores, new round, etc.) Clients listening on channel-broadcast-{slug} re-fetch broadcast games on receipt.
Used in: , , , ,
Used in:
timestamp is in milliseconds!
these are only loaded by specific endpoints.
Used as response type in: user_service.SocializeService.GetChatsForChannel
Used in: ,
position coordinates, like H8 or G10. Only matters for TILE_PLACEMENT.
tiles that are being played (or exchanged). The `.` character is used for thru, and lowercase characters are used for blanks.
machine_letters is tiles, but in binary.
For CHALLENGE_PLAY events, specifies which word indices to challenge. Indices correspond to the wordsFormed array from the last play. If empty or not set, challenges all words (default/backward compatible).
Used in:
When a Receiver declines a Seeker:
Used in: , ,
Used as request type in: tournament_service.TournamentService.SetDivisionControls
Used as field type in: ,
Used as request type in: tournament_service.TournamentService.SetRoundControls
Used in:
Used as response type in: tournament_service.TournamentService.GetTournament
Used in:
tiles are laid out in row-major form
repeated int32 h_cross_scores = 4; repeated int32 v_cross_scores = 5;
A GameDocument encodes the entire state of a game. It includes a history of events, as well as information about the current state of the bag, timers, etc. It should be possible to recreate an entire omgwords game from a GameDocument state at any given time.
Used as response type in: omgwords_service.GameEventService.GetGameDocument
Used as field type in: , , ,
players are in order of who went first.
The index of the player who won, or -1 if it was a tie.
The board layout is just the name for the layout of the board. It should have a sensible default, if blank.
The letter distribution is the name of the distribution of tiles used for this game. If blank, should default to "english".
gameplay-specific structures: board is the current state of the board
bag is the current tiles in the bag.
The index of the player on turn
Used in:
user_id is an internal, unchangeable user ID, whereas the other two user identifiers might possibly be mutable.
A GameDocumentEvent should eventually replace the GameHistoryRefresher. For now, it will be used for annotated games.
Used in: , , , , , ,
NONE: the game has not yet ended!
TIME: one person timed out (and lost)
WENT_OUT: game ended regularly, with one person having zero tiles on their rack.
6 consecutive zeroes ends the game.
Aborted games are aborted by mutual agreement.
CANCELLED means the game never started. Game start signal was not sent.
FORCE_FORFEIT is a way to force an opponent to take a loss if they left a game early without resigning.
ADJUDICATED means the game ended by external ruling (e.g., league deadline) based on the current score. Unlike FORCE_FORFEIT, this is neutral and can result in a win, loss, or tie for either player.
GameEndedEvent is always sent from the server to both clients.
The winner is not always the highest scoring player; one player can time out. The end_reason should make it clear what happened.
If it was a tie, the winner and loser above can be interchanged.
Time that the game ended
Send the full game history again. This will have rack information in it.
GameEvent is an internal game event, saved in the GameDocument.
Used in: ,
An event will not have all of these; it depends on the type of the event.
words_formed is a list of all words made by this play
The player who played this move is encoded in player_index. This should be the index in GameDocument.players.
For CHALLENGE events, indices of words that were challenged. Empty = challenged all words (backward compatible with existing games).
Used in:
Used in:
Only for international rules (or after 6 zeroes)
Lose a turn for challenging a word incorrectly (only for double challenge)
Issue a challenge
A GameHistoryRefresher is sent to both players when the game starts, and any observers at the time that they begin observing. It can also be sent to a player who reconnects in the middle of a game.
The history contains all the moves, points, as well as the last known racks of each player. It also implicitly contains whose turn it is at the moment, by the events / turns in the history. The front-end is responsible for showing all this information in a nice format. Note: the racks of each player should not be sent to both players, only to observers. The back-end will have to be smart enough to overwrite this information with a blank string before sending it. It might not even be that great of a big deal, as I'm sure people can devise other ways to cheat, but shrug.
These represent how much time each player has remaining on their clock as of the "refresher", in milliseconds. player1 is the player who is listed first in the game history, regardless of whether they went first.
outstanding_event refers to any possible outstanding game meta event that has not yet been responded to or expired.
Time bank remaining for each player in correspondence games, in milliseconds
Initial time bank for correspondence games, in minutes (similar to max_overtime_minutes)
Used as response type in: game_service.GameMetadataService.GetMetadata
Used as field type in:
done - is game done? bool done = 9;
a game index within a round.
Index of the player whose turn it is (0 or 1). Optional for backwards compatibility.
League information
time_bank is the current remaining time bank per player, in milliseconds. Populated for active correspondence/league games so clients can compute the real time until expiry (per-turn allowance + bank), not just the per-turn proxy. Empty for games without a time bank or for finished games.
Used as response type in: game_service.GameMetadataService.GetActiveCorrespondenceGames, game_service.GameMetadataService.GetRecentCorrespondenceGames, game_service.GameMetadataService.GetRecentGames
GameMetaEvent defines how we serialize meta events to the database.
Used in: ,
the player that performed the event.
how long should this event remain active, in milliseconds?
Used in:
These are "original events"
Adjudication is just seen as a "nudge" on the front end.
Are we going to implement this someday?
And these are responses: A user can accept an abort, or the client will auto-accept when time expires:
A user would not accept an adjudication. The client auto-accepts this when time expires
An adjudication is denied when the receiver responds positively to a nudge.
More:
add X seconds at a time (30?) to opponent's clock
Some meta events have a timer associated with them. Send this with the original event id after time has expired.
Used in:
Used in: , , , , ,
time_bank_minutes is the number of minutes of time bank for correspondence games. When a player exceeds their per-turn time (increment_seconds), the deficit is deducted from their time bank. Player times out only when time bank is exhausted.
A GameRules is just the name of a board layout + the name of a letter distribution. These must exist in a database or file somewhere.
Used in: , ,
The supported board layout names are CrosswordGame and SuperCrosswordGame
The supported letter distributions are english, french, norwegian, german, catalan, spanish. There are more to come!
Use "classic" for our classic game, otherwise it could be some other game (a is worth 100, dogworms, etc.)
Used in: ,
A NATIVE game is the default OMGWords game (or its variants) created on the woogles site, between two players or between a player and a bot.
An ANNOTATED game does not feature Woogles players, but is instead created by a broadcaster/annotator to represent a real-life game. It is created using the liwords "editor" mode or by importing a GCG.
Used as request type in: league_service.LeagueService.GetDivisionTimeBankWarnings
Time bank threshold in hours (e.g., 24 for 1 day)
Used as response type in: league_service.LeagueService.GetDivisionTimeBankWarnings
Request for getting followers of a user
Response containing list of follower user IDs
Request for getting users that a user follows
Response containing list of user IDs that the user follows
InitRealmInfo is a request for the API server to send back information about that realm back to the user. For example, for the lobby realm, we would like lists of active games, chats, etc; for game realms, we would like the game history.
InstantiateGame is an internal message passed to gamesvc in order to instantiate a game.
assigned_first is -1 if random, or the player index in user_ids otherwise
When we go to a new path in our SPA, we send a JoinPath. When we leave the path, we send an Unjoin realm. d
Used in: ,
Used in: ,
Extended stats for richer leaderboard display
Sum of scores (for ScAV = total_score / games_played)
Sum of opponent scores (for OScAV)
Sum of bingos (for BAV = total_bingos / games_played)
Sum of opponent bingos (for OBAV)
Sum of turns (for #TAV = total_turns / games_played)
Highest single turn score (HT)
Highest game score (HG)
Number of timeout losses (#TO)
Number of blanks played (for ?AV = blanks_played / games_played)
Sum of tiles played (for TAV = total_tiles_played / games_played)
Sum of opponent tiles played (for OTAV)
How player was placed in this division (NEW, PROMOTED, etc.)
Average mistake index from BestBot analysis (0 if no analysis)
Number of games with completed BestBot analysis
Best possible finishing rank (computed from remaining pairings)
Worst possible finishing rank (computed from remaining pairings)
Used in: , ,
A MatchUser requests or receives a match via a seek or a match request.
Used in:
user_id is the database, or anonymous, ID of the user.
relevant_rating is the rating of the user, for the relevant seek mode.
if is_anonymous, backend won't bother to look up the user in the DB.
display_name is the display username of the user (could be real name too)
In order to make socket messages as small and simple as possible, we should include the message type with the socket message. Whenever we add a new client <-> server socket message type, add it to this list.
deprecate soon
used for TournamentDataResponse (metadata)
Add more events here. The total number of events should fit in a byte. We should definitely not be using anywhere close to 255 events, and in order to enforce that I'll be forcing the event type header to just be a byte long.
Used in:
Monitoring/Invigilation data for tournament participants
Used in: , ,
camera_key and screenshot_key are only sent to directors and the user themselves
Camera stream status and timestamp
Screenshot stream status and timestamp
Single user monitoring stream status update (sent via WebSocket to individual user)
A NewGameEvent gets sent from the server to the involved clients when a new game is about to begin. It should follow a SoughtGameProcessEvent.
These are the connection IDs of the requesting and accepting users.
Used in:
Used in:
Used as request type in: pair_service.PairService.HandlePairRequest
Used as response type in: pair_service.PairService.HandlePairRequest, tournament_service.TournamentService.RunCOP
Used in: , , ,
can be a list, for elimination tourneys
Used in:
PlacementStatus indicates a player's status for next season placement
Used in:
Brand new player
Promoted from lower division
Relegated from higher division
Stayed in same division
Returning after 1-3 seasons
Returning after 4+ seasons
Used in: ,
Meta information about the player of a particular game.
Used in: , ,
Rating for the particular mode of the game. String because it could be provisional or some other strings.
string avatar_url = 7; // the UserService now offers Avatar info
first is true if the player went first. This is deprecated because it is assumed the player listed first went first.
Used in:
Used in:
Only authenticated connections.
map of variant name to rating
Used in:
PromotionFormula defines how many players are promoted/relegated per division
Used in: ,
ceil(N/6) - default, e.g. 15 players = 3 promoted/relegated
ceil((N+1)/5), e.g. 15 players = 4 promoted/relegated
ceil(N/5), e.g. 15 players = 3 promoted/relegated
ceil(N/3), e.g. 15 players = 5 promoted/relegated
Used in:
This can be sent from the user to the tournament or vice-versa.
within a matchplay type tournament where several
games share a round.
if true, this is a NOT-ready message.
realm should be made obsolete. RegisterRealmResponse should always return a list of realms.
RematchStartedEvent gets sent to a game for which there is a rematch. It notifies that observers of the game that a rematch has started.
rematch_game_id is the new game ID.
Used in: , , ,
Optional is needed to represent: - `nil` for no override at all - `0` overriding the default to disable the spread cap Without an optional, these two cases would be indistinguishable.
COP-specific fields (only used when pairing_method == COP) These arrays should have one value per round in the round range. gibson_spreads are ordered from last round to first (reverse chronological).
hopefulness_thresholds are ordered from last round to first (reverse chronological).
control_loss_activation_round is 0-indexed relative to the start of this COP round range.
reset_round is the Australian Draw repeat-reset point, stored as a 1-based round number (valid >= 1). A meeting in 1-based round r is avoided as a repeat iff r >= reset_round, so meetings in earlier rounds are allowed to recur. This emulates a day-based reset (e.g. set 9 so rounds 1-8 are forgiven when pairing round 9 onward). 0/unset is treated as 1 (reset from round 1 = avoid all prior meetings, the default no-repeat behavior); do not rely on the proto3 zero-default as a meaningful sentinel -- the reader clamps it explicitly. reset_round at or past the current round forgives every prior meeting (King-of-the-Hill). When even a strict pairing is impossible the reset point is relaxed upward one round at a time.
Used in:
Used in:
Used in: , , , ,
Used in: , , ,
How to calculate promotion/relegation counts
Used in: ,
Used in:
connection_id is the websocket ID via which this game was requested.
rematch_for is the game ID that this Match Request is a rematch for (empty if it isn't a rematch)
If this match request is part of a tournament, it is treated in a special way. We are moving towards server-only matching during tournaments, so the following will only be used in "clubhouse mode" / more free-form clubs.
SeekRequests sends all open seek requests.
Used in:
The server will send back a challenge result event only in the case of a challenge. In all other cases, the server will send back a ServerGameplayEvent. A ServerChallengeResultEvent is sent back along with a list of ServerGameplayEvents, instead of trying to reconstruct and send the right incremental events. The reason is that the logic is complex and has many special cases, and is already fully implemented in Macondo. We don't wish to re-implement it both in this repo's backend and frontend. XXX: This message type is obsolete, and will be replaced by OMGWordsChallengeResultEvent
The server will send back a ServerGameplayEvent to a ClientGameplayEvent. The server will also send these asynchronously for opponent gameplay events. XXX: This message type is obsolete and will be replaced by ServerOMGWordsEvent
XXX: move to ipc.GameEvent
XXX: move to ipc.PlayState
the event has the nickname, but not the userid.
time bank remaining for the player who just moved, in milliseconds
opponent_rack is populated for annotated games to keep frontend state in sync when rack inference borrows tiles from opponent
ServerOMGWordsEvent is a new event type.
opponent_rack is populated for annotated games to keep frontend state in sync when rack inference borrows tiles from opponent
A SoughtGameProcessEvent gets sent when a match request (or seek request) get accepted (from client to server), or canceled -- when sent from server to client.
Used in: ,
Stream status for monitoring
Used in:
Used in:
Number of games with time bank below threshold
Used in:
Used in:
time_of_last_update is the timestamp of the last update, in milliseconds If no update has been made, this defaults to timeStarted.
time_started is a unix timestamp, in milliseconds.
time_remaining is an array of remaining time per player, in milliseconds
max_overtime is the number of minutes that the game is allowed to go overtime
increment_seconds is the amount of seconds that is added to the timer after every move
reset_to_increment_after_turn sets the timer for the player to increment_seconds. this can be used for correspondence games; for example, time_remaining and increment_seconds can be set to the same number of seconds (let's say 5 days) at the beginning, and this flag can be set to on. Then we should always have 5 days to make any move.
If untimed is true, then Timers are not updated at all.
time_bank is an array of time bank per player, in milliseconds. Used for correspondence/league games. Once time_remaining reaches 0, time is deducted from time_bank. Player only loses when both are exhausted.
Used in:
The ID of the tournament
Note: this field seems totally unused
Used in:
Used in:
New tournaments will use full tournament messages (specifically, TournamentDivisionDataResponse et al). This event is also used in the tournament_service's RecentGamesResponse, which can be used to fetch information for the last games played in a tournament.
Used in:
Time that the game ended
Used in:
Used in: , , , , ,
NO_RESULT: the game is not over
ELIMINATED: player is eliminated in a bracket tournament
VOID: player never played this round and should neither be assigned a win nor a loss. Useful for club-type games.
Broadcast message for monitoring updates
Used in: ,
Used as request type in: tournament_service.TournamentService.AddDirectors, tournament_service.TournamentService.AddPlayers, tournament_service.TournamentService.RemoveDirectors, tournament_service.TournamentService.RemovePlayers
Used as field type in: , ,
This message makes the "Status Bar" show up and also tells the players that the backend is now accepting "ready" messages for this round.
for matchplay type rounds etc.
(message has no fields)
Used in: