Skip to content

Commit

Permalink
cmdinterface: Output room status json on various events
Browse files Browse the repository at this point in the history
  • Loading branch information
past-due committed Nov 13, 2024
1 parent 1762fb1 commit 259e023
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 1 deletion.
22 changes: 22 additions & 0 deletions lib/netplay/netplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,11 @@ void NET_setLobbyDisabled(const std::string& infoLinkURL)
lobby_disabled_info_link_url = infoLinkURL;
}

uint32_t NET_getCurrentHostedLobbyGameId()
{
return gamestruct.gameId;
}

// Sets if the game is password protected or not
void NETGameLocked(bool flag)
{
Expand Down Expand Up @@ -991,12 +996,19 @@ static void NETplayerLeaving(UDWORD index, bool quietSocketClose)
sync_counter.left++;
bool wasSpectator = NetPlay.players[index].isSpectator;
MultiPlayerLeave(index); // more cleanup
bool resetReadyCalled = false;
if (ingame.localJoiningInProgress) // Only if game hasn't actually started yet.
{
NET_DestroyPlayer(index); // sets index player's array to false
if (!wasSpectator)
{
resetReadyStatus(false); // reset ready status for all players
resetReadyCalled = true;
}

if (!resetReadyCalled)
{
wz_command_interface_output_room_status_json();
}
}
}
Expand All @@ -1020,6 +1032,7 @@ static void NETplayerDropped(UDWORD index)
sync_counter.drops++;
bool wasSpectator = NetPlay.players[index].isSpectator;
MultiPlayerLeave(id); // more cleanup
bool resetReadyCalled = false;
if (ingame.localJoiningInProgress) // Only if game hasn't actually started yet.
{
// Send message type specifically for dropped / disconnects
Expand All @@ -1031,6 +1044,12 @@ static void NETplayerDropped(UDWORD index)
if (!wasSpectator)
{
resetReadyStatus(false); // reset ready status for all players
resetReadyCalled = true;
}

if (!resetReadyCalled)
{
wz_command_interface_output_room_status_json();
}
}

Expand Down Expand Up @@ -4361,6 +4380,9 @@ static void NETallowJoining()
{
ASSERT(false, "wzFiles is uninitialized?? (Player: %" PRIu8 ")", index);
}

wz_command_interface_output_room_status_json();

continue; // continue to next tmp_socket
}

Expand Down
1 change: 1 addition & 0 deletions lib/netplay/netplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ void NET_clearDownloadingWZFiles();
bool NET_getLobbyDisabled();
const std::string& NET_getLobbyDisabledInfoLinkURL();
void NET_setLobbyDisabled(const std::string& infoLinkURL);
uint32_t NET_getCurrentHostedLobbyGameId();

bool NETGameIsLocked();
void NETGameLocked(bool flag);
Expand Down
16 changes: 16 additions & 0 deletions src/multiint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2615,6 +2615,8 @@ static bool SendReadyRequest(UBYTE player, bool bReady)
std::string playerName = NetPlay.players[player].name;
std::string playerNameB64 = base64Encode(std::vector<unsigned char>(playerName.begin(), playerName.end()));
wz_command_interface_output("WZEVENT: readyStatus=%d: %" PRIu32 " %s %s %s %s %s\n", bReady ? 1 : 0, player, playerPublicKeyB64.c_str(), playerIdentityHash.c_str(), playerVerifiedStatus.c_str(), playerNameB64.c_str(), NetPlay.players[player].IPtextAddress);

wz_command_interface_output_room_status_json();
}
return changedValue;
}
Expand Down Expand Up @@ -2681,6 +2683,8 @@ bool recvReadyRequest(NETQUEUE queue)
std::string playerName = NetPlay.players[player].name;
std::string playerNameB64 = base64Encode(std::vector<unsigned char>(playerName.begin(), playerName.end()));
wz_command_interface_output("WZEVENT: readyStatus=%d: %" PRIu32 " %s %s %s %s %s\n", bReady ? 1 : 0, player, playerPublicKeyB64.c_str(), playerIdentityHash.c_str(), playerVerifiedStatus.c_str(), playerNameB64.c_str(), NetPlay.players[player].IPtextAddress);

