diff --git a/src/common/Collision/Management/MMapMgr.cpp b/src/common/Collision/Management/MMapMgr.cpp index e1e64ac9f..315b446fb 100644 --- a/src/common/Collision/Management/MMapMgr.cpp +++ b/src/common/Collision/Management/MMapMgr.cpp @@ -141,7 +141,8 @@ namespace MMAP uint32 packedGridPos = packTileID(x, y); if (mmap->loadedTileRefs.find(packedGridPos) != mmap->loadedTileRefs.end()) { - LOG_ERROR("maps", "MMAP:loadMap: Asked to load already loaded navmesh tile. {:03}{:02}{:02}.mmtile", mapId, x, y); + // Peiru: Commented out for now because Playerbots system uses this method to load or check loaded maps and will spam logs +// LOG_ERROR("maps", "MMAP:loadMap: Asked to load already loaded navmesh tile. {:03}{:02}{:02}.mmtile", mapId, x, y); return false; } diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index ccb63cf7e..6aa99d3a5 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -75,6 +75,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_IP_NOT_BANNED, "DELETE FROM ip_banned WHERE ip = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_ACCOUNT_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?, 1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED, "UPDATE account_banned SET active = 0 WHERE id = ? AND active != 0", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM, "DELETE FROM realmcharacters WHERE acctid = ? AND realmid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_REP_REALM_CHARACTERS, "REPLACE INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index 3a9bb4a82..5872eddca 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -59,6 +59,7 @@ enum LoginDatabaseStatements : uint32 LOGIN_SEL_ACCOUNT_BY_ID, LOGIN_INS_ACCOUNT_BANNED, LOGIN_UPD_ACCOUNT_NOT_BANNED, + LOGIN_DEL_REALM_CHARACTERS_BY_REALM, LOGIN_DEL_REALM_CHARACTERS, LOGIN_REP_REALM_CHARACTERS, LOGIN_SEL_SUM_REALM_CHARACTERS, diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h index 403664faf..6933f0944 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h @@ -287,6 +287,18 @@ protected: uint32 BasesDefended = 0; }; +struct CaptureABPointInfo +{ + CaptureABPointInfo() : _ownerTeamId(TEAM_NEUTRAL), _iconNone(0), _iconCapture(0), _state(BG_AB_NODE_STATE_NEUTRAL), _captured(false) {} + + TeamId _ownerTeamId; + uint32 _iconNone; + uint32 _iconCapture; + uint8 _state; + + bool _captured; +}; + class AC_GAME_API BattlegroundAB : public Battleground { public: @@ -311,6 +323,9 @@ public: bool IsTeamScores500Disadvantage(TeamId teamId) const { return _teamScores500Disadvantage[teamId]; } TeamId GetPrematureWinner() override; + + [[nodiscard]] CaptureABPointInfo const& GetCapturePointInfo(uint32 node) const { return _capturePointInfo[node]; } + private: void PostUpdateImpl(uint32 diff) override; @@ -321,21 +336,7 @@ private: void NodeDeoccupied(uint8 node); void ApplyPhaseMask(); - struct CapturePointInfo - { - CapturePointInfo() : _ownerTeamId(TEAM_NEUTRAL), _iconNone(0), _iconCapture(0), _state(BG_AB_NODE_STATE_NEUTRAL), _captured(false) - { - } - - TeamId _ownerTeamId; - uint32 _iconNone; - uint32 _iconCapture; - uint8 _state; - - bool _captured; - }; - - CapturePointInfo _capturePointInfo[BG_AB_DYNAMIC_NODES_COUNT]; + CaptureABPointInfo _capturePointInfo[BG_AB_DYNAMIC_NODES_COUNT]; EventMap _bgEvents; uint32 _honorTics; uint32 _reputationTics; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h index 4e364df5b..c151117f5 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h @@ -376,6 +376,25 @@ protected: uint32 FlagCaptures = 0; }; +struct CaptureEYPointInfo +{ + CaptureEYPointInfo() : _ownerTeamId(TEAM_NEUTRAL), _barStatus(BG_EY_PROGRESS_BAR_STATE_MIDDLE), _areaTrigger(0) + { + _playersCount[TEAM_ALLIANCE] = 0; + _playersCount[TEAM_HORDE] = 0; + } + + Player* player = nullptr; + TeamId _ownerTeamId; + int8 _barStatus; + uint32 _areaTrigger; + int8 _playersCount[PVP_TEAMS_COUNT]; + + bool IsUnderControl(TeamId teamId) const { return _ownerTeamId == teamId; } + bool IsUnderControl() const { return _ownerTeamId != TEAM_NEUTRAL; } + bool IsUncontrolled() const { return _ownerTeamId == TEAM_NEUTRAL; } +}; + class AC_GAME_API BattlegroundEY : public Battleground { public: @@ -415,6 +434,8 @@ public: bool AllNodesConrolledByTeam(TeamId teamId) const override; TeamId GetPrematureWinner() override; + [[nodiscard]] CaptureEYPointInfo const& GetCapturePointInfo(uint32 node) const { return _capturePointInfo[node]; } + private: void PostUpdateImpl(uint32 diff) override; @@ -430,26 +451,7 @@ private: /* Scorekeeping */ void AddPoints(TeamId teamId, uint32 points); - struct CapturePointInfo - { - CapturePointInfo() : _ownerTeamId(TEAM_NEUTRAL), _barStatus(BG_EY_PROGRESS_BAR_STATE_MIDDLE), _areaTrigger(0) - { - _playersCount[TEAM_ALLIANCE] = 0; - _playersCount[TEAM_HORDE] = 0; - } - - TeamId _ownerTeamId; - int8 _barStatus; - uint32 _areaTrigger; - int8 _playersCount[PVP_TEAMS_COUNT]; - Player* player = nullptr; - - bool IsUnderControl(TeamId teamId) const { return _ownerTeamId == teamId; } - bool IsUnderControl() const { return _ownerTeamId != TEAM_NEUTRAL; } - bool IsUncontrolled() const { return _ownerTeamId == TEAM_NEUTRAL; } - }; - - CapturePointInfo _capturePointInfo[EY_POINTS_MAX]; + CaptureEYPointInfo _capturePointInfo[EY_POINTS_MAX]; EventMap _bgEvents; uint32 _honorTics; uint8 _ownedPointsCount[PVP_TEAMS_COUNT]; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h index 6a6b40188..e8ec81bf0 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h @@ -983,6 +983,9 @@ public: bool AllNodesConrolledByTeam(TeamId teamId) const override; // overwrited bool IsResourceGlutAllowed(TeamId teamId) const; void DoAction(uint32 action, ObjectGuid guid) override; + + [[nodiscard]] ICNodePoint const& GetICNodePoint(uint8 index) { return nodePoint[index]; } + private: uint32 closeFortressDoorsTimer; bool doorsClosed; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index b80f32d81..4ce30904b 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -206,7 +206,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(), m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false), - m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTarget(false), m_cannotReachTimer(0), + m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTimer(0), _isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0) { m_regenTimer = CREATURE_REGEN_INTERVAL; @@ -1299,6 +1299,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) m_spawnId = sObjectMgr->GenerateCreatureSpawnId(); CreatureData& data = sObjectMgr->NewOrExistCreatureData(m_spawnId); + data.spawnId = m_spawnId; uint32 displayId = GetNativeDisplayId(); uint32 npcflag = GetUInt32Value(UNIT_NPC_FLAGS); @@ -3420,15 +3421,19 @@ bool Creature::IsMovementPreventedByCasting() const return false; } -void Creature::SetCannotReachTarget(bool cannotReach) +bool Creature::SetCannotReachTarget(bool cannotReach, bool isChase /*= true*/) { - if (cannotReach == m_cannotReachTarget) - return; - m_cannotReachTarget = cannotReach; + if (!isChase || !Unit::SetCannotReachTarget(cannotReach)) + { + return false; + } + m_cannotReachTimer = 0; if (cannotReach) LOG_DEBUG("entities.unit", "Creature::SetCannotReachTarget() called with true. Details: {}", GetDebugInfo()); + + return true; } time_t Creature::GetLastDamagedTime() const diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 1d14b6fe5..07dc9c4a7 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -359,6 +359,7 @@ typedef std::unordered_map EquipmentInfo struct CreatureData { CreatureData() = default; + ObjectGuid::LowType spawnId{0}; uint32 id1{0}; // entry in creature_template uint32 id2{0}; // entry in creature_template uint32 id3{0}; // entry in creature_template diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index ff5b9a8f5..5fca8163a 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1009,6 +1009,7 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool // update in loaded data (changing data only in this place) GameObjectData& data = sObjectMgr->NewGOData(m_spawnId); + data.spawnId = m_spawnId; data.id = GetEntry(); data.mapid = mapid; diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index a9337760e..0ae0052bf 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -721,6 +721,7 @@ enum GOState struct GameObjectData { explicit GameObjectData() = default; + ObjectGuid::LowType spawnId{0}; uint32 id{0}; // entry in gamobject_template uint16 mapid{0}; uint32 phaseMask{0}; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 06d42758b..691fd6b69 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -12005,11 +12005,21 @@ bool Player::GetBGAccessByLevel(BattlegroundTypeId bgTypeId) const float Player::GetReputationPriceDiscount(Creature const* creature) const { - FactionTemplateEntry const* vendor_faction = creature->GetFactionTemplateEntry(); - if (!vendor_faction || !vendor_faction->faction) + FactionTemplateEntry const* vendorFaction = creature->GetFactionTemplateEntry(); + if (!vendorFaction) + { + return 1.0f; + } + + return GetReputationPriceDiscount(vendorFaction); +} + +float Player::GetReputationPriceDiscount(FactionTemplateEntry const* vendorFaction) const +{ + if (!vendorFaction->faction) return 1.0f; - ReputationRank rank = GetReputationRank(vendor_faction->faction); + ReputationRank rank = GetReputationRank(vendorFaction->faction); if (rank <= REP_NEUTRAL) return 1.0f; @@ -15935,3 +15945,9 @@ uint32 Player::GetSpellCooldownDelay(uint32 spell_id) const SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); return uint32(itr != m_spellCooldowns.end() && itr->second.end > getMSTime() ? itr->second.end - getMSTime() : 0); } + +void Player::ResetSpeakTimers() +{ + m_speakTime = 0; + m_speakCount = 0; +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 1d2b0246b..d17796ed8 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -662,7 +662,7 @@ enum PlayerSlots #define INVENTORY_SLOT_BAG_0 255 -enum EquipmentSlots // 19 slots +enum EquipmentSlots : uint32 // 19 slots { EQUIPMENT_SLOT_START = 0, EQUIPMENT_SLOT_HEAD = 0, @@ -1323,6 +1323,7 @@ public: bool _StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore); float GetReputationPriceDiscount(Creature const* creature) const; + float GetReputationPriceDiscount(FactionTemplateEntry const* vendorFaction) const; [[nodiscard]] Player* GetTrader() const { return m_trade ? m_trade->GetTrader() : nullptr; } [[nodiscard]] TradeData* GetTradeData() const { return m_trade; } @@ -2538,6 +2539,8 @@ public: [[nodiscard]] PlayerSetting GetPlayerSetting(std::string source, uint8 index); void UpdatePlayerSetting(std::string source, uint8 index, uint32 value); + void ResetSpeakTimers(); + protected: // Gamemaster whisper whitelist WhisperListContainer WhisperList; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b813e83ef..12763c5c4 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -212,6 +212,7 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject), m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefMgr(this), + m_cannotReachTarget(false), m_comboTarget(nullptr), m_comboPoints(0) { @@ -9704,15 +9705,32 @@ ReputationRank Unit::GetFactionReactionTo(FactionTemplateEntry const* factionTem } } + return GetFactionReactionTo(factionTemplateEntry, targetFactionTemplateEntry); +} + +ReputationRank Unit::GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, FactionTemplateEntry const* targetFactionTemplateEntry) +{ // common faction based check if (factionTemplateEntry->IsHostileTo(*targetFactionTemplateEntry)) + { return REP_HOSTILE; + } + if (factionTemplateEntry->IsFriendlyTo(*targetFactionTemplateEntry)) + { return REP_FRIENDLY; + } + if (targetFactionTemplateEntry->IsFriendlyTo(*factionTemplateEntry)) + { return REP_FRIENDLY; + } + if (factionTemplateEntry->factionFlags & FACTION_TEMPLATE_FLAG_HATES_ALL_EXCEPT_FRIENDS) + { return REP_HOSTILE; + } + // neutral by default return REP_NEUTRAL; } @@ -18304,11 +18322,23 @@ void Unit::SendPlaySpellVisual(uint32 id) SendMessageToSet(&data, true); } +void Unit::SendPlaySpellVisual(ObjectGuid guid, uint32 id) +{ + WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 8 + 4); + data << guid; + data << uint32(id); // SpellVisualKit.dbc index + SendMessageToSet(&data, true); +} + void Unit::SendPlaySpellImpact(ObjectGuid guid, uint32 id) { WorldPacket data(SMSG_PLAY_SPELL_IMPACT, 8 + 4); data << guid; // target data << uint32(id); // SpellVisualKit.dbc index + + if (IsPlayer()) + ToPlayer()->SendDirectMessage(&data); + else SendMessageToSet(&data, true); } @@ -20529,3 +20559,15 @@ bool Unit::CanRestoreMana(SpellInfo const* spellInfo) const return false; } + +bool Unit::SetCannotReachTarget(bool cannotReach, bool /*isChase = true*/) +{ + if (cannotReach == m_cannotReachTarget) + { + return false; + } + + m_cannotReachTarget = cannotReach; + + return true; +} diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 59c8adf04..373ac7c8d 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1442,6 +1442,7 @@ public: ReputationRank GetReactionTo(Unit const* target, bool checkOriginalFaction = false) const; ReputationRank GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, Unit const* target) const; + static ReputationRank GetFactionReactionTo(FactionTemplateEntry const* factionTemplateEntry, FactionTemplateEntry const* targetFactionTemplateEntry); bool IsHostileTo(Unit const* unit) const; [[nodiscard]] bool IsHostileToPlayers() const; @@ -1662,6 +1663,7 @@ public: Aura* AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target); void SetAuraStack(uint32 spellId, Unit* target, uint32 stack); void SendPlaySpellVisual(uint32 id); + void SendPlaySpellVisual(ObjectGuid guid, uint32 id); void SendPlaySpellImpact(ObjectGuid guid, uint32 id); void BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown); void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns); @@ -2381,6 +2383,9 @@ public: [[nodiscard]] bool CanRestoreMana(SpellInfo const* spellInfo) const; + virtual bool SetCannotReachTarget(bool cannotReach, bool isChase = true); + [[nodiscard]] bool CanNotReachTarget() const { return m_cannotReachTarget; } + protected: explicit Unit (bool isWorldObject); @@ -2463,6 +2468,8 @@ protected: bool IsAlwaysDetectableFor(WorldObject const* seer) const override; bool _instantCast; + bool m_cannotReachTarget; + private: bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo); bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index a1d142fb8..4a6e76733 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -44,7 +44,7 @@ struct MapEntry; #define MAX_RAID_SUBGROUPS MAXRAIDSIZE/MAXGROUPSIZE #define TARGETICONCOUNT 8 -enum RollVote +enum RollVote : uint32 { PASS = 0, NEED = 1, @@ -256,6 +256,8 @@ public: void SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags flag); void RemoveUniqueGroupMemberFlag(GroupMemberFlags flag); + ObjectGuid const GetTargetIcon(uint8 id) const { return m_targetIcons[id]; } + Difficulty GetDifficulty(bool isRaid) const; Difficulty GetDungeonDifficulty() const; Difficulty GetRaidDifficulty() const; @@ -294,6 +296,8 @@ public: bool CountRollVote(ObjectGuid playerGUID, ObjectGuid Guid, uint8 Choise); void EndRoll(Loot* loot, Map* allowedMap); + Rolls GetRolls() const { return RollId; } + // related to disenchant rolls void ResetMaxEnchantingLevel(); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 39a156606..4550509f9 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -830,7 +830,7 @@ bool Guild::BankMoveItemData::HasStoreRights(MoveItemData* pOther) const // Do not check rights if item is being swapped within the same bank tab if (pOther->IsBank() && pOther->GetContainer() == m_container) return true; - return m_pGuild->_MemberHasTabRights(m_pPlayer->GetGUID(), m_container, GUILD_BANK_RIGHT_DEPOSIT_ITEM); + return m_pGuild->MemberHasTabRights(m_pPlayer->GetGUID(), m_container, GUILD_BANK_RIGHT_DEPOSIT_ITEM); } bool Guild::BankMoveItemData::HasWithdrawRights(MoveItemData* pOther) const @@ -1214,7 +1214,7 @@ void Guild::HandleRoster(WorldSession* session) } } - bool sendOfficerNote = _HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE); + bool sendOfficerNote = HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE); for (auto const& [guid, member] : m_members) { WorldPackets::Guild::GuildRosterMemberData& memberData = roster.MemberData.emplace_back(); @@ -1270,7 +1270,7 @@ void Guild::HandleSetMOTD(WorldSession* session, std::string_view motd) return; // Player must have rights to set MOTD - if (!_HasRankRight(session->GetPlayer(), GR_RIGHT_SETMOTD)) + if (!HasRankRight(session->GetPlayer(), GR_RIGHT_SETMOTD)) SendCommandResult(session, GUILD_COMMAND_EDIT_MOTD, ERR_GUILD_PERMISSIONS); else { @@ -1293,7 +1293,7 @@ void Guild::HandleSetInfo(WorldSession* session, std::string_view info) return; // Player must have rights to set guild's info - if (_HasRankRight(session->GetPlayer(), GR_RIGHT_MODIFY_GUILD_INFO)) + if (HasRankRight(session->GetPlayer(), GR_RIGHT_MODIFY_GUILD_INFO)) { m_info = info; @@ -1326,6 +1326,12 @@ void Guild::HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo) } } +void Guild::HandleSetEmblem(EmblemInfo const& emblemInfo) +{ + m_emblemInfo = emblemInfo; + m_emblemInfo.SaveToDB(m_id); +} + void Guild::HandleSetLeader(WorldSession* session, std::string_view name) { Player* player = session->GetPlayer(); @@ -1362,7 +1368,7 @@ void Guild::HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string void Guild::HandleSetMemberNote(WorldSession* session, std::string_view name, std::string_view note, bool isPublic) { // Player must have rights to set public/officer note - if (!_HasRankRight(session->GetPlayer(), isPublic ? GR_RIGHT_EPNOTE : GR_RIGHT_EOFFNOTE)) + if (!HasRankRight(session->GetPlayer(), isPublic ? GR_RIGHT_EPNOTE : GR_RIGHT_EOFFNOTE)) SendCommandResult(session, GUILD_COMMAND_PUBLIC_NOTE, ERR_GUILD_PERMISSIONS); else if (Member* member = GetMember(name)) { @@ -1395,6 +1401,29 @@ void Guild::HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string_v } } +void Guild::HandleSetRankInfo(uint8 rankId, uint32 rights, std::string_view name, uint32 moneyPerDay) +{ + if (RankInfo* rankInfo = GetRankInfo(rankId)) + { + if (!name.empty()) + { + rankInfo->SetName(name); + } + + if (rights > 0) + { + rankInfo->SetRights(rights); + } + + if (moneyPerDay > 0) + { + _SetRankBankMoneyPerDay(rankId, moneyPerDay); + } + + _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(rankId), rankInfo->GetName(), std::to_string(m_ranks.size())); + } +} + void Guild::HandleBuyBankTab(WorldSession* session, uint8 tabId) { Player* player = session->GetPlayer(); @@ -1457,7 +1486,7 @@ void Guild::HandleInviteMember(WorldSession* session, std::string const& name) return; } // Inviting player must have rights to invite - if (!_HasRankRight(player, GR_RIGHT_INVITE)) + if (!HasRankRight(player, GR_RIGHT_INVITE)) { SendCommandResult(session, GUILD_COMMAND_INVITE, ERR_GUILD_PERMISSIONS); return; @@ -1528,7 +1557,7 @@ void Guild::HandleRemoveMember(WorldSession* session, std::string_view name) { Player* player = session->GetPlayer(); // Player must have rights to remove members - if (!_HasRankRight(player, GR_RIGHT_REMOVE)) + if (!HasRankRight(player, GR_RIGHT_REMOVE)) SendCommandResult(session, GUILD_COMMAND_REMOVE, ERR_GUILD_PERMISSIONS); else if (Member* member = GetMember(name)) { @@ -1558,7 +1587,7 @@ void Guild::HandleUpdateMemberRank(WorldSession* session, std::string_view name, Player* player = session->GetPlayer(); GuildCommandType type = demote ? GUILD_COMMAND_DEMOTE : GUILD_COMMAND_PROMOTE; // Player must have rights to promote - if (!_HasRankRight(player, demote ? GR_RIGHT_DEMOTE : GR_RIGHT_PROMOTE)) + if (!HasRankRight(player, demote ? GR_RIGHT_DEMOTE : GR_RIGHT_PROMOTE)) SendCommandResult(session, type, ERR_GUILD_PERMISSIONS); // Promoted player must be a member of guild else if (Member* member = GetMember(name)) @@ -1820,7 +1849,7 @@ void Guild::SendPermissions(WorldSession* session) const WorldPackets::Guild::GuildPermissionsQueryResults queryResult; queryResult.RankID = rankId; queryResult.WithdrawGoldLimit = _GetRankBankMoneyPerDay(rankId); - queryResult.Flags = _GetRankRights(rankId); + queryResult.Flags = GetRankRights(rankId); queryResult.NumTabs = _GetPurchasedTabsSize(); for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) @@ -2088,13 +2117,13 @@ bool Guild::Validate() // Broadcasts void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::string_view msg, uint32 language) const { - if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) + if (session && session->GetPlayer() && HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { WorldPacket data; ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg); for (auto const& [guid, member] : m_members) if (Player* player = member.FindPlayer()) - if (_HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID())) + if (HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID())) player->GetSession()->SendPacket(&data); } } @@ -2497,7 +2526,7 @@ inline std::string Guild::_GetRankName(uint8 rankId) const return ""; } -inline uint32 Guild::_GetRankRights(uint8 rankId) const +uint32 Guild::GetRankRights(uint8 rankId) const { if (const RankInfo* rankInfo = GetRankInfo(rankId)) return rankInfo->GetRights(); @@ -2546,7 +2575,7 @@ inline int32 Guild::_GetMemberRemainingMoney(Member const& member) const if (rankId == GR_GUILDMASTER) return static_cast(GUILD_WITHDRAW_MONEY_UNLIMITED); - if ((_GetRankRights(rankId) & (GR_RIGHT_WITHDRAW_REPAIR | GR_RIGHT_WITHDRAW_GOLD)) != 0) + if ((GetRankRights(rankId) & (GR_RIGHT_WITHDRAW_REPAIR | GR_RIGHT_WITHDRAW_GOLD)) != 0) { int32 remaining = _GetRankBankMoneyPerDay(rankId) - member.GetBankWithdrawValue(GUILD_BANK_MAX_TABS); if (remaining > 0) @@ -2566,7 +2595,7 @@ inline void Guild::_UpdateMemberWithdrawSlots(CharacterDatabaseTransaction trans } } -inline bool Guild::_MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const +bool Guild::MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const { if (const Member* member = GetMember(guid)) { @@ -2578,6 +2607,19 @@ inline bool Guild::_MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 righ return false; } +bool Guild::HasRankRight(Player* player, uint32 right) const +{ + if (player) + { + if (Member const* member = GetMember(player->GetGUID())) + { + return (GetRankRights(member->GetRankId()) & right) != GR_RIGHT_EMPTY; + } + } + + return false; +} + // Add new event log record inline void Guild::_LogEvent(GuildEventLogTypes eventType, ObjectGuid playerGuid1, ObjectGuid playerGuid2, uint8 newRank) { @@ -2723,7 +2765,7 @@ bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError void Guild::_SendBankContent(WorldSession* session, uint8 tabId, bool sendAllSlots) const { ObjectGuid guid = session->GetPlayer()->GetGUID(); - if (!_MemberHasTabRights(guid, tabId, GUILD_BANK_RIGHT_VIEW_TAB)) + if (!MemberHasTabRights(guid, tabId, GUILD_BANK_RIGHT_VIEW_TAB)) return; _SendBankList(session, tabId, sendAllSlots); @@ -2883,7 +2925,7 @@ void Guild::_SendBankList(WorldSession* session /* = nullptr*/, uint8 tabId /*= packet.Write(); for (auto const& [guid, member] : m_members) { - if (!_MemberHasTabRights(member.GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) + if (!MemberHasTabRights(member.GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) continue; Player* player = member.FindPlayer(); if (!player) diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index df5c288e0..42bfeb4cf 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -241,7 +241,8 @@ enum GuildMemberFlags class EmblemInfo { public: - EmblemInfo() : m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { } + EmblemInfo(uint32 style = 0, uint32 color = 0, uint32 borderStyle = 0, uint32 borderColor = 0, uint32 backgroundColor = 0) : + m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { } void LoadFromDB(Field* fields); void SaveToDB(uint32 guildId) const; @@ -692,11 +693,13 @@ public: void HandleQuery(WorldSession* session); void HandleSetMOTD(WorldSession* session, std::string_view motd); void HandleSetInfo(WorldSession* session, std::string_view info); - void HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo); + void HandleSetEmblem(WorldSession* session, EmblemInfo const& emblemInfo); + void HandleSetEmblem(EmblemInfo const& emblemInfo); void HandleSetLeader(WorldSession* session, std::string_view name); void HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string_view name, std::string_view icon); void HandleSetMemberNote(WorldSession* session, std::string_view name, std::string_view note, bool officer); void HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string_view name, uint32 rights, uint32 moneyPerDay, std::array const& rightsAndSlots); + void HandleSetRankInfo(uint8 rankId, uint32 rights = 0, std::string_view name = "", uint32 moneyPerDay = 0); void HandleBuyBankTab(WorldSession* session, uint8 tabId); void HandleInviteMember(WorldSession* session, std::string const& name); void HandleAcceptMember(WorldSession* session); @@ -775,6 +778,10 @@ public: [[nodiscard]] bool ModifyBankMoney(CharacterDatabaseTransaction trans, const uint64& amount, bool add) { return _ModifyBankMoney(trans, amount, add); } [[nodiscard]] uint32 GetMemberSize() const { return m_members.size(); } + bool MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const; + bool HasRankRight(Player* player, uint32 right) const; + uint32 GetRankRights(uint8 rankId) const; + protected: uint32 m_id; std::string m_name; @@ -799,13 +806,6 @@ private: inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } inline const RankInfo* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } inline RankInfo* GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } - inline bool _HasRankRight(Player* player, uint32 right) const - { - if (player) - if (Member const* member = GetMember(player->GetGUID())) - return (_GetRankRights(member->GetRankId()) & right) != GR_RIGHT_EMPTY; - return false; - } inline uint8 _GetLowestRankId() const { return uint8(m_ranks.size() - 1); } @@ -836,7 +836,6 @@ private: void _SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay); void _SetRankBankTabRightsAndSlots(uint8 rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB = true); int8 _GetRankBankTabRights(uint8 rankId, uint8 tabId) const; - uint32 _GetRankRights(uint8 rankId) const; int32 _GetRankBankMoneyPerDay(uint8 rankId) const; int32 _GetRankBankTabSlotsPerDay(uint8 rankId, uint8 tabId) const; std::string _GetRankName(uint8 rankId) const; @@ -844,7 +843,6 @@ private: int32 _GetMemberRemainingSlots(Member const& member, uint8 tabId) const; int32 _GetMemberRemainingMoney(Member const& member) const; void _UpdateMemberWithdrawSlots(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 tabId); - bool _MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const; void _LogEvent(GuildEventLogTypes eventType, ObjectGuid playerGuid1, ObjectGuid playerGuid2 = ObjectGuid::Empty, uint8 newRank = 0); void _LogBankEvent(CharacterDatabaseTransaction trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid playerGuid, uint32 itemOrMoney, uint16 itemStackCount = 0, uint8 destTabId = 0); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index abd1f2b67..93cd26d7f 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -58,19 +58,9 @@ #include "WorldPacket.h" #include "WorldSession.h" -class LoginQueryHolder : public CharacterDatabaseQueryHolder +LoginQueryHolder::LoginQueryHolder(uint32 accountId, ObjectGuid guid) : m_accountId(accountId), m_guid(guid) { -private: - uint32 m_accountId; - ObjectGuid m_guid; -public: - LoginQueryHolder(uint32 accountId, ObjectGuid guid) - : m_accountId(accountId), m_guid(guid) { } - - ObjectGuid GetGuid() const { return m_guid; } - uint32 GetAccountId() const { return m_accountId; } - bool Initialize(); -}; +} bool LoginQueryHolder::Initialize() { @@ -561,7 +551,12 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) newChar->SaveToDB(characterTransaction, true, false); createInfo->CharCount++; - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_REALM_CHARACTERS); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); + stmt->SetData(0, GetAccountId()); + stmt->SetData(1, realm.Id.Realm); + trans->Append(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_REP_REALM_CHARACTERS); stmt->SetData(0, createInfo->CharCount); stmt->SetData(1, GetAccountId()); stmt->SetData(2, realm.Id.Realm); @@ -897,8 +892,7 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder) CharacterDatabase.Execute(stmt); LoginDatabasePreparedStatement* loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE); - loginStmt->SetData(0, realm.Id.Realm); - loginStmt->SetData(1, GetAccountId()); + loginStmt->SetData(0, GetAccountId()); LoginDatabase.Execute(loginStmt); pCurrChar->SetInGameTime(GameTime::GetGameTimeMS().count()); diff --git a/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp b/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp index b4debdf2f..c3f92c583 100644 --- a/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/DatabaseScript.cpp @@ -18,6 +18,21 @@ #include "ScriptMgr.h" #include "ScriptMgrMacros.h" +bool ScriptMgr::OnDatabasesLoading() +{ + auto ret = IsValidBoolScript([&](DatabaseScript* script) + { + return !script->OnDatabasesLoading(); + }); + + if (ret && *ret) + { + return false; + } + + return true; +} + void ScriptMgr::OnAfterDatabasesLoaded(uint32 updateFlags) { ExecuteScript([&](DatabaseScript* script) @@ -25,3 +40,43 @@ void ScriptMgr::OnAfterDatabasesLoaded(uint32 updateFlags) script->OnAfterDatabasesLoaded(updateFlags); }); } + +void ScriptMgr::OnDatabasesKeepAlive() +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabasesKeepAlive(); + }); +} + +void ScriptMgr::OnDatabasesClosing() +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabasesClosing(); + }); +} + +void ScriptMgr::OnDatabaseWarnAboutSyncQueries(bool apply) +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabaseWarnAboutSyncQueries(apply); + }); +} + +void ScriptMgr::OnDatabaseSelectIndexLogout(Player* player, uint32& statementIndex, uint32& statementParam) +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabaseSelectIndexLogout(player, statementIndex, statementParam); + }); +} + +void ScriptMgr::OnDatabaseGetDBRevision(std::string& revision) +{ + ExecuteScript([&](DatabaseScript* script) + { + script->OnDatabaseGetDBRevision(revision); + }); +} diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp index 959fc2b35..867a278e4 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp @@ -305,6 +305,14 @@ void ScriptMgr::OnPlayerUpdate(Player* player, uint32 p_time) }); } +void ScriptMgr::OnAfterPlayerUpdate(Player* player, uint32 diff) +{ + ExecuteScript([&](PlayerScript* script) + { + script->OnAfterUpdate(player, diff); + }); +} + void ScriptMgr::OnPlayerLogin(Player* player) { ExecuteScript([&](PlayerScript* script) diff --git a/src/server/game/Scripting/ScriptDefines/ServerScript.cpp b/src/server/game/Scripting/ScriptDefines/ServerScript.cpp index ca8f7cf67..9e10e12c3 100644 --- a/src/server/game/Scripting/ScriptDefines/ServerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/ServerScript.cpp @@ -74,6 +74,15 @@ bool ScriptMgr::CanPacketReceive(WorldSession* session, WorldPacket const& packe return true; } +void ScriptMgr::OnPacketReceived(WorldSession* session, WorldPacket const& packet) +{ + WorldPacket copy(packet); + ExecuteScript([&](ServerScript* script) + { + script->OnPacketReceived(session, copy); + }); +} + bool ScriptMgr::CanPacketSend(WorldSession* session, WorldPacket const& packet) { ASSERT(session); diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index 04c18ab62..f5f2b0255 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -597,6 +597,7 @@ public: [[nodiscard]] virtual std::string const& GetRealmName() const = 0; virtual void SetRealmName(std::string name) = 0; virtual void RemoveOldCorpses() = 0; + virtual SQLQueryHolderCallback& AddQueryHolderCallback(SQLQueryHolderCallback&& callback) = 0; }; #endif //AZEROTHCORE_IWORLD_H diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 5f091c9d1..c58dc2882 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -66,6 +66,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "OutdoorPvPMgr.h" +#include "QueryHolder.h" #include "PetitionMgr.h" #include "Player.h" #include "PlayerDump.h" @@ -2459,6 +2460,7 @@ void World::Update(uint32 diff) CharacterDatabase.KeepAlive(); LoginDatabase.KeepAlive(); WorldDatabase.KeepAlive(); + sScriptMgr->OnDatabasesKeepAlive(); } { @@ -3302,6 +3304,8 @@ void World::LoadDBRevision() { m_AuthDBRevision = "Unkown Auth Database Revision"; } + + sScriptMgr->OnDatabaseGetDBRevision(m_PlayerbotsDBRevision); } void World::UpdateAreaDependentAuras() @@ -3369,6 +3373,12 @@ uint64 World::getWorldState(uint32 index) const void World::ProcessQueryCallbacks() { _queryProcessor.ProcessReadyCallbacks(); + _queryHolderProcessor.ProcessReadyCallbacks(); +} + +SQLQueryHolderCallback& World::AddQueryHolderCallback(SQLQueryHolderCallback&& callback) +{ + return _queryHolderProcessor.AddCallback(std::move(callback)); } void World::RemoveOldCorpses() diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 4ec0f7ded..d74df174e 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -377,6 +377,9 @@ protected: void ResetRandomBG(); void CalendarDeleteOldEvents(); void ResetGuildCap(); + + SQLQueryHolderCallback& AddQueryHolderCallback(SQLQueryHolderCallback&& callback) override; + private: static std::atomic_long m_stopEvent; static uint8 m_ExitCode; @@ -457,6 +460,7 @@ private: void ProcessQueryCallbacks(); QueryCallbackProcessor _queryProcessor; + AsyncCallbackProcessor _queryHolderProcessor; /** * @brief Executed when a World Session is being finalized. Be it from a normal login or via queue popping. diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index e34b16183..d3090818e 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -224,6 +224,7 @@ public: { ObjectGuid::LowType guid = sObjectMgr->GenerateCreatureSpawnId(); CreatureData& data = sObjectMgr->NewOrExistCreatureData(guid); + data.spawnId = guid; data.id1 = id; data.phaseMask = chr->GetPhaseMaskForSpawn(); data.posX = chr->GetTransOffsetX();