diff --git a/server/gamedb_init.sql b/server/gamedb_init.sql index 73fb98b366a6cce9f9b83d41c41d3229e7f2647e..a225cfd1639b09168a6eb693ebda90a6eccf783a 100644 --- a/server/gamedb_init.sql +++ b/server/gamedb_init.sql @@ -9,4 +9,15 @@ CREATE TABLE IF NOT EXISTS gameSaves ( ); CREATE INDEX IF NOT EXISTS idx_gameSaves_uid ON gameSaves(uid); -CREATE INDEX IF NOT EXISTS idx_gameSaves_mode ON gameSaves(mode); \ No newline at end of file +CREATE INDEX IF NOT EXISTS idx_gameSaves_mode ON gameSaves(mode); + +CREATE TABLE IF NOT EXISTS globalSaves ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + uid INTEGER NOT NULL, + key TEXT NOT NULL, + data BLOB NOT NULL, + UNIQUE(uid, key) +); + +CREATE INDEX IF NOT EXISTS idx_globalSaves_uid ON globalSaves(uid); +CREATE INDEX IF NOT EXISTS idx_globalSaves_key ON globalSaves(key); diff --git a/src/server/gamelogic/rpc-dispatchers.cpp b/src/server/gamelogic/rpc-dispatchers.cpp index a8136d8132740bec0651aef389376826ff7cf6a0..e54e88b294e315a60b298ad862808f337d7037a8 100644 --- a/src/server/gamelogic/rpc-dispatchers.cpp +++ b/src/server/gamelogic/rpc-dispatchers.cpp @@ -418,40 +418,44 @@ static _rpcRet _rpc_Player_getSaveState(const JsonRpcPacket &packet) { } static _rpcRet _rpc_Player_saveGlobalState(const JsonRpcPacket &packet) { - if (!(packet.param_count == 2 && + if (!(packet.param_count == 3 && std::holds_alternative(packet.param1) && - std::holds_alternative(packet.param2) + std::holds_alternative(packet.param2) && + std::holds_alternative(packet.param3) )) { return { false, nullVal }; } auto connId = std::get(packet.param1); - auto jsonData = std::get(packet.param2); + auto key = std::get(packet.param2); + auto jsonData = std::get(packet.param3); auto player = Server::instance().user_manager().findPlayerByConnId(connId).lock(); if (!player) { return { false, nullVal }; } - player->saveGlobalState(jsonData); + player->saveGlobalState(key, jsonData); return { true, nullVal }; } static _rpcRet _rpc_Player_getGlobalSaveState(const JsonRpcPacket &packet) { - if (!(packet.param_count == 1 && - std::holds_alternative(packet.param1) + if (!(packet.param_count == 2 && + std::holds_alternative(packet.param1) && + std::holds_alternative(packet.param2) )) { return { false, nullVal }; } auto connId = std::get(packet.param1); + auto key = std::get(packet.param2); auto player = Server::instance().user_manager().findPlayerByConnId(connId).lock(); if (!player) { return { false, nullVal }; } - std::string result = player->getGlobalSaveState(); + std::string result = player->getGlobalSaveState(key); return { true, result }; } diff --git a/src/server/user/player.cpp b/src/server/user/player.cpp index 8679e2614e127865490ecf15f381a20cb2f1a51e..e25b3129b6918a3fc55db44625cf56e031d731fb 100644 --- a/src/server/user/player.cpp +++ b/src/server/user/player.cpp @@ -403,14 +403,6 @@ std::string Player::getSaveState() { return readSaveState(mode); } -void Player::saveGlobalState(std::string_view jsonData) { - writeSaveState("__global__", jsonData); -} - -std::string Player::getGlobalSaveState() { - return readSaveState("__global__"); -} - void Player::writeSaveState(std::string mode, std::string_view jsonData) { if (!Sqlite3::checkString(mode)) { spdlog::error("Invalid mode string for saveState: {}", mode); @@ -421,7 +413,7 @@ void Player::writeSaveState(std::string mode, std::string_view jsonData) { auto &gamedb = Server::instance().gameDatabase(); auto sql = fmt::format("REPLACE INTO gameSaves (uid, mode, data) VALUES ({},'{}',X'{}')", id, mode, hexData); - gamedb.exec(sql);; + gamedb.exec(sql); } std::string Player::readSaveState(std::string mode) { @@ -442,6 +434,42 @@ std::string Player::readSaveState(std::string mode) { return data; } + spdlog::warn("Returned data is not valid JSON: {}", data); + return "{}"; +} + +void Player::saveGlobalState(std::string_view key, std::string_view jsonData) { + if (!Sqlite3::checkString(key)) { + spdlog::error("Invalid key string for saveGlobalState: {}", std::string(key)); + return; + } + + auto hexData = toHex(jsonData); + auto &gamedb = Server::instance().gameDatabase(); + auto sql = fmt::format("REPLACE INTO globalSaves (uid, key, data) VALUES ({},'{}',X'{}')", id, key, hexData); + + gamedb.exec(sql); +} + + +std::string Player::getGlobalSaveState(std::string_view key) { + if (!Sqlite3::checkString(key)) { + spdlog::error("Invalid key string for getGlobalSaveState: {}", std::string(key)); + return "{}"; + } + + auto sql = fmt::format("SELECT data FROM globalSaves WHERE uid = {} AND key = '{}'", id, key); + + auto result = Server::instance().gameDatabase().select(sql); + if (result.empty() || result[0].count("data") == 0 || result[0]["data"] == "#null") { + return "{}"; + } + + const auto& data = result[0]["data"]; + if (!data.empty() && (data[0] == '{' || data[0] == '[')) { + return data; + } + spdlog::warn("Returned data is not valid JSON: {}", data); return "{}"; } \ No newline at end of file diff --git a/src/server/user/player.h b/src/server/user/player.h index 1b751953be41ec7c34b5bbb34590bc40e36e43cb..e00c6ae1d32a41529b862092e83912393229d5c4 100644 --- a/src/server/user/player.h +++ b/src/server/user/player.h @@ -100,8 +100,8 @@ public: void saveState(std::string_view jsonData); std::string getSaveState(); // 全局存档 - void saveGlobalState(std::string_view jsonData); - std::string getGlobalSaveState(); + void saveGlobalState(std::string_view key, std::string_view jsonData); + std::string getGlobalSaveState(std::string_view key); private: int id = 0;