Lobby browser, names and passwords, The Good Stuff, smarter queues, and a balance pass
- Lobbies: a name (default "Lobby <code>"), Unlisted or Public, and an optional password. The Multiplayer page scrolls: a Browser of public lobbies (name, count, padlock, code, little player previews, Join with a password field when locked), Join by code, Create, then Settings. Errors show under whatever caused them. Links take ?pass= (and --pass), and Copy Link includes it. Protocol 11. - Queue areas center on their host along the floor's flat stretch, squeezing their slots to fit, and move to a nearby surface when the host's is too short. - An airblast steals an enemy's flail ball onto its own chain for a while. Flail balls reel themselves back after 15 seconds. Doubler echoes of the Grimoire teleport move you too. - The Good Stuff: a new trinket, the inverse of Diazepam (more spread). Spread is now a multiplier, and it widens or narrows the Vacuum's cone. - Balance: Sword basic slash 25% smaller and charged slash half the size, Whip basic lash half the damage and reach, Recoil Coil recoil halved, Speedometer no longer speeds you up. - Fixes: fashions survive coming back from a game, Quit shows only in the sandbox menu, and the chat log keeps above the menu's tip.
This commit is contained in:
1 parent
af41b53717
commit
37560547d4
17 files changed
+666
-277
No files matched your search
+54
-5
@@ -100,11 +100,15 @@ enum LeaveReason
|
||||
LEAVE_KICKED
|
||||
};
|
||||
|
||||
// A lobby: its members in the order they joined (the first hosting), and its rooms, the sandbox first.
|
||||
// A lobby: its name, the password to join it (empty for none), whether the lobby list shows it, its members in the
|
||||
// order they joined (the first hosting), and its rooms, the sandbox first.
|
||||
struct Lobby
|
||||
{
|
||||
std::string name;
|
||||
std::string password;
|
||||
std::vector<int> members;
|
||||
std::vector<int> rooms;
|
||||
bool isPublic = false;
|
||||
};
|
||||
|
||||
// What the network's threads hand the game loop: a member's connection opening or closing, one of their data channels
|
||||
@@ -329,7 +333,8 @@ static void lobby_enter(int id, const std::string& code)
|
||||
list += (list.empty() ? "" : ",") + std::string("{\"id\":") + std::to_string(other) +
|
||||
",\"name\":" + json_quote(members[other].name) + "}";
|
||||
send(id, "{\"type\":\"welcome\",\"id\":" + std::to_string(id) + ",\"code\":" + json_quote(code) +
|
||||
",\"host\":" + std::to_string(lobby.members.front()) + ",\"members\":[" + list + "]}");
|
||||
",\"name\":" + json_quote(lobby.name) + ",\"host\":" + std::to_string(lobby.members.front()) +
|
||||
",\"members\":[" + list + "]}");
|
||||
for (int other : lobby.members)
|
||||
if (other != id)
|
||||
send(other, "{\"type\":\"member_join\",\"id\":" + std::to_string(id) +
|
||||
@@ -360,7 +365,35 @@ static void lobby_exit(int id, LeaveReason leave = LEAVE_QUIT, const std::string
|
||||
",\"host\":" + std::to_string(lobby.members.front()) + reason + "}");
|
||||
}
|
||||
|
||||
// The lobby messages, in JSON: making, joining and leaving lobbies, kicking, and keeping the connection busy.
|
||||
// Tells a member about every public lobby: its code and name, how many are in it, whether it needs a password, and each
|
||||
// player's color and fashion (as their fighter in its sandbox has them, or as they brought it while in a game), for
|
||||
// little previews of them.
|
||||
static void lobbies_send(int id)
|
||||
{
|
||||
std::string list;
|
||||
for (auto& [code, lobby] : lobbies)
|
||||
{
|
||||
if (!lobby.isPublic || lobby.rooms.empty())
|
||||
continue;
|
||||
Sim& sandbox = rooms[lobby.rooms.front()].sim;
|
||||
std::string players;
|
||||
for (int member : lobby.members)
|
||||
{
|
||||
int fighter = sandbox.match.fighter_find(sandbox, member);
|
||||
Profile& profile = members[member].profile;
|
||||
int color = fighter >= 0 ? sandbox.match.colors[fighter] : profile.color;
|
||||
int fashion = fighter >= 0 ? sandbox.match.fashions[fighter] : profile.fashion;
|
||||
players += (players.empty() ? "" : ",") + std::string("{\"color\":") + std::to_string(color) +
|
||||
",\"fashion\":" + std::to_string(fashion) + "}";
|
||||
}
|
||||
list += (list.empty() ? "" : ",") + std::string("{\"code\":") + json_quote(code) +
|
||||
",\"name\":" + json_quote(lobby.name) + ",\"locked\":" + (lobby.password.empty() ? "false" : "true") +
|
||||
",\"players\":[" + players + "]}";
|
||||
}
|
||||
send(id, "{\"type\":\"lobbies\",\"lobbies\":[" + list + "]}");
|
||||
}
|
||||
|
||||
// The lobby messages, in JSON: listing, making, joining and leaving lobbies, kicking, and keeping the connection busy.
|
||||
static void text_handle(int id, const std::string& text)
|
||||
{
|
||||
simdjson::dom::element message;
|
||||
@@ -371,12 +404,14 @@ static void text_handle(int id, const std::string& text)
|
||||
// Answered, so proxies see the connection busy both ways.
|
||||
if (type == "ping")
|
||||
return send(id, "{\"type\":\"pong\"}");
|
||||
if (type == "create" || type == "join")
|
||||
if (type == "list" || type == "create" || type == "join")
|
||||
{
|
||||
int64_t version = 0;
|
||||
std::string_view name;
|
||||
if (message["version"].get(version) || version != PROTOCOL_VERSION)
|
||||
return error_send(id, "Different game version");
|
||||
if (type == "list")
|
||||
return lobbies_send(id);
|
||||
if (!members[id].code.empty())
|
||||
return error_send(id, "Already in a lobby");
|
||||
members[id].name = name_clean(message["name"].get(name) ? "" : name);
|
||||
@@ -385,7 +420,15 @@ static void text_handle(int id, const std::string& text)
|
||||
std::string code = code_make();
|
||||
if (code.empty())
|
||||
return error_send(id, "No free lobby codes");
|
||||
std::printf("Lobby %s opened (%zu open)\n", code.c_str(), lobbies.size() + 1);
|
||||
// A lobby's name defaults to its code, and it starts unlisted unless asked otherwise.
|
||||
std::string_view field;
|
||||
bool isPublic = false;
|
||||
Lobby& lobby = lobbies[code];
|
||||
lobby.name = text_clean(message["lobby"].get(field) ? "" : field, LOBBY_NAME_MAX);
|
||||
lobby.name = lobby.name.empty() ? "Lobby " + code : lobby.name;
|
||||
lobby.password = text_clean(message["password"].get(field) ? "" : field, LOBBY_PASSWORD_MAX);
|
||||
lobby.isPublic = !message["public"].get(isPublic) && isPublic;
|
||||
std::printf("Lobby %s opened (%zu open)\n", code.c_str(), lobbies.size());
|
||||
return lobby_enter(id, code);
|
||||
}
|
||||
std::string_view raw;
|
||||
@@ -399,6 +442,11 @@ static void text_handle(int id, const std::string& text)
|
||||
return error_send(id, "No lobby with that code");
|
||||
if ((int)lobby->second.members.size() >= LOBBY_MEMBERS_MAX)
|
||||
return error_send(id, "That lobby is full");
|
||||
std::string_view password;
|
||||
if (message["password"].get(password))
|
||||
password = "";
|
||||
if (!lobby->second.password.empty() && password != lobby->second.password)
|
||||
return error_send(id, password.empty() ? LOBBY_PASSWORD_NEEDED : "Wrong password");
|
||||
return lobby_enter(id, code);
|
||||
}
|
||||
if (type == "leave")
|
||||
@@ -634,6 +682,7 @@ static void game_open(int sandboxSerial, int queuer)
|
||||
members[players[k]].profile = profile_get(sandbox.sim.fighters[seats[k]]);
|
||||
std::memcpy(members[players[k]].profile.name, lobby.names[seats[k]], sizeof(lobby.names[seats[k]]));
|
||||
members[players[k]].profile.color = lobby.colors[seats[k]];
|
||||
members[players[k]].profile.fashion = lobby.fashions[seats[k]];
|
||||
}
|
||||
int serial = room_open(sandbox.code);
|
||||
Room& game = rooms[serial];
|
||||
|
||||
Reference in new issue
Block a user