diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index bce5f62782c..fd54a522cbb 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -121,7 +121,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT spell, talentGroup FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW, "SELECT quest FROM character_queststatus_rewarded WHERE guid = ? AND active = 1", CONNECTION_ASYNC); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 5a379ca9ec1..1592241cac3 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -6118,6 +6118,9 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal) } } } + + if (Guild * guild = GetGuild()) + guild->UpdateMemberData(this, GUILD_MEMBER_DATA_PROFESSIONS, 0); } bool Player::HasSkill(uint32 skill) const @@ -17330,6 +17333,34 @@ bool Player::LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, flo return true; } +void Player::LoadPrimaryProfessionsFromDB(ObjectGuid guid, std::vector& data) +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SKILLS); + stmt->setUInt32(0, guid.GetCounter()); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (result) + { + do + { + Field* fields = result->Fetch(); + uint16 skill = fields[0].GetUInt16(); + uint16 value = fields[1].GetUInt16(); + uint16 max = fields[2].GetUInt16(); + + SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skill); + if (!skillLine || skillLine->categoryId != SKILL_CATEGORY_PROFESSION) + continue; + + PrimaryProfessionData profession; + profession.SkillId = skill; + profession.Step = max / 75; + profession.Rank = value; + data.push_back(profession); + + } while (result->NextRow()); + } +} + void Player::SetHomebind(WorldLocation const& loc, uint32 areaId) { loc.GetPosition(m_homebindX, m_homebindY, m_homebindZ); @@ -28584,3 +28615,26 @@ void Player::SendTamePetFailure(PetTameFailureReason reason) data << uint8(reason); SendDirectMessage(&data); } + +void Player::GetPrimaryProfessionData(PrimaryProfessionData* data) +{ + for (uint8 i = 0; i < 2; i++) + { + uint32 skillId = GetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + i); + SkillStatusMap::iterator itr = mSkillStatus.find(skillId); + if (itr != mSkillStatus.end() && itr->second.uState != SKILL_DELETED) + { + uint16 field = itr->second.pos / 2; + uint8 offset = itr->second.pos & 1; // itr->second.pos % 2 + data[i].SkillId = skillId; + data[i].Step = GetUInt16Value(PLAYER_SKILL_STEP_0 + field, offset); + data[i].Rank = GetUInt16Value(PLAYER_SKILL_RANK_0 + field, offset); + } + else + { + data[i].SkillId = 0; + data[i].Step = 0; + data[i].Rank = 0; + } + } +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 4064fe1010c..3c274e85f92 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -376,6 +376,13 @@ struct EnchantDuration typedef std::list EnchantDurationList; typedef std::list ItemDurationList; +struct PrimaryProfessionData +{ + uint32 SkillId = 0; + uint32 Step = 0; + uint32 Rank = 0; +}; + enum DrunkenState { DRUNKEN_SOBER = 0, @@ -1089,6 +1096,8 @@ class TC_GAME_API Player : public Unit, public GridObject void SendTamePetFailure(PetTameFailureReason reason); + void GetPrimaryProfessionData(PrimaryProfessionData* professions); + PlayerTaxi m_taxi; void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), getLevel()); } bool ActivateTaxiPathTo(std::vector const& nodes, Creature* npc = nullptr, uint32 spellid = 0); @@ -1493,6 +1502,7 @@ class TC_GAME_API Player : public Unit, public GridObject static float GetFloatValueFromArray(Tokenizer const& data, uint16 index); static uint32 GetZoneIdFromDB(ObjectGuid guid); static bool LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid guid); + static void LoadPrimaryProfessionsFromDB(ObjectGuid guid, std::vector& data); static bool IsValidGender(uint8 Gender) { return Gender <= GENDER_FEMALE; } static bool ValidateAppearance(uint8 race, uint8 class_, uint8 gender, uint8 hairID, uint8 hairColor, uint8 faceID, uint8 facialHair, uint8 skinColor, bool create = false); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index a30118e0400..d7fea36cc10 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -676,6 +676,7 @@ Guild::Member::Member(ObjectGuid::LowType guildId, ObjectGuid guid, uint8 rankId m_weekReputation(0) { memset(m_bankWithdraw, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(int32)); + memset(m_professions, 0, GUILD_PROFESSION_COUNT * sizeof(PrimaryProfessionData)); } void Guild::Member::SetStats(Player* player) @@ -799,7 +800,21 @@ bool Guild::Member::LoadFromDB(Field* fields) m_zoneId = Player::GetZoneIdFromDB(m_guid); } - + std::vector professions; + Player::LoadPrimaryProfessionsFromDB(m_guid, professions); + if (professions.size() > GUILD_PROFESSION_COUNT) + TC_LOG_ERROR("guild", "Guild::Member::LoadFromDB: Character %s has too many primary professions. Skipped loading profession data.", m_guid.ToString().c_str()); + else + { + uint8 index = 0; + for (PrimaryProfessionData profession : professions) + { + m_professions[index].SkillId = profession.SkillId; + m_professions[index].Rank = profession.Rank; + m_professions[index].Step = profession.Step; + index++; + } + } ResetFlags(); return true; @@ -899,6 +914,15 @@ void Guild::Member::ResetWeekActivityAndReputation() CharacterDatabase.CommitTransaction(trans); } +void Guild::Member::UpdatePrimaryProfessionData() +{ + if (!IsOnline()) + return; + + Player* player = FindConnectedPlayer(); + player->GetPrimaryProfessionData(m_professions); +} + // Get amount of money/slots left for today. // If (tabId == GUILD_BANK_MAX_TABS) return money amount. // Otherwise return remaining items amount for specified tab. @@ -1477,6 +1501,9 @@ void Guild::UpdateMemberData(Player* player, uint8 dataid, uint32 value) case GUILD_MEMBER_DATA_LEVEL: member->SetLevel(value); break; + case GUILD_MEMBER_DATA_PROFESSIONS: + member->UpdatePrimaryProfessionData(); + break; default: TC_LOG_ERROR("guild", "Guild::UpdateMemberData: Called with incorrect DATAID %u (value %u)", dataid, value); return; @@ -1556,7 +1583,12 @@ void Guild::HandleRoster(WorldSession* session) memberData.LastSave = member->GetInactiveDays(); memberData.GuildRepToCap = sWorld->getIntConfig(CONFIG_GUILD_WEEKLY_REP_CAP) - member->GetWeekReputation(); - //GuildRosterProfessionData + for (uint8 i = 0; i < GUILD_PROFESSION_COUNT; i++) + { + memberData.Profession[i].DbID = member->GetPrimaryProfessionData(i).SkillId; + memberData.Profession[i].Step = member->GetPrimaryProfessionData(i).Step; + memberData.Profession[i].Rank = member->GetPrimaryProfessionData(i).Rank; + } memberData.VirtualRealmAddress = 0; memberData.Status = member->GetFlags(); @@ -2927,6 +2959,7 @@ bool Guild::AddMember(SQLTransaction& trans, ObjectGuid guid, uint8 rankId) player->SetGuildIdInvited(0); player->SetRank(rankId); player->SetGuildLevel(GetLevel()); + member->UpdatePrimaryProfessionData(); SendLoginInfo(player->GetSession()); name = player->GetName(); } diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 95a6e632ee8..d0ced922caf 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -33,6 +33,7 @@ class Unit; class WorldPacket; class WorldSession; struct ItemPosCount; +struct PrimaryProfessionData; enum AchievementCriteriaTypes : uint8; enum InventoryResult : uint8; enum LocaleConstant : uint8; @@ -49,6 +50,7 @@ enum GuildMisc GUILD_WITHDRAW_SLOT_UNLIMITED = 0xFFFFFFFF, GUILD_EVENT_LOG_GUID_UNDEFINED = 0xFFFFFFFF, GUILD_EXPERIENCE_UNCAPPED_LEVEL = 20, ///> Hardcoded in client, starting from this level, guild daily experience gain is unlimited. + GUILD_PROFESSION_COUNT = 2, TAB_UNDEFINED = 0xFF, }; @@ -57,6 +59,7 @@ enum GuildMemberData GUILD_MEMBER_DATA_ZONEID, GUILD_MEMBER_DATA_ACHIEVEMENT_POINTS, GUILD_MEMBER_DATA_LEVEL, + GUILD_MEMBER_DATA_PROFESSIONS }; enum GuildDefaultRanks @@ -354,6 +357,7 @@ private: void AddActivity(uint64 activity); void SetWeekReputation(uint32 reputation) { m_weekReputation = reputation; } void AddReputation(uint32 rep, Player *player); + void UpdatePrimaryProfessionData(); void AddFlag(uint8 var) { m_flags |= var; } void RemFlag(uint8 var) { m_flags &= ~var; } @@ -381,6 +385,7 @@ private: uint64 GetWeekActivity() const { return m_weekActivity; } uint32 GetTotalReputation() const { return m_totalReputation; } uint32 GetWeekReputation() const { return m_weekReputation; } + PrimaryProfessionData GetPrimaryProfessionData(uint8 index) const { return m_professions[index]; } std::set GetTrackedCriteriaIds() const { return m_trackedCriteriaIds; } void SetTrackedCriteriaIds(std::set criteriaIds) { m_trackedCriteriaIds.swap(criteriaIds); } @@ -427,6 +432,7 @@ private: uint64 m_weekActivity; uint32 m_totalReputation; uint32 m_weekReputation; + PrimaryProfessionData m_professions[GUILD_PROFESSION_COUNT]; }; // Base class for event entries diff --git a/src/server/game/Server/Packets/GuildPackets.cpp b/src/server/game/Server/Packets/GuildPackets.cpp index 43a9043b174..9d205e3ea8f 100644 --- a/src/server/game/Server/Packets/GuildPackets.cpp +++ b/src/server/game/Server/Packets/GuildPackets.cpp @@ -256,8 +256,8 @@ WorldPacket const* WorldPackets::Guild::GuildRoster::Write() ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Guild::GuildRosterProfessionData const& rosterProfessionData) { - data << uint32(rosterProfessionData.Rank); data << uint32(rosterProfessionData.Step); + data << uint32(rosterProfessionData.Rank); data << uint32(rosterProfessionData.DbID); return data;