aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormegamage <none@none>2009-09-01 16:47:49 -0500
committermegamage <none@none>2009-09-01 16:47:49 -0500
commitdc68c2b269fdd401e2f0f6e1e372292b74c66bb8 (patch)
tree385932d0531cec602257aa91492d14dfe7533602 /src
parentf0e6acda3b080f7c686190731a2a8c6f5215336b (diff)
[8433] Implement proper store and use character specific account data.
* Base at TOM_RUS reseach save/load character specific account data in new table `character_account_data` * Move its in sql update from `account_data` to new table. * For client packets that can be send in loggined state or just after logout but assocualted with recently logout character add new login status STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT * Store low guid for loggedin player or recently logout into WorldSession. Author: VladimirMangos, TOM_RUS --HG-- branch : trunk
Diffstat (limited to 'src')
-rw-r--r--src/game/CharacterHandler.cpp10
-rw-r--r--src/game/MiscHandler.cpp6
-rw-r--r--src/game/Opcodes.cpp6
-rw-r--r--src/game/Opcodes.h7
-rw-r--r--src/game/Player.cpp1
-rw-r--r--src/game/Player.h3
-rw-r--r--src/game/TradeHandler.cpp2
-rw-r--r--src/game/World.cpp3
-rw-r--r--src/game/WorldSession.cpp101
-rw-r--r--src/game/WorldSession.h28
-rw-r--r--src/game/WorldSocket.cpp2
11 files changed, 125 insertions, 44 deletions
diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp
index 2b3011a0709..7ce02dc6a77 100644
--- a/src/game/CharacterHandler.cpp
+++ b/src/game/CharacterHandler.cpp
@@ -90,6 +90,7 @@ bool LoginQueryHolder::Initialize()
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBGDATA, "SELECT instance_id, team, join_x, join_y, join_z, join_o, join_map, taxi_start, taxi_end, mount_spell FROM character_battleground_data WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGLYPHS, "SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6 FROM character_glyphs WHERE guid='%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, "SELECT spell, spec FROM character_talent WHERE guid='%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA, "SELECT type, time, data FROM character_account_data WHERE guid='%u'", GUID_LOPART(m_guid));
return res;
}
@@ -602,12 +603,9 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
data << pCurrChar->GetOrientation();
SendPacket(&data);
- data.Initialize( SMSG_ACCOUNT_DATA_TIMES, 4+1+8*4 ); // changed in WotLK
- data << uint32(time(NULL)); // unix time of something
- data << uint8(1);
- for(int i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i)
- data << uint32(GetAccountData(i)->Time); // also unix time
- SendPacket(&data);
+ // load player specific part before send times
+ LoadAccountData(holder->GetResult(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA),PER_CHARACTER_CACHE_MASK);
+ SendAccountDataTimes();
data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0
data << uint8(2); // unknown value
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index 1bffc4a8b3b..0268aa4ddf6 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -919,7 +919,7 @@ void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data)
if(decompressedSize == 0) // erase
{
- SetAccountData(type, 0, "");
+ SetAccountData(AccountDataType(type), 0, "");
WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4);
data << uint32(type);
@@ -952,7 +952,7 @@ void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data)
std::string adata;
dest >> adata;
- SetAccountData(type, timestamp, adata);
+ SetAccountData(AccountDataType(type), timestamp, adata);
WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4);
data << uint32(type);
@@ -972,7 +972,7 @@ void WorldSession::HandleRequestAccountData(WorldPacket& recv_data)
if(type > NUM_ACCOUNT_DATA_TYPES)
return;
- AccountData *adata = GetAccountData(type);
+ AccountData *adata = GetAccountData(AccountDataType(type));
uint32 size = adata->Data.size();
diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp
index 8fd57ad52be..593bf085723 100644
--- a/src/game/Opcodes.cpp
+++ b/src/game/Opcodes.cpp
@@ -312,7 +312,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x119*/ { "CMSG_IGNORE_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleIgnoreTradeOpcode },
/*0x11A*/ { "CMSG_ACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleAcceptTradeOpcode },
/*0x11B*/ { "CMSG_UNACCEPT_TRADE", STATUS_LOGGEDIN, &WorldSession::HandleUnacceptTradeOpcode },
- /*0x11C*/ { "CMSG_CANCEL_TRADE", STATUS_AUTHED, &WorldSession::HandleCancelTradeOpcode },
+ /*0x11C*/ { "CMSG_CANCEL_TRADE", STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, &WorldSession::HandleCancelTradeOpcode},
/*0x11D*/ { "CMSG_SET_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeItemOpcode },
/*0x11E*/ { "CMSG_CLEAR_TRADE_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleClearTradeItemOpcode },
/*0x11F*/ { "CMSG_SET_TRADE_GOLD", STATUS_LOGGEDIN, &WorldSession::HandleSetTradeGoldOpcode },
@@ -551,7 +551,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x208*/ { "SMSG_GMTICKET_UPDATETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x209*/ { "SMSG_ACCOUNT_DATA_TIMES", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x20A*/ { "CMSG_REQUEST_ACCOUNT_DATA", STATUS_LOGGEDIN, &WorldSession::HandleRequestAccountData },
- /*0x20B*/ { "CMSG_UPDATE_ACCOUNT_DATA", STATUS_AUTHED, &WorldSession::HandleUpdateAccountData },
+ /*0x20B*/ { "CMSG_UPDATE_ACCOUNT_DATA", STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, &WorldSession::HandleUpdateAccountData},
/*0x20C*/ { "SMSG_UPDATE_ACCOUNT_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x20D*/ { "SMSG_CLEAR_FAR_SIGHT_IMMEDIATE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x20E*/ { "SMSG_POWERGAINLOG_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide },
@@ -1007,7 +1007,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] =
/*0x3D0*/ { "CMSG_TARGET_CAST", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x3D1*/ { "CMSG_TARGET_SCRIPT_CAST", STATUS_NEVER, &WorldSession::Handle_NULL },
/*0x3D2*/ { "CMSG_CHANNEL_DISPLAY_LIST", STATUS_LOGGEDIN, &WorldSession::HandleChannelDisplayListQuery },
- /*0x3D3*/ { "CMSG_SET_ACTIVE_VOICE_CHANNEL", STATUS_AUTHED, &WorldSession::HandleSetActiveVoiceChannel },
+ /*0x3D3*/ { "CMSG_SET_ACTIVE_VOICE_CHANNEL", STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, &WorldSession::HandleSetActiveVoiceChannel },
/*0x3D4*/ { "CMSG_GET_CHANNEL_MEMBER_COUNT", STATUS_LOGGEDIN, &WorldSession::HandleGetChannelMemberCount },
/*0x3D5*/ { "SMSG_CHANNEL_MEMBER_COUNT", STATUS_NEVER, &WorldSession::Handle_ServerSide },
/*0x3D6*/ { "CMSG_CHANNEL_VOICE_ON", STATUS_LOGGEDIN, &WorldSession::HandleChannelVoiceOnOpcode },
diff --git a/src/game/Opcodes.h b/src/game/Opcodes.h
index b468cc64978..c3371f866b6 100644
--- a/src/game/Opcodes.h
+++ b/src/game/Opcodes.h
@@ -1271,9 +1271,10 @@ enum Opcodes
/// Player state
enum SessionStatus
{
- STATUS_AUTHED = 0, ///< Player authenticated
- STATUS_LOGGEDIN, ///< Player in game
- STATUS_TRANSFER, ///< Player transferring to another map
+ STATUS_AUTHED = 0, ///< Player authenticated (_player==NULL, m_playerRecentlyLogout = false or will be reset before handler call, m_GUID have garbage)
+ STATUS_LOGGEDIN, ///< Player in game (_player!=NULL, m_GUID == _player->GetGUID(), inWorld())
+ STATUS_TRANSFER, ///< Player transferring to another map (_player!=NULL, m_GUID == _player->GetGUID(), !inWorld())
+ STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, ///< _player!= NULL or _player==NULL && m_playerRecentlyLogout, m_GUID store last _player guid)
STATUS_NEVER ///< Opcode not accepted from client (deprecated or server side only)
};
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 23e468cbb3c..1b425890273 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -4231,6 +4231,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
}
CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",guid);
+ CharacterDatabase.PExecute("DELETE FROM character_account_data WHERE guid = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_action WHERE guid = '%u'",guid);
CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u'",guid);
diff --git a/src/game/Player.h b/src/game/Player.h
index 969d2a73960..1ad2d22554d 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -800,7 +800,8 @@ enum PlayerLoginQueryIndex
PLAYER_LOGIN_QUERY_LOADBGDATA = 21,
PLAYER_LOGIN_QUERY_LOADGLYPHS = 22,
PLAYER_LOGIN_QUERY_LOADTALENTS = 23,
- MAX_PLAYER_LOGIN_QUERY = 24
+ PLAYER_LOGIN_QUERY_LOADACCOUNTDATA = 24,
+ MAX_PLAYER_LOGIN_QUERY = 25
};
enum PlayerDelayedOperations
diff --git a/src/game/TradeHandler.cpp b/src/game/TradeHandler.cpp
index 04ec4d8e95f..66781c1b63b 100644
--- a/src/game/TradeHandler.cpp
+++ b/src/game/TradeHandler.cpp
@@ -453,7 +453,7 @@ void WorldSession::SendCancelTrade()
void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/)
{
// sended also after LOGOUT COMPLETE
- if(_player) // needed because STATUS_AUTHED
+ if(_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
_player->TradeCancel(true);
}
diff --git a/src/game/World.cpp b/src/game/World.cpp
index 0923ec3cbbd..6314f4212bc 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -264,7 +264,7 @@ World::AddSession_ (WorldSession* s)
// Updates the population
if (pLimit > 0)
{
- float popu = GetActiveSessionCount (); //updated number of users on the server
+ float popu = GetActiveSessionCount (); // updated number of users on the server
popu /= pLimit;
popu *= 2;
loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);
@@ -2560,4 +2560,3 @@ void World::LoadDBVersion()
if(m_CreatureEventAIVersion.empty())
m_CreatureEventAIVersion = "Unknown creature EventAI.";
}
-
diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp
index 3ec1675ca49..fc3ddb4b486 100644
--- a/src/game/WorldSession.cpp
+++ b/src/game/WorldSession.cpp
@@ -207,6 +207,19 @@ bool WorldSession::Update(uint32 /*diff*/)
}
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
break;
+ case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
+ if(!_player && !m_playerRecentlyLogout)
+ {
+ LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout");
+ }
+ else
+ {
+ // not expected _player or must checked in packet hanlder
+ (this->*opHandle.handler)(*packet);
+ if (sLog.IsOutDebug() && packet->rpos() < packet->wpos())
+ LogUnprocessedTail(packet);
+ }
+ break;
case STATUS_TRANSFER:
if(!_player)
LogUnexpectedOpcode(packet, "the player has not logged in yet");
@@ -423,7 +436,7 @@ void WorldSession::LogoutPlayer(bool Save)
_player->CleanupsBeforeDelete();
Map* _map = _player->GetMap();
_map->Remove(_player, true);
- _player = NULL; // deleted in Remove call
+ SetPlayer(NULL); // deleted in Remove call
///- Send the 'logout complete' packet to the client
WorldPacket data( SMSG_LOGOUT_COMPLETE, 0 );
@@ -559,15 +572,19 @@ void WorldSession::SendAuthWaitQue(uint32 position)
}
}
-void WorldSession::LoadAccountData()
+void WorldSession::LoadGlobalAccountData()
{
- for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i)
- {
- AccountData data;
- m_accountData[i] = data;
- }
+ LoadAccountData(
+ CharacterDatabase.PQuery("SELECT type, time, data FROM account_data WHERE account='%u'", GetAccountId()),
+ GLOBAL_CACHE_MASK
+ );
+}
- QueryResult *result = CharacterDatabase.PQuery("SELECT type, time, data FROM account_data WHERE account='%u'", GetAccountId());
+void WorldSession::LoadAccountData(QueryResult* result, uint32 mask)
+{
+ for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i)
+ if (mask & (1 << i))
+ m_accountData[i] = AccountData();
if(!result)
return;
@@ -577,28 +594,65 @@ void WorldSession::LoadAccountData()
Field *fields = result->Fetch();
uint32 type = fields[0].GetUInt32();
- if(type < NUM_ACCOUNT_DATA_TYPES)
+ if (type >= NUM_ACCOUNT_DATA_TYPES)
+ {
+ sLog.outError("Table `%s` have invalid account data type (%u), ignore.",
+ mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data");
+ continue;
+ }
+
+ if ((mask & (1 << type))==0)
{
- m_accountData[type].Time = fields[1].GetUInt32();
- m_accountData[type].Data = fields[2].GetCppString();
+ sLog.outError("Table `%s` have non appropriate for table account data type (%u), ignore.",
+ mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data");
+ continue;
}
+
+ m_accountData[type].Time = fields[1].GetUInt32();
+ m_accountData[type].Data = fields[2].GetCppString();
+
} while (result->NextRow());
delete result;
}
-void WorldSession::SetAccountData(uint32 type, time_t time_, std::string data)
+void WorldSession::SetAccountData(AccountDataType type, time_t time_, std::string data)
{
+ if ((1 << type) & GLOBAL_CACHE_MASK)
+ {
+ uint32 acc = GetAccountId();
+
+ CharacterDatabase.BeginTransaction ();
+ CharacterDatabase.PExecute("DELETE FROM account_data WHERE account='%u' AND type='%u'", acc, type);
+ CharacterDatabase.escape_string(data);
+ CharacterDatabase.PExecute("INSERT INTO account_data VALUES ('%u','%u','%u','%s')", acc, type, (uint32)time_, data.c_str());
+ CharacterDatabase.CommitTransaction ();
+ }
+ else
+ {
+ // _player can be NULL and packet received after logout but m_GUID still store correct guid
+ if(!m_GUIDLow)
+ return;
+
+ CharacterDatabase.BeginTransaction ();
+ CharacterDatabase.PExecute("DELETE FROM character_account_data WHERE guid='%u' AND type='%u'", m_GUIDLow, type);
+ CharacterDatabase.escape_string(data);
+ CharacterDatabase.PExecute("INSERT INTO character_account_data VALUES ('%u','%u','%u','%s')", m_GUIDLow, type, (uint32)time_, data.c_str());
+ CharacterDatabase.CommitTransaction ();
+ }
+
m_accountData[type].Time = time_;
m_accountData[type].Data = data;
+}
- uint32 acc = GetAccountId();
-
- CharacterDatabase.BeginTransaction ();
- CharacterDatabase.PExecute("DELETE FROM account_data WHERE account='%u' AND type='%u'", acc, type);
- CharacterDatabase.escape_string(data);
- CharacterDatabase.PExecute("INSERT INTO account_data VALUES ('%u','%u','%u','%s')", acc, type, (uint32)time_, data.c_str());
- CharacterDatabase.CommitTransaction ();
+void WorldSession::SendAccountDataTimes()
+{
+ WorldPacket data( SMSG_ACCOUNT_DATA_TIMES, 4+1+8*4 ); // changed in WotLK
+ data << uint32(time(NULL)); // unix time of something
+ data << uint8(1);
+ for(int i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i)
+ data << uint32(m_accountData[i].Time); // also unix time
+ SendPacket(&data);
}
void WorldSession::LoadTutorialsData()
@@ -825,3 +879,12 @@ void WorldSession::SendAddonsInfo()
SendPacket(&data);
}
+
+void WorldSession::SetPlayer( Player *plr )
+{
+ _player = plr;
+
+ // set m_GUID that can be used while player loggined and later until m_playerRecentlyLogout not reset
+ if(_player)
+ m_GUIDLow = _player->GetGUIDLow();
+} \ No newline at end of file
diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h
index c549a2c87ad..0da58f55445 100644
--- a/src/game/WorldSession.h
+++ b/src/game/WorldSession.h
@@ -46,7 +46,22 @@ class QueryResult;
class LoginQueryHolder;
class CharacterHandler;
-#define NUM_ACCOUNT_DATA_TYPES 8
+enum AccountDataType
+{
+ GLOBAL_CONFIG_CACHE = 0, // 0x01 g
+ PER_CHARACTER_CONFIG_CACHE = 1, // 0x02 p
+ GLOBAL_BINDINGS_CACHE = 2, // 0x04 g
+ PER_CHARACTER_BINDINGS_CACHE = 3, // 0x08 p
+ GLOBAL_MACROS_CACHE = 4, // 0x10 g
+ PER_CHARACTER_MACROS_CACHE = 5, // 0x20 p
+ PER_CHARACTER_LAYOUT_CACHE = 6, // 0x40 p
+ PER_CHARACTER_CHAT_CACHE = 7, // 0x80 p
+};
+
+#define NUM_ACCOUNT_DATA_TYPES 8
+
+#define GLOBAL_CACHE_MASK 0x15
+#define PER_CHARACTER_CACHE_MASK 0xEA
struct AccountData
{
@@ -127,7 +142,7 @@ class TRINITY_DLL_SPEC WorldSession
char const* GetPlayerName() const;
void SetSecurity(AccountTypes security) { _security = security; }
std::string const& GetRemoteAddress() { return m_Address; }
- void SetPlayer(Player *plr) { _player = plr; }
+ void SetPlayer(Player *plr);
uint8 Expansion() const { return m_expansion; }
/// Session in auth.queue currently
@@ -185,9 +200,11 @@ class TRINITY_DLL_SPEC WorldSession
void SendPetNameQuery(uint64 guid, uint32 petnumber);
// Account Data
- AccountData *GetAccountData(uint32 type) { return &m_accountData[type]; }
- void SetAccountData(uint32 type, time_t time_, std::string data);
- void LoadAccountData();
+ AccountData *GetAccountData(AccountDataType type) { return &m_accountData[type]; }
+ void SetAccountData(AccountDataType type, time_t time_, std::string data);
+ void SendAccountDataTimes();
+ void LoadGlobalAccountData();
+ void LoadAccountData(QueryResult* result, uint32 mask);
void LoadTutorialsData();
void SendTutorialsData();
void SaveTutorialsData();
@@ -727,6 +744,7 @@ class TRINITY_DLL_SPEC WorldSession
void LogUnexpectedOpcode(WorldPacket *packet, const char * reason);
void LogUnprocessedTail(WorldPacket *packet);
+ uint32 m_GUIDLow; // set loggined or recently logout player (while m_playerRecentlyLogout set)
Player *_player;
WorldSocket *m_Socket;
std::string m_Address;
diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp
index 0da9c875ba2..ba119637cf9 100644
--- a/src/game/WorldSocket.cpp
+++ b/src/game/WorldSocket.cpp
@@ -921,7 +921,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
m_Crypt.Init(&K);
- m_Session->LoadAccountData();
+ m_Session->LoadGlobalAccountData();
m_Session->LoadTutorialsData();
m_Session->ReadAddonsInfo(recvPacket);