diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 5cebb3a2a..0a89ad16f 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -67,7 +67,6 @@ bool LoginQueryHolder::Initialize() res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,active,disabled FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADTUTORIALS, "SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u' AND realmid = '%u'", GetAccountId(), realmID); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button", GUID_LOPART(m_guid)); @@ -83,6 +82,7 @@ bool LoginQueryHolder::Initialize() res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, "SELECT arenateamid, played_week, played_season, personal_rating FROM arena_team_member WHERE guid='%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS,"SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= 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)); return res; } @@ -759,7 +759,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) if(uint32 sourceNode = pCurrChar->m_taxi.GetTaxiSource()) { - sLog.outDebug( "WORLD: Restart character %u taxi flight", pCurrChar->GetGUIDLow() ); uint32 MountId = objmgr.GetTaxiMount(sourceNode, pCurrChar->GetTeam()); @@ -924,9 +923,10 @@ void WorldSession::HandleTutorialFlag( WorldPacket & recv_data ) } uint32 rInt = (iFlag % 32); - uint32 tutflag = GetPlayer()->GetTutorialInt( wInt ); + uint32 tutflag = GetTutorialInt( wInt ); tutflag |= (1 << rInt); - GetPlayer()->SetTutorialInt( wInt, tutflag ); + SetTutorialInt( wInt, tutflag ); + SaveTutorialsData(); //sLog.outDebug("Received Tutorial Flag Set {%u}.", iFlag); } @@ -934,13 +934,15 @@ void WorldSession::HandleTutorialFlag( WorldPacket & recv_data ) void WorldSession::HandleTutorialClear( WorldPacket & /*recv_data*/ ) { for ( uint32 iI = 0; iI < 8; iI++) - GetPlayer()->SetTutorialInt( iI, 0xFFFFFFFF ); + SetTutorialInt( iI, 0xFFFFFFFF ); + SaveTutorialsData(); } void WorldSession::HandleTutorialReset( WorldPacket & /*recv_data*/ ) { for ( uint32 iI = 0; iI < 8; iI++) - GetPlayer()->SetTutorialInt( iI, 0x00000000 ); + SetTutorialInt( iI, 0x00000000 ); + SaveTutorialsData(); } void WorldSession::HandleSetWatchedFactionIndexOpcode(WorldPacket & recv_data) @@ -1326,5 +1328,46 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data) void WorldSession::HandleEquipmentSetSave(WorldPacket &recv_data) { sLog.outDebug("CMSG_EQUIPMENT_SET_SAVE"); - recv_data.hexlike(); + + uint64 setGuid; + if(!recv_data.readPackGUID(setGuid)) + return; + + CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4); + + uint32 Index; + recv_data >> Index; + + std::string name, iconName; + recv_data >> name >> iconName; + + EquipmentSet eqSet; + + eqSet.Guid = setGuid; + eqSet.Index = Index; + eqSet.Name = name; + eqSet.IconName = iconName; + + uint64 itemGuid; + + for(uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + { + if(!recv_data.readPackGUID(itemGuid)) + return; + + eqSet.Items[i] = GUID_LOPART(itemGuid); + } + + _player->SaveEquipmentSet(eqSet); +} + +void WorldSession::HandleEquipmentSetDelete(WorldPacket &recv_data) +{ + sLog.outDebug("CMSG_EQUIPMENT_SET_DELETE"); + + uint64 setGuid; + if(!recv_data.readPackGUID(setGuid)) + return; + + _player->DeleteEquipmentSet(setGuid); } diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index 0291abc83..956185971 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -994,9 +994,14 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data) sLog.outDetail( "MISC: Added Macro %u into button %u", action, button ); GetPlayer()->addActionButton(button,action,type,misc); } + else if(type==ACTION_BUTTON_EQSET) + { + sLog.outDetail( "MISC: Added EquipmentSet %u into button %u", action, button ); + GetPlayer()->addActionButton(button,action,type,misc); + } else if(type==ACTION_BUTTON_SPELL) { - sLog.outDetail( "MISC: Added Action %u into button %u", action, button ); + sLog.outDetail( "MISC: Added Spell %u into button %u", action, button ); GetPlayer()->addActionButton(button,action,type,misc); } else if(type==ACTION_BUTTON_ITEM) diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index 22e756f11..1445b8426 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -344,7 +344,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x13B*/ { "CMSG_CANCEL_CHANNELLING", STATUS_LOGGEDIN, &WorldSession::HandleCancelChanneling }, /*0x13C*/ { "SMSG_AI_REACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x13D*/ { "CMSG_SET_SELECTION", STATUS_LOGGEDIN, &WorldSession::HandleSetSelectionOpcode }, - /*0x13E*/ { "CMSG_SET_TARGET_OBSOLETE", STATUS_LOGGEDIN, &WorldSession::HandleSetTargetOpcode }, + /*0x13E*/ { "CMSG_EQUIPMENT_SET_DELETE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetDelete }, /*0x13F*/ { "CMSG_UNUSED", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x140*/ { "CMSG_UNUSED2", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x141*/ { "CMSG_ATTACKSWING", STATUS_LOGGEDIN, &WorldSession::HandleAttackSwingOpcode }, diff --git a/src/game/Opcodes.h b/src/game/Opcodes.h index 967980c43..bd355f169 100644 --- a/src/game/Opcodes.h +++ b/src/game/Opcodes.h @@ -345,14 +345,14 @@ enum Opcodes SMSG_SPELL_COOLDOWN = 0x134, SMSG_COOLDOWN_EVENT = 0x135, CMSG_CANCEL_AURA = 0x136, - SMSG_UPDATE_AURA_DURATION_OBSOLETE = 0x137, // 3.1 - equipment manager? uint32+guid + SMSG_UPDATE_AURA_DURATION_OBSOLETE = 0x137, // 3.1 - equipment manager? uint32+PGUID SMSG_PET_CAST_FAILED = 0x138, MSG_CHANNEL_START = 0x139, MSG_CHANNEL_UPDATE = 0x13A, CMSG_CANCEL_CHANNELLING = 0x13B, SMSG_AI_REACTION = 0x13C, CMSG_SET_SELECTION = 0x13D, - CMSG_SET_TARGET_OBSOLETE = 0x13E, + CMSG_EQUIPMENT_SET_DELETE = 0x13E, CMSG_UNUSED = 0x13F, CMSG_UNUSED2 = 0x140, CMSG_ATTACKSWING = 0x141, @@ -1257,7 +1257,8 @@ enum Opcodes UMSG_UNKNOWN_1220 = 0x4C4, // not found UMSG_UNKNOWN_1221 = 0x4C5, // not found UMSG_UNKNOWN_1222 = 0x4C6, // not found - NUM_MSG_TYPES = 0x4C7 + SMSG_UNKNOWN_1223 = 0x4C7, // arena pet? + NUM_MSG_TYPES = 0x4C8 }; /// Player state diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 6cc1e12b9..b5b92f401 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -343,10 +343,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this) PlayerTalkClass = new PlayerMenu( GetSession() ); m_currentBuybackSlot = BUYBACK_SLOT_START; - for ( int aX = 0 ; aX < 8 ; aX++ ) - m_Tutorials[ aX ] = 0x00; - m_TutorialsChanged = false; - m_DailyQuestChanged = false; m_lastDailyQuestTime = 0; @@ -14012,6 +14008,36 @@ void Player::_LoadArenaTeamInfo(QueryResult *result) delete result; } +void Player::_LoadEquipmentSets(QueryResult *result) +{ + if (!result) + return; + + uint32 count = 0; + do + { + Field *fields = result->Fetch(); + + EquipmentSet eqSet; + + eqSet.Guid = fields[0].GetUInt64(); + eqSet.Index = fields[1].GetUInt32(); + eqSet.Name = fields[2].GetCppString(); + eqSet.IconName = fields[3].GetCppString(); + + for(uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + eqSet.Items[i] = fields[4+i].GetUInt32(); + + m_EquipmentSets[eqSet.Index] = eqSet; + + ++count; + + if(count >= 10) + break; + } while (result->NextRow()); + delete result; +} + bool Player::LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, bool& in_flight, uint64 guid) { QueryResult *result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,taxi_path FROM characters WHERE guid = '%u'",GUID_LOPART(guid)); @@ -14467,8 +14493,6 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) InitTalentForLevel(); learnDefaultSpells(); - _LoadTutorials(holder->GetResult(PLAYER_LOGIN_QUERY_LOADTUTORIALS)); - // must be before inventory (some items required reputation check) _LoadReputation(holder->GetResult(PLAYER_LOGIN_QUERY_LOADREPUTATION)); @@ -14613,6 +14637,9 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) m_achievementMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS), holder->GetResult(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS)); m_achievementMgr.CheckAllAchievementCriteria(); + + _LoadEquipmentSets(holder->GetResult(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS)); + return true; } @@ -15281,27 +15308,6 @@ void Player::_LoadSpells(QueryResult *result) } } -void Player::_LoadTutorials(QueryResult *result) -{ - //QueryResult *result = CharacterDatabase.PQuery("SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u' AND realmid = '%u'", GetAccountId(), realmid); - - if(result) - { - do - { - Field *fields = result->Fetch(); - - for (int iI=0; iI<8; iI++) - m_Tutorials[iI] = fields[iI].GetUInt32(); - } - while( result->NextRow() ); - - delete result; - } - - m_TutorialsChanged = false; -} - void Player::_LoadGroup(QueryResult *result) { //QueryResult *result = CharacterDatabase.PQuery("SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", GetGUIDLow()); @@ -15731,7 +15737,6 @@ void Player::SaveToDB() _SaveInventory(); _SaveQuestStatus(); _SaveDailyQuestStatus(); - _SaveTutorials(); _SaveSpells(); _SaveSpellCooldowns(); _SaveActions(); @@ -16051,33 +16056,6 @@ void Player::_SaveSpells() } } -void Player::_SaveTutorials() -{ - 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' AND realmid = '%u'", GetSession()->GetAccountId(), realmID ); - if(result) - { - Rows = result->Fetch()[0].GetUInt32(); - delete result; - } - - if (Rows) - { - CharacterDatabase.PExecute("UPDATE character_tutorial SET tut0='%u', tut1='%u', tut2='%u', tut3='%u', tut4='%u', tut5='%u', tut6='%u', tut7='%u' WHERE account = '%u' AND realmid = '%u'", - m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7], GetSession()->GetAccountId(), realmID ); - } - else - { - CharacterDatabase.PExecute("INSERT INTO character_tutorial (account,realmid,tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7) VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", GetSession()->GetAccountId(), realmID, 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 Player::outDebugValues() const { if(!sLog.IsOutDebug()) // optimize disabled debug output @@ -18085,12 +18063,6 @@ void Player::SendInitialPacketsBeforeAddToMap() // SMSG_SET_PROFICIENCY // SMSG_UPDATE_AURA_DURATION - // tutorial stuff - /*data.Initialize(SMSG_TUTORIAL_FLAGS, 8*4); - for (int i = 0; i < 8; ++i) - data << uint32( GetTutorialInt(i) ); - GetSession()->SendPacket(&data);*/ - SendTalentsInfoData(false); SendInitialSpells(); @@ -18104,18 +18076,17 @@ void Player::SendInitialPacketsBeforeAddToMap() m_achievementMgr.SendAllAchievementData(); UpdateZone(GetZoneId()); - // equipment manager! data.Initialize(SMSG_EQUIPMENT_SET_LIST); - data << uint32(0); // count - /*for(count) + data << uint32(m_EquipmentSets.size()); // count + for(EquipmentSets::iterator itr = m_EquipmentSets.begin(); itr != m_EquipmentSets.end(); ++itr) { - data << uint8(0); // PGUID, equipment set guid? - data << uint32(0); // counter(0,1,...)? - data << uint8(0); // string set name - data << uint8(0); // string icon name + data.appendPackGUID(itr->second.Guid); + data << uint32(itr->second.Index); + data << itr->second.Name; + data << itr->second.IconName; for(uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) - data << uint8(0); // item GUID? - }*/ + data.appendPackGUID(MAKE_NEW_GUID(itr->second.Items[i], 0, HIGHGUID_ITEM)); + } GetSession()->SendPacket(&data); data.Initialize(SMSG_LOGIN_SETTIMESPEED, 8); @@ -18123,10 +18094,6 @@ void Player::SendInitialPacketsBeforeAddToMap() data << (float)0.01666667f; // game speed GetSession()->SendPacket( &data ); - data.Initialize(SMSG_TIME_SYNC_REQ, 4); // new 2.0.x, enable movement - data << uint32(0x00000000); // on blizz it increments periodically - GetSession()->SendPacket(&data); - // set fly flag if in fly form or taxi flight to prevent visually drop at ground in showup moment if(HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED) || isInFlight()) AddUnitMovementFlag(MOVEMENTFLAG_FLYING2); @@ -19958,3 +19925,39 @@ void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank) pet->learnSpell(spellid); sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid); } + +void Player::SaveEquipmentSet(EquipmentSet eqset) +{ + if(m_EquipmentSets.size() >= 10) // client limit + return; + + EquipmentSets::iterator itr = m_EquipmentSets.find(eqset.Index); + if(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 + { + 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]); + } + + 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); + break; + } + } +} diff --git a/src/game/Player.h b/src/game/Player.h index 86fefeb6d..33592abf1 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -145,6 +145,7 @@ struct ActionButton enum ActionButtonType { ACTION_BUTTON_SPELL = 0, + ACTION_BUTTON_EQSET = 32, ACTION_BUTTON_MACRO = 64, ACTION_BUTTON_CMACRO= 65, ACTION_BUTTON_ITEM = 128 @@ -702,6 +703,17 @@ enum QuestBagSlots QUESTBAG_SLOT_END = 200 }; +struct EquipmentSet +{ + uint64 Guid; + uint32 Index; + std::string Name; + std::string IconName; + uint32 Items[EQUIPMENT_SLOT_END]; +}; + +typedef std::map EquipmentSets; + struct ItemPosCount { ItemPosCount(uint16 _pos, uint32 _count) : pos(_pos), count(_count) {} @@ -833,24 +845,23 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOADSPELLS = 4, PLAYER_LOGIN_QUERY_LOADQUESTSTATUS = 5, PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS = 6, - PLAYER_LOGIN_QUERY_LOADTUTORIALS = 7, // common for all characters for some account at specific realm - PLAYER_LOGIN_QUERY_LOADREPUTATION = 8, - PLAYER_LOGIN_QUERY_LOADINVENTORY = 9, - PLAYER_LOGIN_QUERY_LOADACTIONS = 10, - PLAYER_LOGIN_QUERY_LOADMAILCOUNT = 11, - PLAYER_LOGIN_QUERY_LOADMAILDATE = 12, - PLAYER_LOGIN_QUERY_LOADSOCIALLIST = 13, - PLAYER_LOGIN_QUERY_LOADHOMEBIND = 14, - PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS = 15, - PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES = 16, - PLAYER_LOGIN_QUERY_LOADGUILD = 17, - PLAYER_LOGIN_QUERY_LOADARENAINFO = 18, - PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS = 19, - PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS = 20, + PLAYER_LOGIN_QUERY_LOADREPUTATION = 7, + PLAYER_LOGIN_QUERY_LOADINVENTORY = 8, + PLAYER_LOGIN_QUERY_LOADACTIONS = 9, + PLAYER_LOGIN_QUERY_LOADMAILCOUNT = 10, + PLAYER_LOGIN_QUERY_LOADMAILDATE = 11, + PLAYER_LOGIN_QUERY_LOADSOCIALLIST = 12, + PLAYER_LOGIN_QUERY_LOADHOMEBIND = 13, + PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS = 14, + PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES = 15, + PLAYER_LOGIN_QUERY_LOADGUILD = 16, + PLAYER_LOGIN_QUERY_LOADARENAINFO = 17, + PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS = 18, + PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS = 19, + PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS = 20, MAX_PLAYER_LOGIN_QUERY = 21 }; - // Player summoning auto-decline time (in secs) #define MAX_PLAYER_SUMMON_DELAY (2*MINUTE) #define MAX_MONEY_AMOUNT (0x7FFFFFFF-1) @@ -1363,22 +1374,6 @@ class MANGOS_DLL_SPEC Player : public Unit MoneyChanged( value ); } - uint32 GetTutorialInt(uint32 intId ) - { - ASSERT( (intId < 8) ); - return m_Tutorials[intId]; - } - - void SetTutorialInt(uint32 intId, uint32 value) - { - ASSERT( (intId < 8) ); - if(m_Tutorials[intId]!=value) - { - m_Tutorials[intId] = value; - m_TutorialsChanged = true; - } - } - QuestStatusMap& getQuestStatusMap() { return mQuestStatus; }; const uint64& GetSelection( ) const { return m_curSelection; } @@ -1856,6 +1851,9 @@ 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 DeleteEquipmentSet(uint64 setGuid); + void SendInitWorldStates(); void SendUpdateWorldState(uint32 Field, uint32 Value); void SendDirectMessage(WorldPacket *data); @@ -2210,11 +2208,11 @@ class MANGOS_DLL_SPEC Player : public Unit void _LoadReputation(QueryResult *result); void _LoadSkills(); void _LoadSpells(QueryResult *result); - void _LoadTutorials(QueryResult *result); void _LoadFriendList(QueryResult *result); bool _LoadHomeBind(QueryResult *result); void _LoadDeclinedNames(QueryResult *result); void _LoadArenaTeamInfo(QueryResult *result); + void _LoadEquipmentSets(QueryResult *result); /*********************************************************/ /*** SAVE SYSTEM ***/ @@ -2228,7 +2226,6 @@ class MANGOS_DLL_SPEC Player : public Unit void _SaveDailyQuestStatus(); void _SaveReputation(); void _SaveSpells(); - void _SaveTutorials(); void _SetCreateBits(UpdateMask *updateMask, Player *target) const; void _SetUpdateBits(UpdateMask *updateMask, Player *target) const; @@ -2318,9 +2315,6 @@ class MANGOS_DLL_SPEC Player : public Unit time_t m_nextThinkTime; - uint32 m_Tutorials[8]; - bool m_TutorialsChanged; - bool m_DailyQuestChanged; time_t m_lastDailyQuestTime; @@ -2394,6 +2388,7 @@ class MANGOS_DLL_SPEC Player : public Unit DeclinedName *m_declinedname; Runes *m_runes; AchievementMgr m_achievementMgr; + EquipmentSets m_EquipmentSets; private: // internal common parts for CanStore/StoreItem functions uint8 _CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool swap, Item *pSrcItem ) const; diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 73f622d6d..e1b40f0f0 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -566,6 +566,58 @@ void WorldSession::SetAccountData(uint32 type, time_t time_, std::string data) CharacterDatabase.CommitTransaction (); } +void WorldSession::LoadTutorialsData() +{ + for ( int aX = 0 ; aX < 8 ; ++aX ) + m_Tutorials[ aX ] = 0; + + QueryResult *result = CharacterDatabase.PQuery("SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u'", GetAccountId()); + + if(result) + { + do + { + Field *fields = result->Fetch(); + + for (int iI = 0; iI < 8; iI++) + m_Tutorials[iI] = fields[iI].GetUInt32(); + } + while( result->NextRow() ); + + delete result; + } +} + +void WorldSession::SendTutorialsData() +{ + WorldPacket data(SMSG_TUTORIAL_FLAGS, 4*8); + for(uint32 i = 0; i < 8; ++i) + data << m_Tutorials[i]; + SendPacket(&data); +} + +void WorldSession::SaveTutorialsData() +{ + 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()); + if(result) + { + Rows = result->Fetch()[0].GetUInt32(); + delete result; + } + + if (Rows) + { + CharacterDatabase.PExecute("UPDATE character_tutorial SET tut0='%u', tut1='%u', tut2='%u', tut3='%u', tut4='%u', tut5='%u', tut6='%u', tut7='%u' WHERE account = '%u'", + m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7], GetAccountId()); + } + else + { + 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]); + } +} + void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo *mi) { CHECK_PACKET_SIZE(data, data.rpos()+4+2+4+4+4+4+4); diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 6ace0b362..526c33f47 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -169,6 +169,19 @@ class MANGOS_DLL_SPEC WorldSession AccountData *GetAccountData(uint32 type) { return &m_accountData[type]; } void SetAccountData(uint32 type, time_t time_, std::string data); void LoadAccountData(); + void LoadTutorialsData(); + void SendTutorialsData(); + void SaveTutorialsData(); + uint32 GetTutorialInt(uint32 intId ) + { + return m_Tutorials[intId]; + } + + void SetTutorialInt(uint32 intId, uint32 value) + { + if(m_Tutorials[intId] != value) + m_Tutorials[intId] = value; + } //mail //used with item_page table @@ -672,6 +685,7 @@ class MANGOS_DLL_SPEC WorldSession void HandleCharCustomize(WorldPacket& recv_data); void HandleInspectAchievements(WorldPacket& recv_data); void HandleEquipmentSetSave(WorldPacket& recv_data); + void HandleEquipmentSetDelete(WorldPacket& recv_data); private: // private trade methods void moveItems(Item* myItems[], Item* hisItems[]); @@ -696,6 +710,7 @@ class MANGOS_DLL_SPEC WorldSession int m_sessionDbLocaleIndex; uint32 m_latency; AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; + uint32 m_Tutorials[8]; ZThread::LockedQueue _recvQueue; }; diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp index 570d38ebc..bc95ab1b7 100644 --- a/src/game/WorldSocket.cpp +++ b/src/game/WorldSocket.cpp @@ -187,7 +187,7 @@ int WorldSocket::SendPacket (const WorldPacket& pct) } ServerPktHeader header(pct.size()+2, pct.GetOpcode()); - m_Crypt.EncryptSend ( header.header, header.getHeaderLength()); + //m_Crypt.EncryptSend ( header.header, header.getHeaderLength()); if (m_OutBuffer->space () >= pct.size () + header.getHeaderLength() && msg_queue()->is_empty()) { @@ -480,7 +480,7 @@ int WorldSocket::handle_input_header (void) ACE_ASSERT (m_Header.length () == sizeof (ClientPktHeader)); - m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader)); + //m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader)); ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ()); @@ -982,10 +982,10 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) // NOTE ATM the socket is singlethreaded, have this in mind ... ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1); - m_Crypt.SetKey (&K); - m_Crypt.Init (); + m_Crypt.Init(&K); m_Session->LoadAccountData(); + m_Session->LoadTutorialsData(); // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec ACE_OS::sleep (ACE_Time_Value (0, 10000)); @@ -996,11 +996,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked)) SendPacket (SendAddonPacked); - // TODO: fix it! - WorldPacket data(SMSG_TUTORIAL_FLAGS, 4*8); - for(uint32 i = 0; i < 8; ++i) - data << uint32(-1); - SendPacket(data); + m_Session->SendTutorialsData(); return 0; } diff --git a/src/realmd/AuthCodes.h b/src/realmd/AuthCodes.h index b9351b748..4e08b13bf 100644 --- a/src/realmd/AuthCodes.h +++ b/src/realmd/AuthCodes.h @@ -66,8 +66,8 @@ enum LoginResult // we need to stick to 1 version or half of the stuff will work for someone // others will not and opposite -// will only support WoW, WoW:TBC and WoW:WotLK 3.1.0 client build 9626... +// will only support WoW, WoW:TBC and WoW:WotLK 3.1.0 client build 9637... -#define EXPECTED_MANGOS_CLIENT_BUILD {9626, 0} +#define EXPECTED_MANGOS_CLIENT_BUILD {9637, 0} #endif diff --git a/src/shared/Auth/AuthCrypt.cpp b/src/shared/Auth/AuthCrypt.cpp index 5c91a22bc..ae38dc1ba 100644 --- a/src/shared/Auth/AuthCrypt.cpp +++ b/src/shared/Auth/AuthCrypt.cpp @@ -24,57 +24,46 @@ AuthCrypt::AuthCrypt() _initialized = false; } -void AuthCrypt::Init() +AuthCrypt::~AuthCrypt() { - _send_i = _send_j = _recv_i = _recv_j = 0; + +} + +void AuthCrypt::Init(BigNumber *K) +{ + uint8 recvSeed[SEED_KEY_SIZE] = { 0x22, 0xBE, 0xE5, 0xCF, 0xBB, 0x07, 0x64, 0xD9, 0x00, 0x45, 0x1B, 0xD0, 0x24, 0xB8, 0xD5, 0x45 }; + HmacHash recvHash(SEED_KEY_SIZE, (uint8*)recvSeed); + recvHash.UpdateBigNumber(K); + recvHash.Finalize(); + _recvCrypt.Init(SHA_DIGEST_LENGTH, recvHash.GetDigest()); + + uint8 sendSeed[SEED_KEY_SIZE] = { 0xF4, 0x66, 0x31, 0x59, 0xFC, 0x83, 0x6E, 0x31, 0x31, 0x02, 0x51, 0xD5, 0x44, 0x31, 0x67, 0x98 }; + HmacHash sendHash(SEED_KEY_SIZE, (uint8*)sendSeed); + sendHash.UpdateBigNumber(K); + sendHash.Finalize(); + _sendCrypt.Init(SHA_DIGEST_LENGTH, sendHash.GetDigest()); + + uint8 emptyBuf[1000]; + memset(emptyBuf, 0, 1000); + + _sendCrypt.Process(1000, (uint8*)emptyBuf, (uint8*)emptyBuf); + _recvCrypt.Process(1000, (uint8*)emptyBuf, (uint8*)emptyBuf); + _initialized = true; } void AuthCrypt::DecryptRecv(uint8 *data, size_t len) { - if (!_initialized) return; - if (len < CRYPTED_RECV_LEN) return; + if (!_initialized) + return; - for (size_t t = 0; t < CRYPTED_RECV_LEN; t++) - { - _recv_i %= _key.size(); - uint8 x = (data[t] - _recv_j) ^ _key[_recv_i]; - ++_recv_i; - _recv_j = data[t]; - data[t] = x; - } + _recvCrypt.Process(len, data, data); } void AuthCrypt::EncryptSend(uint8 *data, size_t len) { - if (!_initialized) return; + if (!_initialized) + return; - for (size_t t = 0; t < len; t++) - { - _send_i %= _key.size(); - uint8 x = (data[t] ^ _key[_send_i]) + _send_j; - ++_send_i; - data[t] = _send_j = x; - } -} - -void AuthCrypt::SetKey(BigNumber *bn) -{ - uint8 *key = new uint8[SHA_DIGEST_LENGTH]; - GenerateKey(key, bn); - _key.resize(SHA_DIGEST_LENGTH); - std::copy(key, key + SHA_DIGEST_LENGTH, _key.begin()); - delete[] key; -} - -AuthCrypt::~AuthCrypt() -{ -} - -void AuthCrypt::GenerateKey(uint8 *key, BigNumber *bn) -{ - HmacHash hash; - hash.UpdateBigNumber(bn); - hash.Finalize(); - memcpy(key, hash.GetDigest(), SHA_DIGEST_LENGTH); + _sendCrypt.Process(len, data, data); } diff --git a/src/shared/Auth/AuthCrypt.h b/src/shared/Auth/AuthCrypt.h index 5717f72ec..4ad71694a 100644 --- a/src/shared/Auth/AuthCrypt.h +++ b/src/shared/Auth/AuthCrypt.h @@ -21,6 +21,7 @@ #include #include +#include "SARC4.h" class BigNumber; @@ -30,22 +31,15 @@ class AuthCrypt AuthCrypt(); ~AuthCrypt(); - const static size_t CRYPTED_RECV_LEN = 6; - - void Init(); - - void SetKey(BigNumber *); - + void Init(BigNumber *K); void DecryptRecv(uint8 *, size_t); void EncryptSend(uint8 *, size_t); bool IsInitialized() { return _initialized; } - static void GenerateKey(uint8 *, BigNumber *); - private: - std::vector _key; - uint8 _send_i, _send_j, _recv_i, _recv_j; + SARC4 _sendCrypt; + SARC4 _recvCrypt; bool _initialized; }; #endif diff --git a/src/shared/Auth/Hmac.cpp b/src/shared/Auth/Hmac.cpp index d0517aad7..380907448 100644 --- a/src/shared/Auth/Hmac.cpp +++ b/src/shared/Auth/Hmac.cpp @@ -19,10 +19,11 @@ #include "Auth/Hmac.h" #include "BigNumber.h" -HmacHash::HmacHash() +HmacHash::HmacHash(uint32 len, uint8 *seed) { - uint8 temp[SEED_KEY_SIZE] = { 0x38, 0xA7, 0x83, 0x15, 0xF8, 0x92, 0x25, 0x30, 0x71, 0x98, 0x67, 0xB1, 0x8C, 0x4, 0xE2, 0xAA }; - memcpy(&m_key, &temp, SEED_KEY_SIZE); + ASSERT(len == SEED_KEY_SIZE); + + memcpy(&m_key, seed, len); HMAC_CTX_init(&m_ctx); HMAC_Init_ex(&m_ctx, &m_key, SEED_KEY_SIZE, EVP_sha1(), NULL); } diff --git a/src/shared/Auth/Hmac.h b/src/shared/Auth/Hmac.h index 3e0dacc3b..0b4058335 100644 --- a/src/shared/Auth/Hmac.h +++ b/src/shared/Auth/Hmac.h @@ -30,7 +30,7 @@ class BigNumber; class HmacHash { public: - HmacHash(); + HmacHash(uint32 len, uint8 *seed); ~HmacHash(); void UpdateBigNumber(BigNumber *bn); void UpdateData(const uint8 *data, int length); diff --git a/src/shared/Auth/Makefile.am b/src/shared/Auth/Makefile.am index 9e4956711..34e56ad0a 100644 --- a/src/shared/Auth/Makefile.am +++ b/src/shared/Auth/Makefile.am @@ -33,6 +33,8 @@ libmangosauth_a_SOURCES = \ BigNumber.h \ Hmac.cpp \ Hmac.h \ + SARC4.cpp \ + SARC4.h \ Sha1.cpp \ Sha1.h \ md5.c \ diff --git a/src/shared/Auth/SARC4.cpp b/src/shared/Auth/SARC4.cpp new file mode 100644 index 000000000..7b0bf21c4 --- /dev/null +++ b/src/shared/Auth/SARC4.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Auth/SARC4.h" +#include "BigNumber.h" + +void SARC4::Init(uint32 len, uint8 *seed) +{ + RC4_set_key(&m_rc4_key, len, seed); +} + +void SARC4::Process(uint32 len, uint8 *indata, uint8 *outdata) +{ + RC4(&m_rc4_key, len, indata, outdata); +} diff --git a/src/shared/Auth/SARC4.h b/src/shared/Auth/SARC4.h new file mode 100644 index 000000000..2a8c6403e --- /dev/null +++ b/src/shared/Auth/SARC4.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _AUTH_SARC4_H +#define _AUTH_SARC4_H + +#include "Common.h" +#include +#include + +class BigNumber; + +#define SEED_KEY_SIZE 16 + +class SARC4 +{ + public: + void Init(uint32 len, uint8 *seed); + void Process(uint32 len, uint8 *indata, uint8 *outdata); + private: + RC4_KEY m_rc4_key; +}; +#endif diff --git a/win/VC90/shared.vcproj b/win/VC90/shared.vcproj index 32931be90..29e6d8bf1 100644 --- a/win/VC90/shared.vcproj +++ b/win/VC90/shared.vcproj @@ -632,6 +632,14 @@ RelativePath="..\..\src\shared\Auth\Hmac.h" > + + + +