wz_command_interface_output_room_status_json();
}
return changedValue;
}
Expand Down Expand Up @@ -7318,6 +7322,18 @@ void WzMultiplayerOptionsTitleUI::frontendMultiMessages(bool running)
NETuint32_t(&player_id);
NETend();

if (player_id >= MAX_CONNECTED_PLAYERS)
{
debug(LOG_ERROR, "Bad NET_PLAYERRESPONDING received, ID is %d", (int)player_id);
break;
}

if (whosResponsible(player_id) != queue.index && queue.index != NetPlay.hostPlayer)
{
HandleBadParam("NET_PLAYERRESPONDING given incorrect params.", player_id, queue.index);
break;
}

ingame.JoiningInProgress[player_id] = false;
ingame.DataIntegrity[player_id] = false;
break;
Expand Down
2 changes: 2 additions & 0 deletions src/multijoin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,8 @@ void recvPlayerLeft(NETQUEUE queue)

debug(LOG_INFO, "** player %u has dropped, in-game! (gameTime: %" PRIu32 ")", playerIndex, gameTime);
ActivityManager::instance().updateMultiplayGameData(game, ingame, NETGameIsLocked());

wz_command_interface_output_room_status_json();
}

// ////////////////////////////////////////////////////////////////////////////
Expand Down
5 changes: 5 additions & 0 deletions src/multiplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ bool multiPlayerLoop()
}
ingame.lastPlayerDataCheck2 = std::chrono::steady_clock::now();
wz_command_interface_output("WZEVENT: allPlayersJoined\n");
wz_command_interface_output_room_status_json();
}
if (NetPlay.bComms)
{
Expand Down Expand Up @@ -1460,6 +1461,8 @@ bool recvMessage()
std::string playerName = NetPlay.players[player_id].name;
std::string playerNameB64 = base64Encode(std::vector<unsigned char>(playerName.begin(), playerName.end()));
wz_command_interface_output("WZEVENT: playerResponding: %" PRIu32 " %s %s %s %s %s\n", player_id, playerPublicKeyB64.c_str(), playerIdentityHash.c_str(), playerVerifiedStatus.c_str(), playerNameB64.c_str(), NetPlay.players[player_id].IPtextAddress);

wz_command_interface_output_room_status_json();
}
}
break;
Expand Down Expand Up @@ -2530,6 +2533,8 @@ void resetReadyStatus(bool bSendOptions, bool ignoreReadyReset)
changeReadyStatus(i, false);
}
}

wz_command_interface_output_room_status_json();
}
}

Expand Down
204 changes: 203 additions & 1 deletion src/stdinreader.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
This file is part of Warzone 2100.
Copyright (C) 2020-2021 Warzone 2100 Project
Copyright (C) 2020-2024 Warzone 2100 Project
Warzone 2100 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand All @@ -26,6 +26,7 @@
#include "multistat.h"
#include "multilobbycommands.h"
#include "clparse.h"
#include "main.h"

#include <string>
#include <atomic>
Expand Down Expand Up @@ -1451,3 +1452,204 @@ void configSetCmdInterface(WZ_Command_Interface mode, std::string value)
}
wz_cmd_interface_param = value;
}

// MARK: - Output Room Status JSON

static void WzCmdInterfaceDumpHumanPlayerVarsImpl(uint32_t player, bool gameHasFiredUp, nlohmann::ordered_json& j)
{
PLAYER const &p = NetPlay.players[player];

j["name"] = p.name;

if (!gameHasFiredUp)
{
// in lobby, output "ready" status
j["ready"] = static_cast<int>(p.ready);
}
else
{
// once game has fired up, output loading / connection status
if (p.allocated)
{
if (ingame.JoiningInProgress[player])
{
j["status"] = "loading";
}
else
{
j["status"] = "active";
}
if (ingame.PendingDisconnect[player])
{
j["status"] = "pendingleave";
}
}
else
{
j["status"] = "left";
}
}

const auto& identity = getMultiStats(player).identity;
if (!identity.empty())
{
j["pk"] = base64Encode(identity.toBytes(EcKey::Public));
}
else
{
j["pk"] = "";
}
j["ip"] = NetPlay.players[player].IPtextAddress;

if (ingame.PingTimes[player] != PING_LIMIT)
{
j["ping"] = ingame.PingTimes[player];
}
else
{
j["ping"] = -1; // for "infinite" ping
}

j["admin"] = static_cast<int>(NetPlay.players[player].isAdmin || (player == NetPlay.hostPlayer));

if (player == NetPlay.hostPlayer)
{
j["host"] = 1;
}
}

