mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #12373 from ZehMatt/network/connect-update
Improve connecting to servers
This commit is contained in:
commit
649757b77d
|
@ -3664,6 +3664,7 @@ STR_6374 :C
|
|||
STR_6375 :Unknown Ride
|
||||
STR_6376 :{WINDOW_COLOUR_2}Ride vehicle:{NEWLINE}{BLACK}{STRINGID} for {STRINGID}
|
||||
STR_6377 :{WINDOW_COLOUR_2}Type: {BLACK}{STRINGID} for {STRINGID}
|
||||
STR_6378 :Receiving objects list: {INT32} / {INT32}
|
||||
|
||||
#############
|
||||
# Scenarios #
|
||||
|
|
|
@ -3906,6 +3906,8 @@ enum
|
|||
STR_RESEARCH_VEHICLE_LABEL = 6376,
|
||||
STR_RESEARCH_TYPE_LABEL_VEHICLE = 6377,
|
||||
|
||||
STR_MULTIPLAYER_RECEIVING_OBJECTS_LIST = 6378,
|
||||
|
||||
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
|
||||
/* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings
|
||||
};
|
||||
|
|
|
@ -193,9 +193,10 @@ public:
|
|||
void Server_Send_EVENT_PLAYER_JOINED(const char* playerName);
|
||||
void Server_Send_EVENT_PLAYER_DISCONNECTED(const char* playerName, const char* reason);
|
||||
void Client_Send_GAMEINFO();
|
||||
void Client_Send_OBJECTS(const std::vector<std::string>& objects);
|
||||
void Server_Send_OBJECTS(NetworkConnection& connection, const std::vector<const ObjectRepositoryItem*>& objects) const;
|
||||
void Client_Send_MAPREQUEST(const std::vector<std::string>& objects);
|
||||
void Server_Send_OBJECTS_LIST(NetworkConnection& connection, const std::vector<const ObjectRepositoryItem*>& objects) const;
|
||||
void Server_Send_SCRIPTS(NetworkConnection& connection) const;
|
||||
void Client_Send_HEARTBEAT(NetworkConnection& connection) const;
|
||||
|
||||
NetworkStats_t GetStats() const;
|
||||
json_t* GetServerInfoAsJson() const;
|
||||
|
@ -275,11 +276,13 @@ private:
|
|||
uint32_t _actionId;
|
||||
uint32_t _lastUpdateTime = 0;
|
||||
uint32_t _currentDeltaTime = 0;
|
||||
uint32_t _lastSentHeartbeat = 0;
|
||||
std::string _chatLogPath;
|
||||
std::string _chatLogFilenameFormat = "%Y%m%d-%H%M%S.txt";
|
||||
std::string _serverLogPath;
|
||||
std::string _serverLogFilenameFormat = "%Y%m%d-%H%M%S.txt";
|
||||
std::shared_ptr<OpenRCT2::IPlatformEnvironment> _env;
|
||||
std::vector<std::string> _missingObjects;
|
||||
|
||||
void UpdateServer();
|
||||
void UpdateClient();
|
||||
|
@ -288,6 +291,7 @@ private:
|
|||
std::vector<void (Network::*)(NetworkConnection& connection, NetworkPacket& packet)> client_command_handlers;
|
||||
std::vector<void (Network::*)(NetworkConnection& connection, NetworkPacket& packet)> server_command_handlers;
|
||||
void Server_Handle_REQUEST_GAMESTATE(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Server_Handle_HEARTBEAT(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Client_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Server_Client_Joined(const char* name, const std::string& keyhash, NetworkConnection& connection);
|
||||
|
@ -310,10 +314,10 @@ private:
|
|||
void Client_Handle_EVENT(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Client_Handle_TOKEN(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Server_Handle_TOKEN(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Client_Handle_SCRIPTS(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Client_Handle_GAMESTATE(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet);
|
||||
void Server_Handle_MAPREQUEST(NetworkConnection& connection, NetworkPacket& packet);
|
||||
|
||||
uint8_t* save_for_network(size_t& out_size, const std::vector<const ObjectRepositoryItem*>& objects) const;
|
||||
|
||||
|
@ -346,7 +350,7 @@ Network::Network()
|
|||
client_command_handlers[NETWORK_COMMAND_EVENT] = &Network::Client_Handle_EVENT;
|
||||
client_command_handlers[NETWORK_COMMAND_GAMEINFO] = &Network::Client_Handle_GAMEINFO;
|
||||
client_command_handlers[NETWORK_COMMAND_TOKEN] = &Network::Client_Handle_TOKEN;
|
||||
client_command_handlers[NETWORK_COMMAND_OBJECTS] = &Network::Client_Handle_OBJECTS;
|
||||
client_command_handlers[NETWORK_COMMAND_OBJECTS_LIST] = &Network::Client_Handle_OBJECTS_LIST;
|
||||
client_command_handlers[NETWORK_COMMAND_SCRIPTS] = &Network::Client_Handle_SCRIPTS;
|
||||
client_command_handlers[NETWORK_COMMAND_GAMESTATE] = &Network::Client_Handle_GAMESTATE;
|
||||
server_command_handlers.resize(NETWORK_COMMAND_MAX, nullptr);
|
||||
|
@ -356,8 +360,9 @@ Network::Network()
|
|||
server_command_handlers[NETWORK_COMMAND_PING] = &Network::Server_Handle_PING;
|
||||
server_command_handlers[NETWORK_COMMAND_GAMEINFO] = &Network::Server_Handle_GAMEINFO;
|
||||
server_command_handlers[NETWORK_COMMAND_TOKEN] = &Network::Server_Handle_TOKEN;
|
||||
server_command_handlers[NETWORK_COMMAND_OBJECTS] = &Network::Server_Handle_OBJECTS;
|
||||
server_command_handlers[NETWORK_COMMAND_MAPREQUEST] = &Network::Server_Handle_MAPREQUEST;
|
||||
server_command_handlers[NETWORK_COMMAND_REQUEST_GAMESTATE] = &Network::Server_Handle_REQUEST_GAMESTATE;
|
||||
server_command_handlers[NETWORK_COMMAND_HEARTBEAT] = &Network::Server_Handle_HEARTBEAT;
|
||||
|
||||
_chat_log_fs << std::unitbuf;
|
||||
_server_log_fs << std::unitbuf;
|
||||
|
@ -864,6 +869,16 @@ void Network::UpdateClient()
|
|||
window_close_by_class(WC_MULTIPLAYER);
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t ticks = platform_get_ticks();
|
||||
if (ticks - _lastSentHeartbeat >= 3000)
|
||||
{
|
||||
Client_Send_HEARTBEAT(*_serverConnection);
|
||||
_lastSentHeartbeat = ticks;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1449,11 +1464,11 @@ void Network::Client_Send_AUTH(
|
|||
_serverConnection->QueuePacket(std::move(packet));
|
||||
}
|
||||
|
||||
void Network::Client_Send_OBJECTS(const std::vector<std::string>& objects)
|
||||
void Network::Client_Send_MAPREQUEST(const std::vector<std::string>& objects)
|
||||
{
|
||||
log_verbose("client requests %u objects", uint32_t(objects.size()));
|
||||
std::unique_ptr<NetworkPacket> packet(NetworkPacket::Allocate());
|
||||
*packet << static_cast<uint32_t>(NETWORK_COMMAND_OBJECTS) << static_cast<uint32_t>(objects.size());
|
||||
*packet << static_cast<uint32_t>(NETWORK_COMMAND_MAPREQUEST) << static_cast<uint32_t>(objects.size());
|
||||
for (const auto& object : objects)
|
||||
{
|
||||
log_verbose("client requests object %s", object.c_str());
|
||||
|
@ -1470,18 +1485,36 @@ void Network::Server_Send_TOKEN(NetworkConnection& connection)
|
|||
connection.QueuePacket(std::move(packet));
|
||||
}
|
||||
|
||||
void Network::Server_Send_OBJECTS(NetworkConnection& connection, const std::vector<const ObjectRepositoryItem*>& objects) const
|
||||
void Network::Server_Send_OBJECTS_LIST(
|
||||
NetworkConnection& connection, const std::vector<const ObjectRepositoryItem*>& objects) const
|
||||
{
|
||||
log_verbose("Server sends objects list with %u items", objects.size());
|
||||
std::unique_ptr<NetworkPacket> packet(NetworkPacket::Allocate());
|
||||
*packet << static_cast<uint32_t>(NETWORK_COMMAND_OBJECTS) << static_cast<uint32_t>(objects.size());
|
||||
for (auto object : objects)
|
||||
|
||||
if (objects.empty())
|
||||
{
|
||||
log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum);
|
||||
packet->Write(reinterpret_cast<const uint8_t*>(object->ObjectEntry.name), 8);
|
||||
*packet << object->ObjectEntry.checksum << object->ObjectEntry.flags;
|
||||
std::unique_ptr<NetworkPacket> packet(NetworkPacket::Allocate());
|
||||
*packet << static_cast<uint32_t>(NETWORK_COMMAND_OBJECTS_LIST) << static_cast<uint32_t>(0)
|
||||
<< static_cast<uint32_t>(objects.size());
|
||||
|
||||
connection.QueuePacket(std::move(packet));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < objects.size(); ++i)
|
||||
{
|
||||
const auto* object = objects[i];
|
||||
|
||||
std::unique_ptr<NetworkPacket> packet(NetworkPacket::Allocate());
|
||||
*packet << static_cast<uint32_t>(NETWORK_COMMAND_OBJECTS_LIST) << static_cast<uint32_t>(i)
|
||||
<< static_cast<uint32_t>(objects.size());
|
||||
|
||||
log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum);
|
||||
packet->Write(reinterpret_cast<const uint8_t*>(object->ObjectEntry.name), 8);
|
||||
*packet << object->ObjectEntry.checksum << object->ObjectEntry.flags;
|
||||
|
||||
connection.QueuePacket(std::move(packet));
|
||||
}
|
||||
}
|
||||
connection.QueuePacket(std::move(packet));
|
||||
}
|
||||
|
||||
void Network::Server_Send_SCRIPTS(NetworkConnection& connection) const
|
||||
|
@ -1520,6 +1553,16 @@ void Network::Server_Send_SCRIPTS(NetworkConnection& connection) const
|
|||
connection.QueuePacket(std::move(packet));
|
||||
}
|
||||
|
||||
void Network::Client_Send_HEARTBEAT(NetworkConnection& connection) const
|
||||
{
|
||||
log_verbose("Sending heartbeat");
|
||||
|
||||
std::unique_ptr<NetworkPacket> packet(NetworkPacket::Allocate());
|
||||
*packet << static_cast<uint32_t>(NETWORK_COMMAND_HEARTBEAT);
|
||||
|
||||
connection.QueuePacket(std::move(packet));
|
||||
}
|
||||
|
||||
NetworkStats_t Network::GetStats() const
|
||||
{
|
||||
NetworkStats_t stats = {};
|
||||
|
@ -2444,6 +2487,12 @@ void Network::Server_Handle_REQUEST_GAMESTATE(NetworkConnection& connection, Net
|
|||
}
|
||||
}
|
||||
|
||||
void Network::Server_Handle_HEARTBEAT(NetworkConnection& connection, NetworkPacket& packet)
|
||||
{
|
||||
log_verbose("Client %s heartbeat", connection.Socket->GetHostName());
|
||||
connection.ResetLastPacketTime();
|
||||
}
|
||||
|
||||
void Network::Client_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet)
|
||||
{
|
||||
uint32_t auth_status;
|
||||
|
@ -2505,7 +2554,7 @@ void Network::Server_Client_Joined(const char* name, const std::string& keyhash,
|
|||
auto context = GetContext();
|
||||
auto& objManager = context->GetObjectManager();
|
||||
auto objects = objManager.GetPackableObjects();
|
||||
Server_Send_OBJECTS(connection, objects);
|
||||
Server_Send_OBJECTS_LIST(connection, objects);
|
||||
Server_Send_SCRIPTS(connection);
|
||||
|
||||
// Log player joining event
|
||||
|
@ -2529,43 +2578,71 @@ void Network::Server_Handle_TOKEN(NetworkConnection& connection, [[maybe_unused]
|
|||
Server_Send_TOKEN(connection);
|
||||
}
|
||||
|
||||
void Network::Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet)
|
||||
void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkPacket& packet)
|
||||
{
|
||||
auto& repo = GetContext()->GetObjectRepository();
|
||||
uint32_t size;
|
||||
packet >> size;
|
||||
log_verbose("client received object list, it has %u entries", size);
|
||||
if (size > OBJECT_ENTRY_COUNT)
|
||||
|
||||
uint32_t index = 0;
|
||||
uint32_t totalObjects = 0;
|
||||
packet >> index >> totalObjects;
|
||||
|
||||
static constexpr uint32_t OBJECT_START_INDEX = 0;
|
||||
if (index == OBJECT_START_INDEX)
|
||||
{
|
||||
_missingObjects.clear();
|
||||
}
|
||||
|
||||
if (totalObjects > OBJECT_ENTRY_COUNT)
|
||||
{
|
||||
connection.SetLastDisconnectReason(STR_MULTIPLAYER_SERVER_INVALID_REQUEST);
|
||||
connection.Socket->Disconnect();
|
||||
log_warning("Server sent invalid amount of objects");
|
||||
return;
|
||||
}
|
||||
std::vector<std::string> requested_objects;
|
||||
for (uint32_t i = 0; i < size; i++)
|
||||
|
||||
if (totalObjects > 0)
|
||||
{
|
||||
const char* name = reinterpret_cast<const char*>(packet.Read(8));
|
||||
// Required, as packet has no null terminators.
|
||||
std::string s(name, name + 8);
|
||||
uint32_t checksum, flags;
|
||||
char objectListMsg[256];
|
||||
const uint32_t args[] = {
|
||||
index + 1,
|
||||
totalObjects,
|
||||
};
|
||||
format_string(objectListMsg, 256, STR_MULTIPLAYER_RECEIVING_OBJECTS_LIST, &args);
|
||||
|
||||
auto intent = Intent(WC_NETWORK_STATUS);
|
||||
intent.putExtra(INTENT_EXTRA_MESSAGE, std::string{ objectListMsg });
|
||||
intent.putExtra(INTENT_EXTRA_CALLBACK, []() -> void { gNetwork.Close(); });
|
||||
context_open_intent(&intent);
|
||||
|
||||
char objectName[12]{};
|
||||
std::memcpy(objectName, packet.Read(8), 8);
|
||||
|
||||
uint32_t checksum = 0;
|
||||
uint32_t flags = 0;
|
||||
packet >> checksum >> flags;
|
||||
const ObjectRepositoryItem* ori = repo.FindObject(s.c_str());
|
||||
|
||||
const auto* object = repo.FindObject(objectName);
|
||||
// This could potentially request the object if checksums don't match, but since client
|
||||
// won't replace its version with server-provided one, we don't do that.
|
||||
if (ori == nullptr)
|
||||
if (object == nullptr)
|
||||
{
|
||||
log_verbose("Requesting object %s with checksum %x from server", s.c_str(), checksum);
|
||||
requested_objects.push_back(s);
|
||||
log_verbose("Requesting object %s with checksum %x from server", objectName, checksum);
|
||||
_missingObjects.push_back(objectName);
|
||||
}
|
||||
else if (ori->ObjectEntry.checksum != checksum || ori->ObjectEntry.flags != flags)
|
||||
else if (object->ObjectEntry.checksum != checksum || object->ObjectEntry.flags != flags)
|
||||
{
|
||||
log_warning(
|
||||
"Object %s has different checksum/flags (%x/%x) than server (%x/%x).", s.c_str(), ori->ObjectEntry.checksum,
|
||||
ori->ObjectEntry.flags, checksum, flags);
|
||||
"Object %s has different checksum/flags (%x/%x) than server (%x/%x).", objectName, object->ObjectEntry.checksum,
|
||||
object->ObjectEntry.flags, checksum, flags);
|
||||
}
|
||||
}
|
||||
Client_Send_OBJECTS(requested_objects);
|
||||
|
||||
if (index + 1 >= totalObjects)
|
||||
{
|
||||
log_verbose("client received object list, it has %u entries", totalObjects);
|
||||
Client_Send_MAPREQUEST(_missingObjects);
|
||||
_missingObjects.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Network::Client_Handle_SCRIPTS(NetworkConnection& connection, NetworkPacket& packet)
|
||||
|
@ -2660,7 +2737,7 @@ void Network::Client_Handle_GAMESTATE(NetworkConnection& connection, NetworkPack
|
|||
}
|
||||
}
|
||||
|
||||
void Network::Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet)
|
||||
void Network::Server_Handle_MAPREQUEST(NetworkConnection& connection, NetworkPacket& packet)
|
||||
{
|
||||
uint32_t size;
|
||||
packet >> size;
|
||||
|
|
|
@ -57,7 +57,9 @@ bool NetworkPacket::CommandRequiresAuth()
|
|||
case NETWORK_COMMAND_AUTH:
|
||||
case NETWORK_COMMAND_TOKEN:
|
||||
case NETWORK_COMMAND_GAMEINFO:
|
||||
case NETWORK_COMMAND_OBJECTS:
|
||||
case NETWORK_COMMAND_OBJECTS_LIST:
|
||||
case NETWORK_COMMAND_MAPREQUEST:
|
||||
case NETWORK_COMMAND_HEARTBEAT:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
|
|
|
@ -63,12 +63,14 @@ enum NETWORK_COMMAND
|
|||
NETWORK_COMMAND_GROUPLIST,
|
||||
NETWORK_COMMAND_EVENT,
|
||||
NETWORK_COMMAND_TOKEN,
|
||||
NETWORK_COMMAND_OBJECTS,
|
||||
NETWORK_COMMAND_OBJECTS_LIST,
|
||||
NETWORK_COMMAND_MAPREQUEST,
|
||||
NETWORK_COMMAND_GAME_ACTION,
|
||||
NETWORK_COMMAND_PLAYERINFO,
|
||||
NETWORK_COMMAND_REQUEST_GAMESTATE,
|
||||
NETWORK_COMMAND_GAMESTATE,
|
||||
NETWORK_COMMAND_SCRIPTS,
|
||||
NETWORK_COMMAND_HEARTBEAT,
|
||||
NETWORK_COMMAND_MAX,
|
||||
NETWORK_COMMAND_INVALID = -1
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue