Initial commit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shweetandClaude Opus 5.5 committed 2026-11-08 01:30:33 -05:00
commit 2007fb7edc
200 files changed
+27710

No files matched your search

+81
View File
@@ -0,0 +1,81 @@
#pragma once
// What the game and the server agree on. The server hands out lobby codes, keeps each lobby's members and passes
// WebRTC signaling between them; matches themselves run peer to peer. Messages are JSON objects with a "type":
//
// Game to server:
// create {name, version} make a lobby and join it as host
// join {code, name, version} join a lobby by its code
// leave {} leave the lobby
// kick {id, reason} (the host) put someone out of the lobby
// signal {to, payload} pass a WebRTC description or candidate to another member
// ping {} keeps the connection alive through proxies (answered with pong)
//
// Server to game:
// welcome {id, code, host, members: [{id, name}]} in a lobby (members includes this one)
// member_join {id, name}
// member_leave {id, host, kicked?, reason?} host is who hosts now; kicked says they were kicked
// kicked {reason} this member was kicked out of the lobby
// signal {from, payload}
// error {message} the request failed; the connection stays open
// pong {}
//
// A signal's payload is either a description {sdp, kind} or a candidate {candidate, mid}.
#include <string>
#include <string_view>
constexpr int PROTOCOL_VERSION = 2;
constexpr int LOBBY_MEMBERS_MAX = 4;
constexpr int LOBBY_CODE_LENGTH = 4;
// Letters only, without I and O, so codes are easy to read out and type.
constexpr const char LOBBY_CODE_LETTERS[] = "ABCDEFGHJKLMNPQRSTUVWXYZ";
constexpr int PLAYER_NAME_MAX = 24;
constexpr int CHAT_MESSAGE_MAX = 100;
constexpr int KICK_REASON_MAX = 60;
constexpr const char SERVER_URL_DEFAULT[] = "wss://shweetz.net/smack-a-brother/ws";
constexpr int SERVER_URL_LENGTH = 128;
// Text from elsewhere (another player, or the server) made safe to show: only printable ASCII (what the game's font
// has; anything else, emoji included, is dropped), cut to max characters, with spaces at its ends trimmed.
inline std::string text_clean(std::string_view raw, size_t max)
{
std::string text;
for (char c : raw)
if (c >= ' ' && c <= '~' && text.size() < max)
text += c;
size_t first = text.find_first_not_of(' ');
size_t last = text.find_last_not_of(' ');
return first == std::string::npos ? "" : text.substr(first, last - first + 1);
}
// A count of seconds in words: "1 second", "29 seconds".
inline std::string seconds_say(int seconds)
{
return std::to_string(seconds) + (seconds == 1 ? " second" : " seconds");
}
// A string as a JSON string literal, quotes included.
inline std::string json_quote(const std::string& text)
{
std::string quoted = "\"";
for (unsigned char c : text)
if (c == '"' || c == '\\')
quoted += '\\', quoted += (char)c;
else if (c == '\n')
quoted += "\\n";
else if (c == '\r')
quoted += "\\r";
else if (c == '\t')
quoted += "\\t";
else if (c < 0x20)
{
constexpr char HEX[] = "0123456789abcdef";
quoted += "\\u00";
quoted += HEX[c >> 4];
quoted += HEX[c & 15];
}
else
quoted += (char)c;
return quoted + "\"";
}