Fix Crash in ProcessQueryCallbacks
This commit is contained in:
@@ -19041,6 +19041,7 @@ void Player::Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8
|
|||||||
player_bytes2 |= facialHair;
|
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));
|
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()
|
void Player::SendAttackSwingDeadTarget()
|
||||||
|
|||||||
@@ -1426,6 +1426,8 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
|
|||||||
data << uint8(hairColor);
|
data << uint8(hairColor);
|
||||||
data << uint8(facialHair);
|
data << uint8(facialHair);
|
||||||
SendPacket(&data);
|
SendPacket(&data);
|
||||||
|
|
||||||
|
sWorld->ReloadSingleCharacterNameData(GUID_LOPART(guid));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::HandleEquipmentSetSave(WorldPacket &recv_data)
|
void WorldSession::HandleEquipmentSetSave(WorldPacket &recv_data)
|
||||||
|
|||||||
@@ -56,80 +56,41 @@ void WorldSession::SendNameQueryOpcode(Player* p)
|
|||||||
SendPacket(&data);
|
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)
|
void WorldSession::HandleNameQueryOpcode(WorldPacket& recv_data)
|
||||||
{
|
{
|
||||||
uint64 guid;
|
uint64 guid;
|
||||||
|
|
||||||
recv_data >> 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))
|
if (Player* pChar = ObjectAccessor::FindPlayer(guid))
|
||||||
SendNameQueryOpcode(pChar);
|
SendNameQueryOpcode(pChar);
|
||||||
else
|
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*/)
|
void WorldSession::HandleQueryTimeOpcode(WorldPacket & /*recv_data*/)
|
||||||
|
|||||||
@@ -984,22 +984,6 @@ void WorldSession::ProcessQueryCallbacks()
|
|||||||
{
|
{
|
||||||
QueryResult result;
|
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
|
//! HandleCharEnumOpcode
|
||||||
if (_charEnumCallback.ready())
|
if (_charEnumCallback.ready())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -279,8 +279,6 @@ class WorldSession
|
|||||||
|
|
||||||
//void SendTestCreatureQueryOpcode(uint32 entry, uint64 guid, uint32 testvalue);
|
//void SendTestCreatureQueryOpcode(uint32 entry, uint64 guid, uint32 testvalue);
|
||||||
void SendNameQueryOpcode(Player* p);
|
void SendNameQueryOpcode(Player* p);
|
||||||
void SendNameQueryOpcodeFromDB(uint64 guid);
|
|
||||||
void SendNameQueryOpcodeFromDBCallBack(QueryResult result);
|
|
||||||
|
|
||||||
void SendTrainerList(uint64 guid);
|
void SendTrainerList(uint64 guid);
|
||||||
void SendTrainerList(uint64 guid, const std::string& strTitle);
|
void SendTrainerList(uint64 guid, const std::string& strTitle);
|
||||||
|
|||||||
@@ -132,6 +132,10 @@ World::~World()
|
|||||||
|
|
||||||
VMAP::VMapFactory::clear();
|
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
|
//TODO free addSessQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1723,6 +1727,8 @@ void World::SetInitialWorldSettings()
|
|||||||
sLog->outString("Calculate random battleground reset time..." );
|
sLog->outString("Calculate random battleground reset time..." );
|
||||||
InitRandomBGResetTime();
|
InitRandomBGResetTime();
|
||||||
|
|
||||||
|
LoadCharacterNameData();
|
||||||
|
|
||||||
// possibly enable db logging; avoid massive startup spam by doing it here.
|
// possibly enable db logging; avoid massive startup spam by doing it here.
|
||||||
if (sLog->GetLogDBLater())
|
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;
|
typedef UNORDERED_MAP<uint32, WorldSession*> SessionMap;
|
||||||
|
|
||||||
|
struct CharacterNameData
|
||||||
|
{
|
||||||
|
std::string m_name;
|
||||||
|
uint8 m_class;
|
||||||
|
uint8 m_race;
|
||||||
|
uint8 m_gender;
|
||||||
|
};
|
||||||
|
|
||||||
/// The World
|
/// The World
|
||||||
class World
|
class World
|
||||||
{
|
{
|
||||||
@@ -729,6 +737,9 @@ class World
|
|||||||
|
|
||||||
bool isEventKillStart;
|
bool isEventKillStart;
|
||||||
|
|
||||||
|
CharacterNameData *GetCharacterNameData(uint32 guid);
|
||||||
|
void ReloadSingleCharacterNameData(uint32 guid);
|
||||||
|
|
||||||
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
|
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
|
||||||
void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; }
|
void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; }
|
||||||
protected:
|
protected:
|
||||||
@@ -816,7 +827,10 @@ class World
|
|||||||
|
|
||||||
std::list<std::string> m_Autobroadcasts;
|
std::list<std::string> m_Autobroadcasts;
|
||||||
|
|
||||||
private:
|
std::map<uint32, CharacterNameData*> m_CharacterNameDataMap;
|
||||||
|
ACE_Thread_Mutex m_CharacterNameDataMapMutex;
|
||||||
|
void LoadCharacterNameData();
|
||||||
|
|
||||||
void ProcessQueryCallbacks();
|
void ProcessQueryCallbacks();
|
||||||
ACE_Future_Set<PreparedQueryResult> m_realmCharCallbacks;
|
ACE_Future_Set<PreparedQueryResult> m_realmCharCallbacks;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user