1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

Store and send mod list and game version for game rooms

This commit is contained in:
Ivan Savenko 2024-04-15 13:34:16 +03:00
parent 6ba6e0d55b
commit e5f8cefa7f
12 changed files with 139 additions and 11 deletions

View File

@ -201,6 +201,8 @@ void GlobalLobbyClient::receiveActiveGameRooms(const JsonNode & json)
room.hostAccountDisplayName = jsonEntry["hostAccountDisplayName"].String(); room.hostAccountDisplayName = jsonEntry["hostAccountDisplayName"].String();
room.description = jsonEntry["description"].String(); room.description = jsonEntry["description"].String();
room.statusID = jsonEntry["status"].String(); room.statusID = jsonEntry["status"].String();
room.gameVersion = jsonEntry["version"].String();
room.modList = ModVerificationInfo::jsonDeserializeList(jsonEntry["mods"]);
std::chrono::seconds ageSeconds (jsonEntry["ageSeconds"].Integer()); std::chrono::seconds ageSeconds (jsonEntry["ageSeconds"].Integer());
room.startDateFormatted = TextOperations::getCurrentFormattedDateTimeLocal(-ageSeconds); room.startDateFormatted = TextOperations::getCurrentFormattedDateTimeLocal(-ageSeconds);

View File

@ -9,6 +9,8 @@
*/ */
#pragma once #pragma once
#include "../../lib/modding/ModVerificationInfo.h"
struct GlobalLobbyAccount struct GlobalLobbyAccount
{ {
std::string accountID; std::string accountID;
@ -22,8 +24,10 @@ struct GlobalLobbyRoom
std::string hostAccountID; std::string hostAccountID;
std::string hostAccountDisplayName; std::string hostAccountDisplayName;
std::string description; std::string description;
std::string gameVersion;
std::string statusID; std::string statusID;
std::string startDateFormatted; std::string startDateFormatted;
ModCompatibilityInfo modList;
std::vector<GlobalLobbyAccount> participants; std::vector<GlobalLobbyAccount> participants;
int playerLimit; int playerLimit;
}; };

View File

@ -20,7 +20,7 @@
{ {
"type" : "object", "type" : "object",
"additionalProperties" : false, "additionalProperties" : false,
"required" : [ "gameRoomID", "hostAccountID", "hostAccountDisplayName", "description", "participants", "playerLimit", "status", "ageSeconds" ], "required" : [ "gameRoomID", "hostAccountID", "hostAccountDisplayName", "description", "participants", "playerLimit", "status", "ageSeconds", "mods", "version" ],
"properties" : { "properties" : {
"gameRoomID" : "gameRoomID" :
{ {
@ -65,6 +65,38 @@
} }
} }
}, },
"mods" :
{
"type" : "array",
"description" : "List of gameplay-affecting mods active on server",
"items" : {
"type" : "object",
"additionalProperties" : false,
"required" : [ "modId", "name", "version" ],
"properties" : {
"modId" :
{
"type" : "string",
"description" : "Unique identifier of the mod"
},
"name" :
{
"type" : "string",
"description" : "Human-readable name of the mod"
},
"parent" :
{
"type" : "string",
"description" : "Unique ID of parent mod, only for submods"
},
"version" :
{
"type" : "string",
"description" : "Version of mod, as specified in mod config"
}
}
}
}
"status" : "status" :
{ {
"type" : "string", "type" : "string",
@ -78,6 +110,11 @@
"maximum" : 8, "maximum" : 8,
"description" : "Maximum number of players that can join this room, including host" "description" : "Maximum number of players that can join this room, including host"
}, },
"version" :
{
"type" : "string",
"description" : "Version of match server, e.g. 1.5.0"
},
"ageSeconds" : "ageSeconds" :
{ {
"type" : "number", "type" : "number",

View File

@ -32,6 +32,38 @@
{ {
"type" : "string", "type" : "string",
"description" : "Version of match server, e.g. 1.5.0" "description" : "Version of match server, e.g. 1.5.0"
},
"mods" :
{
"type" : "array",
"description" : "List of gameplay-affecting mods active on server",
"items" : {
"type" : "object",
"additionalProperties" : false,
"required" : [ "modId", "name", "version" ],
"properties" : {
"modId" :
{
"type" : "string",
"description" : "Unique identifier of the mod"
},
"name" :
{
"type" : "string",
"description" : "Human-readable name of the mod"
},
"parent" :
{
"type" : "string",
"description" : "Unique ID of parent mod, only for submods"
},
"version" :
{
"type" : "string",
"description" : "Version of mod, as specified in mod config"
}
}
}
} }
} }
} }