void wz_command_interface_output_room_status_json()
{
if (!wz_command_interface_enabled())
{
return;
}

bool gameHasFiredUp = (GetGameMode() == GS_NORMAL);

auto root = nlohmann::ordered_json::object();
root["ver"] = 1;

auto data = nlohmann::ordered_json::object();
if (gameHasFiredUp)
{
if (ingame.TimeEveryoneIsInGame.has_value())
{
data["state"] = "started";
}
else
{
data["state"] = "starting";
}
}
else
{
data["state"] = "lobby";
}
if (NetPlay.isHost)
{
auto lobbyGameId = NET_getCurrentHostedLobbyGameId();
if (lobbyGameId != 0)
{
data["lobbyid"] = lobbyGameId;
}
}
data["map"] = game.map;

root["data"] = std::move(data);

if (NetPlay.isHost)
{
auto players = nlohmann::ordered_json::array();
for (uint8_t player = 0; player < game.maxPlayers; ++player)
{
PLAYER const &p = NetPlay.players[player];
auto j = nlohmann::ordered_json::object();

j["pos"] = p.position;
j["team"] = p.team;
j["col"] = p.colour;
j["fact"] = static_cast<int32_t>(p.faction);

if (p.ai == AI_CLOSED)
{
// closed slot
j["type"] = "closed";
}
else if (p.ai == AI_OPEN)
{
if (!gameHasFiredUp && !p.allocated)
{
// available / open slot (in lobby)
j["type"] = "open";
}
else
{
if (!p.allocated)
{
// if game has fired up and this slot is no longer allocated, skip it entirely if it wasn't initially a human player
if (p.difficulty != AIDifficulty::HUMAN)
{
continue;
}
}

// human (or host) slot
j["type"] = (p.isSpectator) ? "spec" : "player";

WzCmdInterfaceDumpHumanPlayerVarsImpl(player, gameHasFiredUp, j);
}
}
else
{
// bot player
j["type"] = "bot";

j["name"] = getAIName(player);
j["difficulty"] = static_cast<int>(NetPlay.players[player].difficulty);
}

players.push_back(std::move(j));
}
root["players"] = std::move(players);

auto spectators = nlohmann::ordered_json::array();
for (uint32_t i = MAX_PLAYER_SLOTS; i < MAX_CONNECTED_PLAYERS; ++i)
{
PLAYER const &p = NetPlay.players[i];
if (p.ai == AI_CLOSED)
{
continue;
}

auto j = nlohmann::ordered_json::object();
if (!p.allocated)
{
if (!gameHasFiredUp)
{
// available / open spectator slot
j["type"] = "open";
}
else
{
// no spectator connected to this slot - skip
continue;
}
}
else
{
// human (or host) slot
j["type"] = (p.isSpectator) ? "spec" : "player";

WzCmdInterfaceDumpHumanPlayerVarsImpl(i, gameHasFiredUp, j);
}

spectators.push_back(std::move(j));
}
root["specs"] = std::move(spectators);
}

std::string statusJSONStr = std::string("__WZROOMSTATUS__") + root.dump(-1, ' ', false, nlohmann::ordered_json::error_handler_t::replace) + "__ENDWZROOMSTATUS__";
statusJSONStr.append("\n");
wz_command_interface_output_str(statusJSONStr.c_str());
}
2 changes: 2 additions & 0 deletions src/stdinreader.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,5 @@ void wz_command_interface_output(const char *str, ...) WZ_DECL_FORMAT(printf, 1,
#endif

void wz_command_interface_output_str(const char *str);

void wz_command_interface_output_room_status_json();

0 comments on commit 259e023

Please sign in to comment.