Skip to content

Commit

Permalink
Change: multiple modes to send NewGRF data to client / Game Coordinator
Browse files Browse the repository at this point in the history
NewGRFs cannot be changed in multiplayer games, and consumes a lot
of bytes. So only send it once to the Game Coordiantor on registration,
and skip the field after that for any update.
A new game will restart the registration, so any NewGRF change
between games is picked up via the new registration.

Clients that look at the NewGRFs a server has, want to know the names
of the NewGRFs more than the IDs. So in addition to the ID and MD5,
send the full name to the clients too.

This solution is picked so the Game Coordinator isn't sending the
names of all the NewGRFs to the clients constantly (which would
make the server-listing very large), but still allow clinets to
see the name of a specific server if he clicks the button.
  • Loading branch information
TrueBrain committed Jun 30, 2021
1 parent 324eaff commit b2c9f15
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 38 deletions.
66 changes: 42 additions & 24 deletions src/network/core/game_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,17 +158,20 @@ const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo()
* a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This
* function must set all appropriate fields. This GRF is later appended to
* the grfconfig list of the NetworkGameInfo.
* @param config the GRF to handle.
* @param config The GRF to handle.
* @param name The name of the GRF, if known (for example: the server send this info).
*/
static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)
static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config, std::string &name)
{
/* Find the matching GRF file */
const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum);
if (f == nullptr) {
/* Don't know the GRF, so mark game incompatible and the (possibly)
* already resolved name for this GRF (another server has sent the
* name of the GRF already */
* already resolved name for this GRF. */
config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true);
if (strcmp(GetGRFStringFromGRFText(config->name), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0 && !name.empty()) {
AddGRFTextToList(config->name, name.c_str());
}
config->status = GCS_NOT_FOUND;
} else {
config->filename = f->filename;
Expand All @@ -181,10 +184,11 @@ static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)

/**
* Serializes the NetworkGameInfo struct to the packet.
* @param p the packet to write the data to.
* @param info the NetworkGameInfo struct to serialize from.
* @param p The packet to write the data to.
* @param info The NetworkGameInfo struct to serialize from.
* @param newgrf_mode The NewGRF mode of the NetworkGameInfo. See GameInfoNewGRFMode for details.
*/
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info)
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, GameInfoNewGRFMode newgrf_mode)
{
p->Send_uint8 (NETWORK_GAME_INFO_VERSION);

Expand All @@ -194,9 +198,10 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info)
/* NETWORK_GAME_INFO_VERSION = 5 */
assert(info->join_key.empty() || info->join_key[0] == '+');
p->Send_string(info->join_key.empty() ? "" : info->join_key.substr(1));
p->Send_uint8(newgrf_mode);

/* NETWORK_GAME_INFO_VERSION = 4 */
{
if (newgrf_mode != GAME_INFO_NEWGRF_MODE_NONE) {
/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
* the GRFs that are needed, i.e. the ones that the server has
* selected in the NewGRF GUI and not the ones that are used due
Expand All @@ -212,7 +217,12 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info)

/* Send actual GRF Identifications */
for (c = info->grfconfig; c != nullptr; c = c->next) {
if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(p, &c->ident);
if (!HasBit(c->flags, GCF_STATIC)) {
SerializeGRFIdentifier(p, &c->ident);
if (newgrf_mode == GAME_INFO_NEWGRF_MODE_FULL) {
p->Send_string(c->GetName());
}
}
}
}

Expand Down Expand Up @@ -257,29 +267,37 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
/* Update the documentation in game_info.h on changes
* to the NetworkGameInfo wire-protocol! */

GameInfoNewGRFMode newgrf_mode = GAME_INFO_NEWGRF_MODE_SHORT;
switch (game_info_version) {
case 5: {
std::string join_key = p->Recv_string(NETWORK_JOIN_KEY_LENGTH);
info->join_key = join_key.empty() ? "" : "+" + join_key;
newgrf_mode = (GameInfoNewGRFMode)p->Recv_uint8();
FALLTHROUGH;
}

case 4: {
GRFConfig **dst = &info->grfconfig;
uint i;
uint num_grfs = p->Recv_uint8();

/* Broken/bad data. It cannot have that many NewGRFs. */
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;

for (i = 0; i < num_grfs; i++) {
GRFConfig *c = new GRFConfig();
DeserializeGRFIdentifier(p, &c->ident);
HandleIncomingNetworkGameInfoGRFConfig(c);

/* Append GRFConfig to the list */
*dst = c;
dst = &c->next;
if (newgrf_mode != GAME_INFO_NEWGRF_MODE_NONE) {
GRFConfig **dst = &info->grfconfig;
uint i;
uint num_grfs = p->Recv_uint8();

/* Broken/bad data. It cannot have that many NewGRFs. */
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;

for (i = 0; i < num_grfs; i++) {
GRFConfig *c = new GRFConfig();
DeserializeGRFIdentifier(p, &c->ident);
std::string name = {};
if (newgrf_mode == GAME_INFO_NEWGRF_MODE_FULL) {
name = p->Recv_string(NETWORK_GRF_NAME_LENGTH);
}
HandleIncomingNetworkGameInfoGRFConfig(c, name);

/* Append GRFConfig to the list */
*dst = c;
dst = &c->next;
}
}
FALLTHROUGH;
}
Expand Down
18 changes: 13 additions & 5 deletions src/network/core/game_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
* all 1 the version of this packet's structure
*
* 5+ var join key of the server
* 4+ 1 number of GRFs attached (n)
* 4+ n * 20 unique identifier for GRF files. Consists of:
* - one 4 byte variable with the GRF ID
* - 16 bytes (sent sequentially) for the MD5 checksum
* 5+ 1 NewGRF mode (0 = none: skip next two fields, 1 = short: skip name, 2 = full)
* 4+ 1 number of NewGRFs attached
* 4+ n * M unique identifier for NewGRF files. Consists of:
* 4+ - one 4 byte variable with the NewGRF ID
* 4+ - 16 bytes (sent sequentially) for the MD5 checksum
* of the GRF
* 5+ - name of the NewGRF
*
* 3+ 4 current game date in days since 1-1-0 (DMY)
* 3+ 4 game introduction date in days since 1-1-0 (DMY)
Expand Down Expand Up @@ -89,6 +91,12 @@ struct NetworkGameInfo : NetworkServerGameInfo {
bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match
};

enum GameInfoNewGRFMode : uint8 {
GAME_INFO_NEWGRF_MODE_NONE = 0, ///< Send/receive NetworkGameInfo without any NewGRF data.
GAME_INFO_NEWGRF_MODE_SHORT, ///< Send/receive NetworkGameInfo with only the ID + MD5 of NewGRFs.
GAME_INFO_NEWGRF_MODE_FULL, ///< Send/receive NetworkGameInfo with ID + MD5 + Name of NewGRFs.
};

extern NetworkServerGameInfo _network_game_info;

std::string_view GetNetworkRevisionString();
Expand All @@ -102,6 +110,6 @@ void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf);
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf);

