diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 01df718..faf0227 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -224,18 +224,22 @@ static void enterPlayer(CNSocket* sock, CNPacketData* data) { return; } - // for convenience - Player& plr = lm->plr; - - plr.groupCnt = 1; - plr.iIDGroup = plr.groupIDs[0] = plr.iID; + Player plr = {}; + Database::getPlayer(&plr, lm->playerId); // check if account is already in use if (isAccountInUse(plr.accountId)) { // kick the other player exitDuplicate(plr.accountId); + + // re-read the player from disk, in case it was just flushed + plr = {}; + Database::getPlayer(&plr, lm->playerId); } + plr.groupCnt = 1; + plr.iIDGroup = plr.groupIDs[0] = plr.iID; + response.iID = plr.iID; response.uiSvrTime = getTime(); response.PCLoadData2CL.iUserLevel = plr.accountLevel; @@ -345,7 +349,7 @@ static void enterPlayer(CNSocket* sock, CNPacketData* data) { if (pair.second->notify) Chat::sendServerMessage(pair.first, "[ADMIN]" + getPlayerName(&plr) + " has joined."); - // deallocate lm (and therefore the plr object) + // deallocate lm delete lm; } diff --git a/src/core/CNShared.hpp b/src/core/CNShared.hpp index a74298c..98fc495 100644 --- a/src/core/CNShared.hpp +++ b/src/core/CNShared.hpp @@ -18,7 +18,7 @@ struct LoginMetadata { uint64_t FEKey; - Player plr; + int32_t playerId; time_t timestamp; }; diff --git a/src/db/Database.hpp b/src/db/Database.hpp index 347cf27..4d8a25d 100644 --- a/src/db/Database.hpp +++ b/src/db/Database.hpp @@ -52,7 +52,8 @@ namespace Database { bool banPlayer(int playerId, std::string& reason); bool unbanPlayer(int playerId); - void updateSelected(int accountId, int playerId); + void updateSelected(int accountId, int slot); + void updateSelectedByPlayerId(int accountId, int playerId); bool validateCharacter(int characterID, int userID); bool isNameFree(std::string firstName, std::string lastName); diff --git a/src/db/login.cpp b/src/db/login.cpp index db44133..fdb40d2 100644 --- a/src/db/login.cpp +++ b/src/db/login.cpp @@ -79,6 +79,29 @@ void Database::updateSelected(int accountId, int slot) { std::cout << "[WARN] Database fail on updateSelected(): " << sqlite3_errmsg(db) << std::endl; } +void Database::updateSelectedByPlayerId(int accountId, int32_t playerId) { + std::lock_guard lock(dbCrit); + + const char* sql = R"( + UPDATE Accounts SET + Selected = p.Slot, + LastLogin = (strftime('%s', 'now')) + FROM (SELECT Slot From Players WHERE PlayerId = ?) AS p + WHERE AccountID = ?; + )"; + + sqlite3_stmt* stmt; + + sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); + sqlite3_bind_int(stmt, 1, playerId); + sqlite3_bind_int(stmt, 2, accountId); + int rc = sqlite3_step(stmt); + sqlite3_finalize(stmt); + + if (rc != SQLITE_DONE) + std::cout << "[WARN] Database fail on updateSelectedByPlayerId(): " << sqlite3_errmsg(db) << std::endl; +} + bool Database::validateCharacter(int characterID, int userID) { std::lock_guard lock(dbCrit); diff --git a/src/servers/CNLoginServer.cpp b/src/servers/CNLoginServer.cpp index fd152f3..f1ba6b8 100644 --- a/src/servers/CNLoginServer.cpp +++ b/src/servers/CNLoginServer.cpp @@ -471,11 +471,7 @@ void CNLoginServer::characterSelect(CNSocket* sock, CNPacketData* data) { LoginMetadata *lm = new LoginMetadata(); lm->FEKey = sock->getFEKey(); lm->timestamp = getTime(); - - Database::getPlayer(&lm->plr, selection->iPC_UID); - // this should never happen but for extra safety - if (lm->plr.iID == 0) - return invalidCharacter(sock); + lm->playerId = selection->iPC_UID; resp.iEnterSerialKey = Rand::cryptoRand(); @@ -485,7 +481,7 @@ void CNLoginServer::characterSelect(CNSocket* sock, CNPacketData* data) { sock->sendPacket(resp, P_LS2CL_REP_SHARD_SELECT_SUCC); // update current slot in DB - Database::updateSelected(loginSessions[sock].userID, lm->plr.slot); + Database::updateSelectedByPlayerId(loginSessions[sock].userID, selection->iPC_UID); } void CNLoginServer::finishTutorial(CNSocket* sock, CNPacketData* data) {