View File

@ -21,6 +21,7 @@ JsonNode ModVerificationInfo::jsonSerializeList(const ModCompatibilityInfo & inp
JsonNode modWriter; JsonNode modWriter;
modWriter["modId"].String() = mod.first; modWriter["modId"].String() = mod.first;
modWriter["name"].String() = mod.second.name; modWriter["name"].String() = mod.second.name;
if (!mod.second.parent.empty())
modWriter["parent"].String() = mod.second.parent; modWriter["parent"].String() = mod.second.parent;
modWriter["version"].String() = mod.second.version.toString(); modWriter["version"].String() = mod.second.version.toString();
output.Vector().push_back(modWriter); output.Vector().push_back(modWriter);

View File

@ -17,7 +17,7 @@ class JsonNode;
struct ModVerificationInfo; struct ModVerificationInfo;
using ModCompatibilityInfo = std::map<std::string, ModVerificationInfo>; using ModCompatibilityInfo = std::map<std::string, ModVerificationInfo>;
struct ModVerificationInfo struct DLL_LINKAGE ModVerificationInfo
{ {
/// human-readable mod name /// human-readable mod name
std::string name; std::string name;

View File

@ -33,7 +33,8 @@ void LobbyDatabase::createTables()
description TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '',
status INTEGER NOT NULL DEFAULT 0, status INTEGER NOT NULL DEFAULT 0,
playerLimit INTEGER NOT NULL, playerLimit INTEGER NOT NULL,
creationTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL creationTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
mods TEXT NOT NULL DEFAULT '[]'
); );
)"; )";
@ -81,6 +82,32 @@ void LobbyDatabase::createTables()
database->prepare(createTableGameRoomInvites)->execute(); database->prepare(createTableGameRoomInvites)->execute();
} }
void LobbyDatabase::upgradeDatabase()
{
auto getDatabaseVersionStatement = database->prepare(R"(
PRAGMA schema.user_version
)");
auto setDatabaseVersionStatement = database->prepare(R"(
PRAGMA schema.user_version = ?
)");
int databaseVersion;
getDatabaseVersionStatement->execute();
getDatabaseVersionStatement->getColumns(databaseVersion);
if (databaseVersion < 10501)
{
database->prepare(R"(
ALTER TABLE gameRooms
ADD COLUMN version TEXT NOT NULL DEFAULT ''
ADD COLUMN mods TEXT NOT NULL DEFAULT '{}'
)")->execute();
setDatabaseVersionStatement->executeOnce(10501);
}
}
void LobbyDatabase::clearOldData() void LobbyDatabase::clearOldData()
{ {
static const std::string removeActiveAccounts = R"( static const std::string removeActiveAccounts = R"(
@ -122,7 +149,7 @@ void LobbyDatabase::prepareStatements()
)"); )");
insertGameRoomStatement = database->prepare(R"( insertGameRoomStatement = database->prepare(R"(
INSERT INTO gameRooms(roomID, hostAccountID, status, playerLimit) VALUES(?, ?, 0, 8); INSERT INTO gameRooms(roomID, hostAccountID, status, playerLimit, version, mods) VALUES(?, ?, 0, 8, ?, ?);
)"); )");
insertGameRoomPlayersStatement = database->prepare(R"( insertGameRoomPlayersStatement = database->prepare(R"(
@ -233,7 +260,7 @@ void LobbyDatabase::prepareStatements()
)"); )");
getActiveGameRoomsStatement = database->prepare(R"( getActiveGameRoomsStatement = database->prepare(R"(
SELECT roomID, hostAccountID, displayName, description, status, playerLimit, strftime('%s',CURRENT_TIMESTAMP)- strftime('%s',gr.creationTime) AS secondsElapsed SELECT roomID, hostAccountID, displayName, description, status, playerLimit, mods, strftime('%s',CURRENT_TIMESTAMP)- strftime('%s',gr.creationTime) AS secondsElapsed
FROM gameRooms gr FROM gameRooms gr
LEFT JOIN accounts a ON gr.hostAccountID = a.accountID LEFT JOIN accounts a ON gr.hostAccountID = a.accountID
WHERE status IN (1, 2, 3) WHERE status IN (1, 2, 3)
@ -298,6 +325,7 @@ LobbyDatabase::LobbyDatabase(const boost::filesystem::path & databasePath)
{ {
database = SQLiteInstance::open(databasePath, true); database = SQLiteInstance::open(databasePath, true);
createTables(); createTables();
upgradeDatabase();
clearOldData(); clearOldData();
prepareStatements(); prepareStatements();
} }
@ -393,9 +421,9 @@ void LobbyDatabase::insertGameRoomInvite(const std::string & targetAccountID, co
insertGameRoomInvitesStatement->executeOnce(roomID, targetAccountID); insertGameRoomInvitesStatement->executeOnce(roomID, targetAccountID);
} }
void LobbyDatabase::insertGameRoom(const std::string & roomID, const std::string & hostAccountID) void LobbyDatabase::insertGameRoom(const std::string & roomID, const std::string & hostAccountID, const std::string & serverVersion, const std::string & modListJson)
{ {
insertGameRoomStatement->executeOnce(roomID, hostAccountID); insertGameRoomStatement->executeOnce(roomID, hostAccountID, serverVersion, modListJson);
} }
void LobbyDatabase::insertAccount(const std::string & accountID, const std::string & displayName) void LobbyDatabase::insertAccount(const std::string & accountID, const std::string & displayName)
@ -526,7 +554,7 @@ std::vector<LobbyGameRoom> LobbyDatabase::getActiveGameRooms()
while(getActiveGameRoomsStatement->execute()) while(getActiveGameRoomsStatement->execute())
{ {
LobbyGameRoom entry; LobbyGameRoom entry;
getActiveGameRoomsStatement->getColumns(entry.roomID, entry.hostAccountID, entry.hostAccountDisplayName, entry.description, entry.roomState, entry.playerLimit, entry.age); getActiveGameRoomsStatement->getColumns(entry.roomID, entry.hostAccountID, entry.hostAccountDisplayName, entry.description, entry.roomState, entry.playerLimit, entry.version, entry.modsJson, entry.age);
result.push_back(entry); result.push_back(entry);
} }
getActiveGameRoomsStatement->reset(); getActiveGameRoomsStatement->reset();

View File

@ -59,6 +59,7 @@ class LobbyDatabase
void prepareStatements(); void prepareStatements();
void createTables(); void createTables();
void upgradeDatabase();
void clearOldData(); void clearOldData();
public: public:
@ -74,7 +75,7 @@ public:
void deleteGameRoomInvite(const std::string & targetAccountID, const std::string & roomID); void deleteGameRoomInvite(const std::string & targetAccountID, const std::string & roomID);
void insertGameRoomInvite(const std::string & targetAccountID, const std::string & roomID); void insertGameRoomInvite(const std::string & targetAccountID, const std::string & roomID);
void insertGameRoom(const std::string & roomID, const std::string & hostAccountID); void insertGameRoom(const std::string & roomID, const std::string & hostAccountID, const std::string & serverVersion, const std::string & modListJson);
void insertAccount(const std::string & accountID, const std::string & displayName); void insertAccount(const std::string & accountID, const std::string & displayName);
void insertAccessCookie(const std::string & accountID, const std::string & accessCookieUUID); void insertAccessCookie(const std::string & accountID, const std::string & accessCookieUUID);
void insertChatMessage(const std::string & sender, const std::string & channelType, const std::string & roomID, const std::string & messageText); void insertChatMessage(const std::string & sender, const std::string & channelType, const std::string & roomID, const std::string & messageText);

View File

@ -44,6 +44,8 @@ struct LobbyGameRoom
std::string hostAccountID; std::string hostAccountID;
std::string hostAccountDisplayName; std::string hostAccountDisplayName;
std::string description; std::string description;
std::string version;
std::string modsJson;
std::vector<LobbyAccount> participants; std::vector<LobbyAccount> participants;
LobbyRoomState roomState; LobbyRoomState roomState;
uint32_t playerLimit; uint32_t playerLimit;

View File

@ -208,9 +208,11 @@ static JsonNode loadLobbyGameRoomToJson(const LobbyGameRoom & gameRoom)
jsonEntry["hostAccountID"].String() = gameRoom.hostAccountID; jsonEntry["hostAccountID"].String() = gameRoom.hostAccountID;
jsonEntry["hostAccountDisplayName"].String() = gameRoom.hostAccountDisplayName; jsonEntry["hostAccountDisplayName"].String() = gameRoom.hostAccountDisplayName;
jsonEntry["description"].String() = gameRoom.description; jsonEntry["description"].String() = gameRoom.description;
jsonEntry["version"].String() = gameRoom.version;
jsonEntry["status"].String() = LOBBY_ROOM_STATE_NAMES[vstd::to_underlying(gameRoom.roomState)]; jsonEntry["status"].String() = LOBBY_ROOM_STATE_NAMES[vstd::to_underlying(gameRoom.roomState)];
jsonEntry["playerLimit"].Integer() = gameRoom.playerLimit; jsonEntry["playerLimit"].Integer() = gameRoom.playerLimit;
jsonEntry["ageSeconds"].Integer() = gameRoom.age.count(); jsonEntry["ageSeconds"].Integer() = gameRoom.age.count();
jsonEntry["mods"] = JsonNode(reinterpret_cast<const std::byte *>(gameRoom.modsJson.data()), gameRoom.modsJson.size());
for(const auto & account : gameRoom.participants) for(const auto & account : gameRoom.participants)
jsonEntry["participants"].Vector().push_back(loadLobbyAccountToJson(account)); jsonEntry["participants"].Vector().push_back(loadLobbyAccountToJson(account));
@ -625,7 +627,8 @@ void LobbyServer::receiveServerLogin(const NetworkConnectionPtr & connection, co
} }
else else
{ {
database->insertGameRoom(gameRoomID, accountID); std::string modListString = json["mods"].isNull() ? "[]" : json["mods"].toCompactString();
database->insertGameRoom(gameRoomID, accountID, version, modListString);
activeGameRooms[connection] = gameRoomID; activeGameRooms[connection] = gameRoomID;
sendServerLoginSuccess(connection, accountCookie); sendServerLoginSuccess(connection, accountCookie);
broadcastActiveGameRooms(); broadcastActiveGameRooms();

View File

@ -13,6 +13,9 @@
#include "CVCMIServer.h" #include "CVCMIServer.h"
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
#include "../lib/json/JsonUtils.h" #include "../lib/json/JsonUtils.h"
#include "../lib/VCMI_Lib.h"
#include "../lib/modding/CModHandler.h"
#include "../lib/modding/CModInfo.h"
GlobalLobbyProcessor::GlobalLobbyProcessor(CVCMIServer & owner) GlobalLobbyProcessor::GlobalLobbyProcessor(CVCMIServer & owner)
: owner(owner) : owner(owner)
@ -125,6 +128,7 @@ void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetwor
toSend["accountID"].String() = getHostAccountID(); toSend["accountID"].String() = getHostAccountID();
toSend["accountCookie"].String() = getHostAccountCookie(); toSend["accountCookie"].String() = getHostAccountCookie();
toSend["version"].String() = VCMI_VERSION_STRING; toSend["version"].String() = VCMI_VERSION_STRING;
toSend["mods"] = getHostModList();
sendMessage(connection, toSend); sendMessage(connection, toSend);
} }
@ -149,6 +153,19 @@ void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetwor
} }
} }
JsonNode GlobalLobbyProcessor::getHostModList() const
{
ModCompatibilityInfo info;
for (auto const & modName : VLC->modh->getActiveMods())
{
if(VLC->modh->getModInfo(modName).checkModGameplayAffecting())
info[modName] = VLC->modh->getModInfo(modName).getVerificationInfo();
}
return ModVerificationInfo::jsonSerializeList(info);
}
void GlobalLobbyProcessor::sendGameStarted() void GlobalLobbyProcessor::sendGameStarted()
{ {
JsonNode toSend; JsonNode toSend;

View File

@ -36,6 +36,7 @@ class GlobalLobbyProcessor : public INetworkClientListener
void establishNewConnection(); void establishNewConnection();
void sendMessage(const NetworkConnectionPtr & targetConnection, const JsonNode & payload); void sendMessage(const NetworkConnectionPtr & targetConnection, const JsonNode & payload);
JsonNode getHostModList() const;
const std::string & getHostAccountID() const; const std::string & getHostAccountID() const;
const std::string & getHostAccountCookie() const; const std::string & getHostAccountCookie() const;
const std::string & getHostAccountDisplayName() const; const std::string & getHostAccountDisplayName() const;