Merge pull request #3281 from n4ndo/master

Fix Crash in ProcessQueryCallbacks
This commit is contained in:
megamage
2011-10-07 15:19:21 -07:00
7 changed files with 117 additions and 84 deletions
@@ -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*/)
-16
View File
@@ -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())
{
-2
View File
@@ -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);
+73
View File
@@ -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;
}
+15 -1
View File
@@ -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;
};