diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 0a89ad16f..8c312e7f8 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -926,7 +926,6 @@ void WorldSession::HandleTutorialFlag( WorldPacket & recv_data ) uint32 tutflag = GetTutorialInt( wInt ); tutflag |= (1 << rInt); SetTutorialInt( wInt, tutflag ); - SaveTutorialsData(); //sLog.outDebug("Received Tutorial Flag Set {%u}.", iFlag); } @@ -935,14 +934,12 @@ void WorldSession::HandleTutorialClear( WorldPacket & /*recv_data*/ ) { for ( uint32 iI = 0; iI < 8; iI++) SetTutorialInt( iI, 0xFFFFFFFF ); - SaveTutorialsData(); } void WorldSession::HandleTutorialReset( WorldPacket & /*recv_data*/ ) { for ( uint32 iI = 0; iI < 8; iI++) SetTutorialInt( iI, 0x00000000 ); - SaveTutorialsData(); } void WorldSession::HandleSetWatchedFactionIndexOpcode(WorldPacket & recv_data) @@ -1335,30 +1332,36 @@ void WorldSession::HandleEquipmentSetSave(WorldPacket &recv_data) CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4); - uint32 Index; - recv_data >> Index; + uint32 index; + recv_data >> index; + if(index >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount + return; - std::string name, iconName; - recv_data >> name >> iconName; + CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+1); + std::string name; + recv_data >> name; + + CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+1); + std::string iconName; + recv_data >> iconName; EquipmentSet eqSet; eqSet.Guid = setGuid; - eqSet.Index = Index; eqSet.Name = name; eqSet.IconName = iconName; - - uint64 itemGuid; + eqSet.state = EQUIPMENT_SET_NEW; for(uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) { + uint64 itemGuid; if(!recv_data.readPackGUID(itemGuid)) return; eqSet.Items[i] = GUID_LOPART(itemGuid); } - _player->SaveEquipmentSet(eqSet); + _player->SetEquipmentSet(index,eqSet); } void WorldSession::HandleEquipmentSetDelete(WorldPacket &recv_data) diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 36c209a00..8837b5c50 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -121,6 +121,7 @@ ObjectMgr::ObjectMgr() m_hiPetNumber = 1; m_ItemTextId = 1; m_mailid = 1; + m_equipmentSetGuid = 1; m_guildId = 1; m_arenaTeamId = 1; m_auctionid = 1; @@ -5124,6 +5125,13 @@ void ObjectMgr::SetHighestGuids() delete result; } + result = CharacterDatabase.Query("SELECT MAX(setguid) FROM character_equipmentsets"); + if (result) + { + m_equipmentSetGuid = (*result)[0].GetUInt64()+1; + delete result; + } + result = CharacterDatabase.Query( "SELECT MAX(guildid) FROM guild" ); if (result) { @@ -5152,6 +5160,16 @@ uint32 ObjectMgr::GenerateAuctionID() return m_auctionid++; } +uint64 ObjectMgr::GenerateEquipmentSetGuid() +{ + if(m_equipmentSetGuid>=0xFFFFFFFFFFFFFFFE) + { + sLog.outError("EquipmentSet guid overflow!! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + return m_equipmentSetGuid++; +} + uint32 ObjectMgr::GenerateGuildId() { if(m_guildId>=0xFFFFFFFE) diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index 011edb85d..8fda417b6 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -564,6 +564,7 @@ class ObjectMgr uint32 GenerateLowGuid(HighGuid guidhigh); uint32 GenerateArenaTeamId(); uint32 GenerateAuctionID(); + uint64 GenerateEquipmentSetGuid(); uint32 GenerateGuildId(); uint32 GenerateItemTextID(); uint32 GenerateMailID(); @@ -767,6 +768,7 @@ class ObjectMgr // first free id for selected id type uint32 m_arenaTeamId; uint32 m_auctionid; + uint64 m_equipmentSetGuid; uint32 m_guildId; uint32 m_ItemTextId; uint32 m_mailid; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 5e8674ea5..cdda08259 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -14010,6 +14010,7 @@ void Player::_LoadArenaTeamInfo(QueryResult *result) void Player::_LoadEquipmentSets(QueryResult *result) { + // SetPQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '%u' ORDER BY setindex", GUID_LOPART(m_guid)); if (!result) return; @@ -14021,18 +14022,19 @@ void Player::_LoadEquipmentSets(QueryResult *result) EquipmentSet eqSet; eqSet.Guid = fields[0].GetUInt64(); - eqSet.Index = fields[1].GetUInt32(); + uint32 index = fields[1].GetUInt32(); eqSet.Name = fields[2].GetCppString(); eqSet.IconName = fields[3].GetCppString(); + eqSet.state = EQUIPMENT_SET_UNCHANGED; for(uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) eqSet.Items[i] = fields[4+i].GetUInt32(); - m_EquipmentSets[eqSet.Index] = eqSet; + m_EquipmentSets[index] = eqSet; ++count; - if(count >= 10) + if(count >= MAX_EQUIPMENT_SET_INDEX) // client limit break; } while (result->NextRow()); delete result; @@ -15742,6 +15744,8 @@ void Player::SaveToDB() _SaveActions(); _SaveAuras(); _SaveReputation(); + _SaveEquipmentSets(); + GetSession()->SaveTutorialsData(); // changed only while character in game CharacterDatabase.CommitTransaction(); @@ -18076,17 +18080,24 @@ void Player::SendInitialPacketsBeforeAddToMap() m_achievementMgr.SendAllAchievementData(); UpdateZone(GetZoneId()); + uint32 count = 0; data.Initialize(SMSG_EQUIPMENT_SET_LIST, 4); - data << uint32(m_EquipmentSets.size()); // count + size_t count_pos = data.wpos(); + data << uint32(count); // count placeholder for(EquipmentSets::iterator itr = m_EquipmentSets.begin(); itr != m_EquipmentSets.end(); ++itr) { + if(itr->second.state==EQUIPMENT_SET_DELETED) + continue; data.appendPackGUID(itr->second.Guid); - data << uint32(itr->second.Index); + data << uint32(itr->first); data << itr->second.Name; data << itr->second.IconName; for(uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) data.appendPackGUID(MAKE_NEW_GUID(itr->second.Items[i], 0, HIGHGUID_ITEM)); + + ++count; // client have limit but it checked at loading and set } + data.put(count_pos,count); GetSession()->SendPacket(&data); data.Initialize(SMSG_LOGIN_SETTIMESPEED, 8); @@ -19926,51 +19937,62 @@ void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank) sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid); } -void Player::SaveEquipmentSet(EquipmentSet eqset) +void Player::SetEquipmentSet(uint32 index, EquipmentSet eqset) { - if(m_EquipmentSets.size() >= 10) // client limit - return; + EquipmentSet& eqslot = m_EquipmentSets[index]; - EquipmentSets::iterator itr = m_EquipmentSets.find(eqset.Index); - if(itr != m_EquipmentSets.end()) + EquipmentSetUpdateState old_state = eqslot.state; + + eqslot = eqset; + eqslot.Guid = objmgr.GenerateEquipmentSetGuid(); + eqslot.state = old_state == EQUIPMENT_SET_NEW ? EQUIPMENT_SET_NEW : EQUIPMENT_SET_CHANGED; + + WorldPacket data(SMSG_EQUIPMENT_SET_SAVED, 4+1); + data << uint32(index); + data.appendPackGUID(eqset.Guid); + GetSession()->SendPacket(&data); +} + +void Player::_SaveEquipmentSets() +{ + for(EquipmentSets::iterator itr = m_EquipmentSets.begin(); itr != m_EquipmentSets.end();) { - CharacterDatabase.PExecute("UPDATE character_equipmentsets SET name='%s', iconname='%s', item0='%u', item1='%u', item2='%u', item3='%u', item4='%u', item5='%u', item6='%u', item7='%u', item8='%u', item9='%u', item10='%u', item11='%u', item12='%u', item13='%u', item14='%u', item15='%u', item16='%u', item17='%u', item18='%u' WHERE guid='%u' AND setguid='"I64FMTD"' AND setindex='%u'", - eqset.Name.c_str(), eqset.IconName.c_str(), eqset.Items[0], eqset.Items[1], eqset.Items[2], eqset.Items[3], eqset.Items[4], eqset.Items[5], eqset.Items[6], eqset.Items[7], - eqset.Items[8], eqset.Items[9], eqset.Items[10], eqset.Items[11], eqset.Items[12], eqset.Items[13], eqset.Items[14], eqset.Items[15], eqset.Items[16], eqset.Items[17], eqset.Items[18], GetGUIDLow(), eqset.Guid, eqset.Index); - } - else - { - QueryResult *result = CharacterDatabase.PQuery("SELECT MAX(setguid) FROM character_equipmentsets"); - if(!result) - eqset.Guid++; - else + uint32 index = itr->first; + EquipmentSet& eqset = itr->second; + switch(eqset.state) { - eqset.Guid = result->Fetch()[0].GetUInt64() + 1; - delete result; + case EQUIPMENT_SET_UNCHANGED: + ++itr; + break; // nothing do + case EQUIPMENT_SET_CHANGED: + CharacterDatabase.PExecute("UPDATE character_equipmentsets SET name='%s', iconname='%s', item0='%u', item1='%u', item2='%u', item3='%u', item4='%u', item5='%u', item6='%u', item7='%u', item8='%u', item9='%u', item10='%u', item11='%u', item12='%u', item13='%u', item14='%u', item15='%u', item16='%u', item17='%u', item18='%u' WHERE guid='%u' AND setguid='"I64FMTD"' AND setindex='%u'", + eqset.Name.c_str(), eqset.IconName.c_str(), eqset.Items[0], eqset.Items[1], eqset.Items[2], eqset.Items[3], eqset.Items[4], eqset.Items[5], eqset.Items[6], eqset.Items[7], + eqset.Items[8], eqset.Items[9], eqset.Items[10], eqset.Items[11], eqset.Items[12], eqset.Items[13], eqset.Items[14], eqset.Items[15], eqset.Items[16], eqset.Items[17], eqset.Items[18], GetGUIDLow(), eqset.Guid, index); + eqset.state = EQUIPMENT_SET_UNCHANGED; + ++itr; + break; + case EQUIPMENT_SET_NEW: + CharacterDatabase.PExecute("INSERT INTO character_equipmentsets VALUES ('%u', '"I64FMTD"', '%u', '%s', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", + GetGUIDLow(), eqset.Guid, index, eqset.Name.c_str(), eqset.IconName.c_str(), eqset.Items[0], eqset.Items[1], eqset.Items[2], eqset.Items[3], eqset.Items[4], eqset.Items[5], eqset.Items[6], eqset.Items[7], + eqset.Items[8], eqset.Items[9], eqset.Items[10], eqset.Items[11], eqset.Items[12], eqset.Items[13], eqset.Items[14], eqset.Items[15], eqset.Items[16], eqset.Items[17], eqset.Items[18]); + eqset.state = EQUIPMENT_SET_UNCHANGED; + ++itr; + break; + case EQUIPMENT_SET_DELETED: + CharacterDatabase.PExecute("DELETE FROM character_equipmentsets WHERE setguid="I64FMTD, eqset.Guid); + m_EquipmentSets.erase(itr++); + break; } - - CharacterDatabase.PExecute("INSERT INTO character_equipmentsets VALUES ('%u', '"I64FMTD"', '%u', '%s', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", - GetGUIDLow(), eqset.Guid, eqset.Index, eqset.Name.c_str(), eqset.IconName.c_str(), eqset.Items[0], eqset.Items[1], eqset.Items[2], eqset.Items[3], eqset.Items[4], eqset.Items[5], eqset.Items[6], eqset.Items[7], - eqset.Items[8], eqset.Items[9], eqset.Items[10], eqset.Items[11], eqset.Items[12], eqset.Items[13], eqset.Items[14], eqset.Items[15], eqset.Items[16], eqset.Items[17], eqset.Items[18]); - - WorldPacket data(SMSG_EQUIPMENT_SET_SAVED, 4+1); - data << uint32(eqset.Index); - data.appendPackGUID(eqset.Guid); - GetSession()->SendPacket(&data); } - - m_EquipmentSets[eqset.Index] = eqset; } void Player::DeleteEquipmentSet(uint64 setGuid) { - CharacterDatabase.PExecute("DELETE FROM character_equipmentsets WHERE setguid="I64FMTD, setGuid); - for(EquipmentSets::iterator itr = m_EquipmentSets.begin(); itr != m_EquipmentSets.end(); ++itr) { if(itr->second.Guid == setGuid) { - m_EquipmentSets.erase(itr); + itr->second.state = EQUIPMENT_SET_DELETED; break; } } diff --git a/src/game/Player.h b/src/game/Player.h index 33592abf1..2fa1477f6 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -703,15 +703,31 @@ enum QuestBagSlots QUESTBAG_SLOT_END = 200 }; +enum EquipmentSetUpdateState +{ + EQUIPMENT_SET_UNCHANGED = 0, + EQUIPMENT_SET_CHANGED = 1, + EQUIPMENT_SET_NEW = 2, + EQUIPMENT_SET_DELETED = 3 +}; + struct EquipmentSet { + EquipmentSet() : Guid(0), state(EQUIPMENT_SET_NEW) + { + for(int i = 0; i < EQUIPMENT_SLOT_END; ++i) + Items[i] = 0; + } + uint64 Guid; - uint32 Index; std::string Name; std::string IconName; uint32 Items[EQUIPMENT_SLOT_END]; + EquipmentSetUpdateState state; }; +#define MAX_EQUIPMENT_SET_INDEX 10 // client limit + typedef std::map EquipmentSets; struct ItemPosCount @@ -1851,7 +1867,7 @@ class MANGOS_DLL_SPEC Player : public Unit void CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attType); void CastItemUseSpell(Item *item,SpellCastTargets const& targets,uint8 cast_count, uint32 glyphIndex); - void SaveEquipmentSet(EquipmentSet eqset); + void SetEquipmentSet(uint32 index, EquipmentSet eqset); void DeleteEquipmentSet(uint64 setGuid); void SendInitWorldStates(); @@ -2226,6 +2242,7 @@ class MANGOS_DLL_SPEC Player : public Unit void _SaveDailyQuestStatus(); void _SaveReputation(); void _SaveSpells(); + void _SaveEquipmentSets(); void _SetCreateBits(UpdateMask *updateMask, Player *target) const; void _SetUpdateBits(UpdateMask *updateMask, Player *target) const; diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index e1b40f0f0..ec71cedc6 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -45,7 +45,8 @@ WorldSession::WorldSession(uint32 id, WorldSocket *sock, uint32 sec, uint8 expan LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time), _player(NULL), m_Socket(sock),_security(sec), _accountId(id), m_expansion(expansion), m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(objmgr.GetIndexForLocale(locale)), -_logoutTime(0), m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_latency(0) +_logoutTime(0), m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), +m_latency(0), m_TutorialsChanged(false) { if (sock) { @@ -586,6 +587,8 @@ void WorldSession::LoadTutorialsData() delete result; } + + m_TutorialsChanged = false; } void WorldSession::SendTutorialsData() @@ -598,6 +601,9 @@ void WorldSession::SendTutorialsData() void WorldSession::SaveTutorialsData() { + if(!m_TutorialsChanged) + return; + uint32 Rows=0; // it's better than rebuilding indexes multiple times QueryResult *result = CharacterDatabase.PQuery("SELECT count(*) AS r FROM character_tutorial WHERE account = '%u'", GetAccountId()); @@ -616,6 +622,8 @@ void WorldSession::SaveTutorialsData() { CharacterDatabase.PExecute("INSERT INTO character_tutorial (account,tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7) VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", GetAccountId(), m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7]); } + + m_TutorialsChanged = false; } void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo *mi) diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 526c33f47..043927d7a 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -180,7 +180,10 @@ class MANGOS_DLL_SPEC WorldSession void SetTutorialInt(uint32 intId, uint32 value) { if(m_Tutorials[intId] != value) + { m_Tutorials[intId] = value; + m_TutorialsChanged = true; + } } //mail @@ -711,6 +714,7 @@ class MANGOS_DLL_SPEC WorldSession uint32 m_latency; AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; uint32 m_Tutorials[8]; + bool m_TutorialsChanged; ZThread::LockedQueue _recvQueue; };