Merge pull request #3281 from n4ndo/master
Fix Crash in ProcessQueryCallbacks
This commit is contained in:
@@ -19035,6 +19035,7 @@ void Player::Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8
|
||||
player_bytes2 |= facialHair;
|
||||
|
||||
CharacterDatabase.PExecute("UPDATE characters SET gender = '%u', playerBytes = '%u', playerBytes2 = '%u' WHERE guid = '%u'", gender, skin | (face << 8) | (hairStyle << 16) | (hairColor << 24), player_bytes2, GUID_LOPART(guid));
|
||||
sWorld->ReloadSingleCharacterNameData(GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
void Player::SendAttackSwingDeadTarget()
|
||||
|
||||
@@ -1426,6 +1426,8 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
|
||||
data << uint8(hairColor);
|
||||
data << uint8(facialHair);
|
||||
SendPacket(&data);
|
||||
|
||||
sWorld->ReloadSingleCharacterNameData(GUID_LOPART(guid));
|
||||
}
|
||||
|
||||
void WorldSession::HandleEquipmentSetSave(WorldPacket &recv_data)
|
||||
|
||||
@@ -56,80 +56,41 @@ void WorldSession::SendNameQueryOpcode(Player* p)
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::SendNameQueryOpcodeFromDB(uint64 guid)
|
||||
{
|
||||
QueryResultFuture lFutureResult =
|
||||
CharacterDatabase.AsyncPQuery(
|
||||
!sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED) ?
|
||||
// ------- Query Without Declined Names --------
|
||||
// 0 1 2 3 4
|
||||
"SELECT guid, name, race, gender, class "
|
||||
"FROM characters WHERE guid = '%u'"
|
||||
:
|
||||
// --------- Query With Declined Names ---------
|
||||
// 0 1 2 3 4
|
||||
"SELECT characters.guid, name, race, gender, class, "
|
||||
// 5 6 7 8 9
|
||||
"genitive, dative, accusative, instrumental, prepositional "
|
||||
"FROM characters LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid WHERE characters.guid = '%u'",
|
||||
GUID_LOPART(guid)
|
||||
);
|
||||
|
||||
_nameQueryCallbacks.insert(lFutureResult);
|
||||
|
||||
// CharacterDatabase.AsyncPQuery(&WorldSession::SendNameQueryOpcodeFromDBCallBack, GetAccountId(),
|
||||
}
|
||||
|
||||
void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult result)
|
||||
{
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
uint32 guid = fields[0].GetUInt32();
|
||||
std::string name = fields[1].GetString();
|
||||
uint8 pRace = 0, pGender = 0, pClass = 0;
|
||||
if (name == "")
|
||||
name = GetTrinityString(LANG_NON_EXIST_CHARACTER);
|
||||
else
|
||||
{
|
||||
pRace = fields[2].GetUInt8();
|
||||
pGender = fields[3].GetUInt8();
|
||||
pClass = fields[4].GetUInt8();
|
||||
}
|
||||
// guess size
|
||||
WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+1+10));
|
||||
data.appendPackGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
|
||||
data << uint8(0); // added in 3.1
|
||||
data << name;
|
||||
data << uint8(0); // realm name for cross realm BG usage
|
||||
data << uint8(pRace); // race
|
||||
data << uint8(pGender); // gender
|
||||
data << uint8(pClass); // class
|
||||
|
||||
// if the first declined name field (5) is empty, the rest must be too
|
||||
if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED) && fields[5].GetString() != "")
|
||||
{
|
||||
data << uint8(1); // is declined
|
||||
for (int i = 5; i < MAX_DECLINED_NAME_CASES+5; ++i)
|
||||
data << fields[i].GetString();
|
||||
}
|
||||
else
|
||||
data << uint8(0); // is not declined
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleNameQueryOpcode(WorldPacket& recv_data)
|
||||
{
|
||||
uint64 guid;
|
||||
|
||||
recv_data >> guid;
|
||||
|
||||
// This is disable by default to prevent lots of console spam
|
||||
// sLog->outString("HandleNameQueryOpcode %u", guid);
|
||||
|
||||
if (Player* pChar = ObjectAccessor::FindPlayer(guid))
|
||||
SendNameQueryOpcode(pChar);
|
||||
else
|
||||
SendNameQueryOpcodeFromDB(guid);
|
||||
{
|
||||
if (CharacterNameData* cname = sWorld->GetCharacterNameData(guid))
|
||||
{
|
||||
WorldPacket data(SMSG_NAME_QUERY_RESPONSE, 8+1+1+1+1+1+1+10);
|
||||
data.appendPackGUID(guid);
|
||||
data << uint8(0);
|
||||
if (cname->m_name == "")
|
||||
{
|
||||
data << std::string(GetTrinityString(LANG_NON_EXIST_CHARACTER));
|
||||
data << uint32(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
data << cname->m_name;
|
||||
data << uint8(0);
|
||||
data << uint8(cname->m_race);
|
||||
data << uint8(cname->m_gender);
|
||||
data << uint8(cname->m_class);
|
||||
}
|
||||
data << uint8(0);
|
||||
SendPacket(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleQueryTimeOpcode(WorldPacket & /*recv_data*/)
|
||||
|
||||
@@ -984,22 +984,6 @@ void WorldSession::ProcessQueryCallbacks()
|
||||
{
|
||||
QueryResult result;
|
||||
|
||||
//! HandleNameQueryOpcode
|
||||
while (!_nameQueryCallbacks.is_empty())
|
||||
{
|
||||
QueryResultFuture lResult;
|
||||
ACE_Time_Value timeout = ACE_Time_Value::zero;
|
||||
if (_nameQueryCallbacks.next_readable(lResult, &timeout) != 1)
|
||||
break;
|
||||
|
||||
if (lResult.ready())
|
||||
{
|
||||
lResult.get(result);
|
||||
SendNameQueryOpcodeFromDBCallBack(result);
|
||||
lResult.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
//! HandleCharEnumOpcode
|
||||
if (_charEnumCallback.ready())
|
||||
{
|
||||
|
||||
@@ -279,8 +279,6 @@ class WorldSession
|
||||
|
||||
//void SendTestCreatureQueryOpcode(uint32 entry, uint64 guid, uint32 testvalue);
|
||||
void SendNameQueryOpcode(Player* p);
|
||||
void SendNameQueryOpcodeFromDB(uint64 guid);
|
||||
void SendNameQueryOpcodeFromDBCallBack(QueryResult result);
|
||||
|
||||
void SendTrainerList(uint64 guid);
|
||||
void SendTrainerList(uint64 guid, const std::string& strTitle);
|
||||
|
||||
@@ -132,6 +132,10 @@ World::~World()
|
||||
|
||||
VMAP::VMapFactory::clear();
|
||||
|
||||
// Clean up character name data
|
||||
for (std::map<uint32, CharacterNameData*>::iterator itr = m_CharacterNameDataMap.begin(); itr != m_CharacterNameDataMap.end(); ++itr)
|
||||
delete itr->second;
|
||||
|
||||
//TODO free addSessQueue
|
||||
}
|
||||
|
||||
@@ -1723,6 +1727,8 @@ void World::SetInitialWorldSettings()
|
||||
sLog->outString("Calculate random battleground reset time..." );
|
||||
InitRandomBGResetTime();
|
||||
|
||||
LoadCharacterNameData();
|
||||
|
||||
// possibly enable db logging; avoid massive startup spam by doing it here.
|
||||
if (sLog->GetLogDBLater())
|
||||
{
|
||||
@@ -2842,3 +2848,70 @@ void World::ProcessQueryCallbacks()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void World::LoadCharacterNameData()
|
||||
{
|
||||
sLog->outString("Loading character name data");
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT guid, name, race, gender, class FROM characters");
|
||||
if (!result)
|
||||
{
|
||||
sLog->outError("No character name data loaded, empty query");
|
||||
return;
|
||||
}
|
||||
|
||||
ACE_Guard<ACE_Thread_Mutex> guard(m_CharacterNameDataMapMutex);
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
CharacterNameData* data = new CharacterNameData;
|
||||
data->m_name = fields[1].GetString();
|
||||
data->m_race = fields[2].GetUInt8();
|
||||
data->m_gender = fields[3].GetUInt8();
|
||||
data->m_class = fields[4].GetUInt8();
|
||||
|
||||
m_CharacterNameDataMap[fields[0].GetUInt32()] = data;
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog->outString("Loaded name data for %u characters", count);
|
||||
}
|
||||
|
||||
void World::ReloadSingleCharacterNameData(uint32 guid)
|
||||
{
|
||||
ACE_Guard<ACE_Thread_Mutex> guard(m_CharacterNameDataMapMutex);
|
||||
|
||||
std::map<uint32, CharacterNameData*>::iterator itr = m_CharacterNameDataMap.find(guid);
|
||||
|
||||
if (itr != m_CharacterNameDataMap.end())
|
||||
{
|
||||
delete itr->second;
|
||||
m_CharacterNameDataMap.erase(itr);
|
||||
}
|
||||
|
||||
QueryResult result = CharacterDatabase.PQuery("SELECT name, race, gender, class FROM characters WHERE guid = '%u'", guid);
|
||||
if (result)
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
CharacterNameData* newdata = new CharacterNameData;
|
||||
newdata->m_name = fields[0].GetString();
|
||||
newdata->m_race = fields[1].GetUInt8();
|
||||
newdata->m_gender = fields[2].GetUInt8();
|
||||
newdata->m_class = fields[3].GetUInt8();
|
||||
m_CharacterNameDataMap[guid] = newdata;
|
||||
}
|
||||
}
|
||||
|
||||
CharacterNameData* World::GetCharacterNameData(uint32 guid)
|
||||
{
|
||||
ACE_Guard<ACE_Thread_Mutex> guard(m_CharacterNameDataMapMutex);
|
||||
|
||||
std::map<uint32, CharacterNameData*>::iterator itr = m_CharacterNameDataMap.find(guid);
|
||||
if (itr != m_CharacterNameDataMap.end())
|
||||
return itr->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -511,6 +511,14 @@ struct CliCommandHolder
|
||||
|
||||
typedef UNORDERED_MAP<uint32, WorldSession*> SessionMap;
|
||||
|
||||
struct CharacterNameData
|
||||
{
|
||||
std::string m_name;
|
||||
uint8 m_class;
|
||||
uint8 m_race;
|
||||
uint8 m_gender;
|
||||
};
|
||||
|
||||
/// The World
|
||||
class World
|
||||
{
|
||||
@@ -729,6 +737,9 @@ class World
|
||||
|
||||
bool isEventKillStart;
|
||||
|
||||
CharacterNameData *GetCharacterNameData(uint32 guid);
|
||||
void ReloadSingleCharacterNameData(uint32 guid);
|
||||
|
||||
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
|
||||
void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; }
|
||||
protected:
|
||||
@@ -816,7 +827,10 @@ class World
|
||||
|
||||
std::list<std::string> m_Autobroadcasts;
|
||||
|
||||
private:
|
||||
std::map<uint32, CharacterNameData*> m_CharacterNameDataMap;
|
||||
ACE_Thread_Mutex m_CharacterNameDataMapMutex;
|
||||
void LoadCharacterNameData();
|
||||
|
||||
void ProcessQueryCallbacks();
|
||||
ACE_Future_Set<PreparedQueryResult> m_realmCharCallbacks;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user