1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-21 17:17:06 +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.description = jsonEntry["description"].String();
room.statusID = jsonEntry["status"].String();
room.gameVersion = jsonEntry["version"].String();
room.modList = ModVerificationInfo::jsonDeserializeList(jsonEntry["mods"]);
std::chrono::seconds ageSeconds (jsonEntry["ageSeconds"].Integer());
room.startDateFormatted = TextOperations::getCurrentFormattedDateTimeLocal(-ageSeconds);

View File

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

View File

@ -20,7 +20,7 @@
{
"type" : "object",
"additionalProperties" : false,
"required" : [ "gameRoomID", "hostAccountID", "hostAccountDisplayName", "description", "participants", "playerLimit", "status", "ageSeconds" ],
"required" : [ "gameRoomID", "hostAccountID", "hostAccountDisplayName", "description", "participants", "playerLimit", "status", "ageSeconds", "mods", "version" ],
"properties" : {
"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" :
{
"type" : "string",
@ -78,6 +110,11 @@
"maximum" : 8,
"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" :
{
"type" : "number",

View File

@ -32,6 +32,38 @@
{
"type" : "string",
"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,7 +21,8 @@ JsonNode ModVerificationInfo::jsonSerializeList(const ModCompatibilityInfo & inp
JsonNode modWriter;
modWriter["modId"].String() = mod.first;
modWriter["name"].String() = mod.second.name;
modWriter["parent"].String() = mod.second.parent;
if (!mod.second.parent.empty())
modWriter["parent"].String() = mod.second.parent;
modWriter["version"].String() = mod.second.version.toString();
output.Vector().push_back(modWriter);
}

View File

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

View File

@ -33,7 +33,8 @@ void LobbyDatabase::createTables()
description TEXT NOT NULL DEFAULT '',
status INTEGER NOT NULL DEFAULT 0,
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();
}
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()
{
static const std::string removeActiveAccounts = R"(
@ -122,7 +149,7 @@ void LobbyDatabase::prepareStatements()
)");
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"(
@ -233,7 +260,7 @@ void LobbyDatabase::prepareStatements()
)");
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
LEFT JOIN accounts a ON gr.hostAccountID = a.accountID
WHERE status IN (1, 2, 3)
@ -298,6 +325,7 @@ LobbyDatabase::LobbyDatabase(const boost::filesystem::path & databasePath)
{
database = SQLiteInstance::open(databasePath, true);
createTables();
upgradeDatabase();
clearOldData();
prepareStatements();
}
@ -393,9 +421,9 @@ void LobbyDatabase::insertGameRoomInvite(const std::string & targetAccountID, co
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)
@ -526,7 +554,7 @@ std::vector<LobbyGameRoom> LobbyDatabase::getActiveGameRooms()
while(getActiveGameRoomsStatement->execute())
{
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);
}
getActiveGameRoomsStatement->reset();

View File

@ -59,6 +59,7 @@ class LobbyDatabase
void prepareStatements();
void createTables();
void upgradeDatabase();
void clearOldData();
public:
@ -74,7 +75,7 @@ public:
void deleteGameRoomInvite(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 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);

View File

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

View File

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

View File

@ -13,6 +13,9 @@
#include "CVCMIServer.h"
#include "../lib/CConfigHandler.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)
: owner(owner)
@ -125,6 +128,7 @@ void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetwor
toSend["accountID"].String() = getHostAccountID();
toSend["accountCookie"].String() = getHostAccountCookie();
toSend["version"].String() = VCMI_VERSION_STRING;
toSend["mods"] = getHostModList();
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()
{
JsonNode toSend;

View File

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