Files
DarkflameServer/dGame/User.cpp
David Markowitz 6389876c6e feat: convert character ids to 64 bits (#1878)
* feat: convert character ids to 64 bits

remove all usages of the PERSISTENT bit with regards to storing of playerIDs on the server.  the bit does not exist and was a phantom in the first place.
Tested that a full playthrough of ag, ns and gf was still doable.  slash commands work, ugc works, friends works, ignore list works, properties work and have names, teaming works.
migrating an old mysql database works . need to test an old sqlite database

* fix sqlite migration

* remove nd specific column migration
2025-09-19 01:12:23 -05:00

142 lines
4.2 KiB
C++

#include "User.h"
#include "Database.h"
#include "Character.h"
#include "dServer.h"
#include "Logger.h"
#include "Game.h"
#include "dZoneManager.h"
#include "eServerDisconnectIdentifiers.h"
#include "eGameMasterLevel.h"
#include "BitStreamUtils.h"
#include "MessageType/Chat.h"
#include <chrono>
#include <ctime>
User::User(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey) {
m_AccountID = 0;
m_Username = "";
m_SessionKey = "";
m_MuteExpire = 0;
m_MaxGMLevel = eGameMasterLevel::CIVILIAN; //The max GM level this account can assign to it's characters
m_LastCharID = 0;
m_SessionKey = sessionKey;
m_SystemAddress = sysAddr;
m_Username = username;
m_LoggedInCharID = 0;
m_IsBestFriendMap = std::unordered_map<std::string, bool>();
auto userInfo = Database::Get()->GetAccountInfo(username);
if (userInfo) {
m_AccountID = userInfo->id;
m_MaxGMLevel = userInfo->maxGmLevel;
m_MuteExpire = userInfo->muteExpire;
}
//If we're loading a zone, we'll load the last used (aka current) character:
if (Game::server->GetZoneID() != 0) {
auto characterList = Database::Get()->GetAccountCharacterIds(m_AccountID);
if (!characterList.empty()) {
const auto lastUsedCharacterId = characterList.front();
Character* character = new Character(lastUsedCharacterId, this);
character->UpdateFromDatabase();
m_Characters.push_back(character);
LOG("Loaded %llu as it is the last used char", lastUsedCharacterId);
}
}
}
User::User(const User& other) {
this->m_AccountID = other.m_AccountID;
this->m_LastCharID = other.m_LastCharID;
this->m_MaxGMLevel = other.m_MaxGMLevel;
this->m_SessionKey = other.m_SessionKey;
this->m_SystemAddress = other.m_SystemAddress;
this->m_Username = other.m_Username;
this->m_LoggedInCharID = other.m_LoggedInCharID;
}
User::~User() {
for (Character* c : m_Characters) {
if (c) {
delete c;
c = nullptr;
}
}
}
User& User::operator= (const User& other) {
this->m_AccountID = other.m_AccountID;
this->m_LastCharID = other.m_LastCharID;
this->m_MaxGMLevel = other.m_MaxGMLevel;
this->m_SessionKey = other.m_SessionKey;
this->m_SystemAddress = other.m_SystemAddress;
this->m_Username = other.m_Username;
this->m_LoggedInCharID = other.m_LoggedInCharID;
return *this;
}
bool User::operator== (const User& other) const {
return m_Username == other.m_Username || m_SessionKey == other.m_SessionKey || m_SystemAddress == other.m_SystemAddress;
}
Character* User::GetLastUsedChar() {
if (m_Characters.size() == 0) return nullptr;
else if (m_Characters.size() == 1) return m_Characters[0];
else {
Character* toReturn = m_Characters[0];
for (size_t i = 0; i < m_Characters.size(); ++i) {
if (m_Characters[i]->GetLastLogin() > toReturn->GetLastLogin()) toReturn = m_Characters[i];
}
return toReturn;
}
}
bool User::GetIsMuted() {
using namespace std::chrono;
constexpr auto refreshInterval = seconds{ 60 };
const auto now = steady_clock::now();
if (now - m_LastMuteCheck >= refreshInterval) {
m_LastMuteCheck = now;
if (const auto info = Database::Get()->GetAccountInfo(m_Username)) {
const auto expire = static_cast<time_t>(info->muteExpire);
if (expire != m_MuteExpire) {
m_MuteExpire = expire;
if (Game::chatServer && m_LoggedInCharID != 0) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::GM_MUTE);
bitStream.Write(m_LoggedInCharID);
bitStream.Write(m_MuteExpire);
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
}
}
}
}
return m_MuteExpire == 1 || m_MuteExpire > std::time(nullptr);
}
time_t User::GetMuteExpire() const {
return m_MuteExpire;
}
void User::SetMuteExpire(time_t value) {
m_MuteExpire = value;
}
void User::UserOutOfSync() {
m_AmountOfTimesOutOfSync++;
if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) {
//YEET
LOG("User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed);
Game::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE);
}
}
void User::UpdateBestFriendValue(const std::string_view playerName, const bool newValue) {
m_IsBestFriendMap[playerName.data()] = newValue;
}