void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info);
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info);
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info, GameInfoNewGRFMode newgrf_mode);

#endif /* NETWORK_CORE_GAME_INFO_H */
15 changes: 9 additions & 6 deletions src/network/network_coordinator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,6 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_SERVER_ERROR(Packet *p)

bool ClientNetworkCoordinatorSocketHandler::Receive_SERVER_REGISTER_ACK(Packet *p)
{
/* Schedule sending an update. */
this->next_update = std::chrono::steady_clock::now();

_settings_client.network.server_join_key = "+" + p->Recv_string(NETWORK_JOIN_KEY_LENGTH);
_settings_client.network.server_join_key_secret = p->Recv_string(NETWORK_JOIN_KEY_SECRET_LENGTH);
_network_server_connection_type = (ConnectionType)p->Recv_uint8();
Expand Down Expand Up @@ -219,6 +216,11 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_SERVER_REGISTER_ACK(Packet *
Debug(net, 3, "Game Coordinator registered our server with invite code '{}'", _network_game_info.join_key);
}

/* Sendt a full update, including NewGRF data. */
this->SendServerUpdate(GAME_INFO_NEWGRF_MODE_SHORT);
/* Schedule sending next update. */
this->next_update = std::chrono::steady_clock::now() + NETWORK_COORDINATOR_DELAY_BETWEEN_UPDATES;

return true;
}

Expand Down Expand Up @@ -428,15 +430,16 @@ void ClientNetworkCoordinatorSocketHandler::Register()

/**
* Send an update of our server status to the Game Coordinator.
* @param include_newgrf_data Whether the server update should include NewGRF data.
*/
void ClientNetworkCoordinatorSocketHandler::SendServerUpdate()
void ClientNetworkCoordinatorSocketHandler::SendServerUpdate(GameInfoNewGRFMode newgrf_mode)
{
Debug(net, 6, "Sending server update to Game Coordinator");
this->next_update = std::chrono::steady_clock::now() + NETWORK_COORDINATOR_DELAY_BETWEEN_UPDATES;

Packet *p = new Packet(PACKET_COORDINATOR_CLIENT_UPDATE);
p->Send_uint8(NETWORK_COORDINATOR_VERSION);
SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo());
SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo(), newgrf_mode);

this->SendPacket(p);
}
Expand Down Expand Up @@ -665,7 +668,7 @@ void ClientNetworkCoordinatorSocketHandler::SendReceive()
}

if (_network_server && _network_server_connection_type != CONNECTION_TYPE_UNKNOWN && std::chrono::steady_clock::now() > this->next_update) {
this->SendServerUpdate();
this->SendServerUpdate(GAME_INFO_NEWGRF_MODE_NONE);
}

if (!_network_server && std::chrono::steady_clock::now() > this->last_activity + IDLE_TIMEOUT) {
Expand Down
2 changes: 1 addition & 1 deletion src/network/network_coordinator.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class ClientNetworkCoordinatorSocketHandler : public NetworkCoordinatorSocketHan
void CloseTurnHandler(const std::string &token);

void Register();
void SendServerUpdate();
void SendServerUpdate(GameInfoNewGRFMode newgrf_mode);
void GetListing();

void ConnectToServer(const std::string &join_key, TCPServerConnecter *connecter);
Expand Down
5 changes: 4 additions & 1 deletion src/network/network_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,10 @@ class NetworkGameWindow : public Window {
break;

case WID_NG_NEWGRF: // NewGRF Settings
if (this->server != nullptr) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig);
if (this->server != nullptr) {
NetworkQueryServer(this->server->connection_string);
ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig);
}
break;

case WID_NG_NEWGRF_MISSING: // Find missing content online
Expand Down
2 changes: 1 addition & 1 deletion src/network/network_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientIn
NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo()
{
Packet *p = new Packet(PACKET_SERVER_GAME_INFO);
SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo());
SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo(), GAME_INFO_NEWGRF_MODE_FULL);

this->SendPacket(p);

Expand Down

0 comments on commit b2c9f15

Please sign in to comment.