Compare commits

...

8 Commits

Author SHA1 Message Date
Kitzunu
b6a4087afb
Merge 591b5fc61f9c00230c5f5fd4c3a73b409f4ea94e into 9f99e89bc325c1a102a042eb07ccfdeb49625048 2025-02-24 13:50:51 -06:00
SaW
9f99e89bc3
fix(Core/Threading): Refactored Map class - some code optimization (#21288) 2025-02-24 15:49:54 -03:00
vrachv
b83071388c
fix(Scripts/SunwellPlateau) Fix flame touched stacking (#21594) 2025-02-24 11:49:33 -03:00
Andrew
f234f034a1
fix(Scripts/SunwellPlateau): Fix twins respawn (#21598) 2025-02-24 11:48:44 -03:00
sudlud
591b5fc61f
Merge branch 'master' into mail_server_template_items 2025-02-24 06:27:30 +01:00
Kitzunu
2ed3a480b7 add check for no item count 2025-02-23 14:13:56 +01:00
Kitzunu
cc5950f068 fix sql error 2025-02-23 14:03:16 +01:00
Kitzunu
38149673de refactor(Core/Mail): Allow ServerMail to send multiple items
* Allow ServerMail to send multiple items by introducing new DB table mail_server_template_items

* Merge existing entries from mail_server_template to mail_server_template_items before dropping columns

* Add foreign keys to mail_server_character.mailId and mail_server_template_items.templateID to remove entries if the parent mail_server_template.id is removed

* Clean up and add early return for ObjectMgr::SendServerMail

* closes https://github.com/azerothcore/azerothcore-wotlk/issues/11446
2025-02-23 13:54:43 +01:00
7 changed files with 217 additions and 138 deletions

View File

@ -0,0 +1,36 @@
--
DROP TABLE IF EXISTS `mail_server_template_items`;
CREATE TABLE `mail_server_template_items` (
`id` INT UNSIGNED AUTO_INCREMENT,
`templateID` INT UNSIGNED NOT NULL,
`faction` ENUM('Alliance', 'Horde') NOT NULL,
`item` INT UNSIGNED NOT NULL,
`itemCount` INT UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_mail_template`
FOREIGN KEY (`templateID`) REFERENCES `mail_server_template`(`id`)
ON DELETE CASCADE
) ENGINE=InnoDB COLLATE='utf8mb4_unicode_ci';
INSERT INTO `mail_server_template_items` (`templateID`, `faction`, `item`, `itemCount`)
SELECT `id`, 'Alliance', `itemA`, `itemCountA` FROM `mail_server_template` WHERE `itemA` > 0;
INSERT INTO `mail_server_template_items` (`templateID`, `faction`, `item`, `itemCount`)
SELECT `id`, 'Horde', `itemH`, `itemCountH` FROM `mail_server_template` WHERE `itemH` > 0;
ALTER TABLE `mail_server_template`
DROP COLUMN `itemA`,
DROP COLUMN `itemCountA`,
DROP COLUMN `itemH`,
DROP COLUMN `itemCountH`;
-- Make sure we dont have invalid instances in mail_server_character.mailId before we add the foregin key to avoid SQL errors
DELETE FROM `mail_server_character` WHERE `mailId` NOT IN (SELECT `id` FROM `mail_server_template`);
-- Add foreign key for mail_server_character.mailId
ALTER TABLE `mail_server_character`
DROP PRIMARY KEY,
ADD PRIMARY KEY (`guid`, `mailId`),
ADD CONSTRAINT `fk_mail_template_character`
FOREIGN KEY (`mailId`) REFERENCES `mail_server_template`(`id`)
ON DELETE CASCADE;

View File

@ -10298,38 +10298,45 @@ uint32 ObjectMgr::GetQuestMoneyReward(uint8 level, uint32 questMoneyDifficulty)
return 0;
}
void ObjectMgr::SendServerMail(Player* player, uint32 id, uint32 reqLevel, uint32 reqPlayTime, uint32 rewardMoneyA, uint32 rewardMoneyH, uint32 rewardItemA, uint32 rewardItemCountA, uint32 rewardItemH, uint32 rewardItemCountH, std::string subject, std::string body, uint8 active) const
void ObjectMgr::SendServerMail(Player* player, uint32 id, uint32 reqLevel, uint32 reqPlayTime, uint32 rewardMoneyA, uint32 rewardMoneyH, std::vector<ServerMailItems> const& items, std::string subject, std::string body, uint8 active) const
{
if (active)
if (!active)
return;
if (player->GetLevel() < reqLevel)
return;
if (player->GetTotalPlayedTime() < reqPlayTime)
return;
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
MailSender sender(MAIL_NORMAL, player->GetGUID().GetCounter(), MAIL_STATIONERY_GM);
MailDraft draft(subject, body);
draft.AddMoney(player->GetTeamId() == TEAM_ALLIANCE ? rewardMoneyA : rewardMoneyH);
// Loop through all items and attach them to the mail
for (auto const& mailItem : items)
{
if (player->GetLevel() < reqLevel)
return;
if (!mailItem.item || !mailItem.itemCount)
continue;
if (player->GetTotalPlayedTime() < reqPlayTime)
return;
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
MailSender sender(MAIL_NORMAL, player->GetGUID().GetCounter(), MAIL_STATIONERY_GM);
MailDraft draft(subject, body);
draft.AddMoney(player->GetTeamId() == TEAM_ALLIANCE ? rewardMoneyA : rewardMoneyH);
if (Item* mailItem = Item::CreateItem(player->GetTeamId() == TEAM_ALLIANCE ? rewardItemA : rewardItemH, player->GetTeamId() == TEAM_ALLIANCE ? rewardItemCountA : rewardItemCountH))
if (Item* newItem = Item::CreateItem(mailItem.item, mailItem.itemCount))
{
mailItem->SaveToDB(trans);
draft.AddItem(mailItem);
newItem->SaveToDB(trans);
draft.AddItem(newItem);
}
draft.SendMailTo(trans, MailReceiver(player), sender);
CharacterDatabase.CommitTransaction(trans);
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_MAIL_SERVER_CHARACTER);
stmt->SetData(0, player->GetGUID().GetCounter());
stmt->SetData(1, id);
CharacterDatabase.Execute(stmt);
LOG_DEBUG("entities.player", "ObjectMgr::SendServerMail() Sent mail id {} to {}", id, player->GetGUID().ToString());
}
draft.SendMailTo(trans, MailReceiver(player), sender);
CharacterDatabase.CommitTransaction(trans);
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_MAIL_SERVER_CHARACTER);
stmt->SetData(0, player->GetGUID().GetCounter());
stmt->SetData(1, id);
CharacterDatabase.Execute(stmt);
LOG_DEBUG("entities.player", "ObjectMgr::SendServerMail() Sent mail id {} to {}", id, player->GetGUID().ToString());
}
void ObjectMgr::LoadMailServerTemplates()
@ -10338,8 +10345,8 @@ void ObjectMgr::LoadMailServerTemplates()
_serverMailStore.clear(); // for reload case
// 0 1 2 3 4 5 6 7 8 9 10 11
QueryResult result = CharacterDatabase.Query("SELECT `id`, `reqLevel`, `reqPlayTime`, `moneyA`, `moneyH`, `itemA`, `itemCountA`, `itemH`,`itemCountH`, `subject`, `body`, `active` FROM `mail_server_template`");
// 0 1 2 3 4 5 6 7
QueryResult result = CharacterDatabase.Query("SELECT `id`, `reqLevel`, `reqPlayTime`, `moneyA`, `moneyH`, `subject`, `body`, `active` FROM `mail_server_template`");
if (!result)
{
LOG_INFO("sql.sql", ">> Loaded 0 server mail rewards. DB table `mail_server_template` is empty.");
@ -10362,13 +10369,9 @@ void ObjectMgr::LoadMailServerTemplates()
servMail.reqPlayTime = fields[2].Get<uint32>();
servMail.moneyA = fields[3].Get<uint32>();
servMail.moneyH = fields[4].Get<uint32>();
servMail.itemA = fields[5].Get<uint32>();
servMail.itemCountA = fields[6].Get<uint32>();
servMail.itemH = fields[7].Get<uint32>();
servMail.itemCountH = fields[8].Get<uint32>();
servMail.subject = fields[9].Get<std::string>();
servMail.body = fields[10].Get<std::string>();
servMail.active = fields[11].Get<uint8>();
servMail.subject = fields[5].Get<std::string>();
servMail.body = fields[6].Get<std::string>();
servMail.active = fields[7].Get<uint8>();
if (servMail.reqLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
{
@ -10381,32 +10384,79 @@ void ObjectMgr::LoadMailServerTemplates()
LOG_ERROR("sql.sql", "Table `mail_server_template` has moneyA {} or moneyH {} larger than MAX_MONEY_AMOUNT {} for id {}, skipped.", servMail.moneyA, servMail.moneyH, MAX_MONEY_AMOUNT, servMail.id);
return;
}
ItemTemplate const* itemTemplateA = sObjectMgr->GetItemTemplate(servMail.itemA);
if (!itemTemplateA && servMail.itemA)
{
LOG_ERROR("sql.sql", "Table `mail_server_template` has invalid item in itemA {} for id {}, skipped.", servMail.itemA, servMail.id);
return;
}
ItemTemplate const* itemTemplateH = sObjectMgr->GetItemTemplate(servMail.itemH);
if (!itemTemplateH && servMail.itemH)
{
LOG_ERROR("sql.sql", "Table `mail_server_template` has invalid item in itemH {} for id {}, skipped.", servMail.itemH, servMail.id);
return;
}
if (!servMail.itemA && servMail.itemCountA)
{
LOG_ERROR("sql.sql", "Table `mail_server_template` has itemCountA {} with no ItemA, set to 0", servMail.itemCountA);
servMail.itemCountA = 0;
}
if (!servMail.itemH && servMail.itemCountH)
{
LOG_ERROR("sql.sql", "Table `mail_server_template` has itemCountH {} with no ItemH, set to 0", servMail.itemCountH);
servMail.itemCountH = 0;
}
} while (result->NextRow());
LoadMailServerTemplatesItems();
LOG_INFO("server.loading", ">> Loaded {} Mail Server Template in {} ms", _serverMailStore.size(), GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
void ObjectMgr::LoadMailServerTemplatesItems()
{
QueryResult result = CharacterDatabase.Query("SELECT `templateID`, `faction`, `item`, `itemCount` FROM `mail_server_template_items`");
if (!result)
{
LOG_INFO("sql.sql", ">> Loaded 0 server mail items. DB table `mail_server_template_items` is empty.");
LOG_INFO("server.loading", " ");
return;
}
do
{
Field* fields = result->Fetch();
uint32 templateID = fields[0].Get<uint32>();
std::string faction = fields[1].Get<std::string>();
uint32 item = fields[2].Get<uint32>();
uint32 itemCount = fields[3].Get<uint32>();
if (_serverMailStore.find(templateID) == _serverMailStore.end())
{
LOG_ERROR("sql.sql", "Table `mail_server_template_items` has an invalid templateID {}, skipped.", templateID);
continue;
}
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item);
if (!itemTemplate)
{
LOG_ERROR("sql.sql", "Table `mail_server_template_items` has an invalid item {} for templateID {}, skipped.", item, templateID);
continue;
}
if (!itemCount)
{
LOG_ERROR("sql.sql", "Table `mail_server_template_items` has itemCount 0 for item {}, skipped.", item);
continue;
}
uint32 stackable = itemTemplate->Stackable;
if (itemCount > stackable)
{
LOG_ERROR("sql.sql", "Table `mail_server_template_items` has itemCount {} exceeding item_template.Stackable {} for item {}, skipped.", itemCount, stackable, item);
continue;
}
uint32 maxCount = itemTemplate->MaxCount;
if (maxCount && itemCount > maxCount)
{
LOG_ERROR("sql.sql", "Table `mail_server_template_items` has itemCount {} exceeding item_template.MaxCount {} for item {}, skipped", itemCount, maxCount, item);
continue;
}
ServerMailItems mailItem;
mailItem.item = item;
mailItem.itemCount = itemCount;
if (faction == "Alliance")
_serverMailStore[templateID].itemsA.push_back(mailItem);
else if (faction == "Horde")
_serverMailStore[templateID].itemsH.push_back(mailItem);
else
{
LOG_ERROR("sql.sql", "Table `mail_server_template_items` has invalid faction value '{}' for id {}, skipped.", faction, templateID);
continue;
}
} while (result->NextRow());
}

View File

@ -1056,6 +1056,7 @@ public:
void LoadInstanceEncounters();
void LoadMailLevelRewards();
void LoadMailServerTemplates();
void LoadMailServerTemplatesItems();
void LoadVehicleTemplateAccessories();
void LoadVehicleAccessories();
void LoadVehicleSeatAddon();
@ -1449,7 +1450,7 @@ public:
}
[[nodiscard]] uint32 GetQuestMoneyReward(uint8 level, uint32 questMoneyDifficulty) const;
void SendServerMail(Player* player, uint32 id, uint32 reqLevel, uint32 reqPlayTime, uint32 rewardMoneyA, uint32 rewardMoneyH, uint32 rewardItemA, uint32 rewardItemCountA, uint32 rewardItemH, uint32 rewardItemCountH, std::string subject, std::string body, uint8 active) const;
void SendServerMail(Player* player, uint32 id, uint32 reqLevel, uint32 reqPlayTime, uint32 rewardMoneyA, uint32 rewardMoneyH, std::vector<ServerMailItems> const& items, std::string subject, std::string body, uint8 active) const;
private:
// first free id for selected id type
uint32 _auctionId; // pussywizard: accessed by a single thread

View File

@ -210,6 +210,13 @@ struct Mail
[[nodiscard]] bool IsReturnedMail() const { return checked & MAIL_CHECK_MASK_RETURNED; }
};
struct ServerMailItems
{
ServerMailItems() = default;
uint32 item{ 0 };
uint32 itemCount{ 0 };
};
struct ServerMail
{
ServerMail() = default;
@ -218,13 +225,13 @@ struct ServerMail
uint32 reqPlayTime{ 0 };
uint32 moneyA{ 0 };
uint32 moneyH{ 0 };
uint32 itemA{ 0 };
uint32 itemCountA{ 0 };
uint32 itemH{ 0 };
uint32 itemCountH{ 0 };
std::string subject;
std::string body;
uint8 active{ 0 };
// Items from mail_server_template_items
std::vector<ServerMailItems> itemsA;
std::vector<ServerMailItems> itemsH;
};
#endif

View File

@ -588,16 +588,20 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
if (t_diff)
_dynamicTree.update(t_diff);
/// update worldsessions for existing players
// Update world sessions and players
for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter)
{
Player* player = m_mapRefIter->GetSource();
if (player && player->IsInWorld())
{
//player->Update(t_diff);
// Update session
WorldSession* session = player->GetSession();
MapSessionFilter updater(session);
session->Update(s_diff, updater);
// update players at tick
if (!t_diff)
player->Update(s_diff);
}
}
@ -605,17 +609,6 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
if (!t_diff)
{
for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter)
{
Player* player = m_mapRefIter->GetSource();
if (!player || !player->IsInWorld())
continue;
// update players at tick
player->Update(s_diff);
}
HandleDelayedVisibility();
return;
}
@ -624,36 +617,35 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
resetMarkedCells();
resetMarkedCellsLarge();
// Prepare object updaters
Acore::ObjectUpdater updater(t_diff, false);
// for creature
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer > grid_object_update(updater);
// for pets
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer > world_object_update(updater);
// For creature
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer> grid_object_update(updater);
// for large creatures
// For pets
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer> world_object_update(updater);
// For large creatures
Acore::ObjectUpdater largeObjectUpdater(t_diff, true);
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer > grid_large_object_update(largeObjectUpdater);
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer > world_large_object_update(largeObjectUpdater);
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer> grid_large_object_update(largeObjectUpdater);
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer> world_large_object_update(largeObjectUpdater);
// pussywizard: container for far creatures in combat with players
std::vector<Creature*> updateList;
updateList.reserve(10);
// non-player active objects, increasing iterator in the loop in case of object removal
// Update non-player active objects
for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();)
{
WorldObject* obj = *m_activeNonPlayersIter;
++m_activeNonPlayersIter;
if (!obj || !obj->IsInWorld())
continue;
VisitNearbyCellsOf(obj, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
if (obj && obj->IsInWorld())
VisitNearbyCellsOf(obj, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
}
// the player iterator is stored in the map object
// to make sure calls to Map::Remove don't invalidate it
// Update players and their associated objects
for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter)
{
Player* player = m_mapRefIter->GetSource();
@ -661,12 +653,10 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
if (!player || !player->IsInWorld())
continue;
// update players at tick
player->Update(s_diff);
VisitNearbyCellsOfPlayer(player, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
// If player is using far sight, visit that object too
// If player is using far sight, update viewpoint
if (WorldObject* viewPoint = player->GetViewpoint())
{
if (Creature* viewCreature = viewPoint->ToCreature())
@ -684,7 +674,8 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
{
updateList.clear();
float rangeSq = player->GetGridActivationRange() - 1.0f;
rangeSq = rangeSq * rangeSq;
rangeSq *= rangeSq;
HostileReference* ref = player->getHostileRefMgr().getFirst();
while (ref)
{
@ -694,20 +685,20 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
updateList.push_back(cre);
ref = ref->next();
}
for (std::vector<Creature*>::const_iterator itr = updateList.begin(); itr != updateList.end(); ++itr)
VisitNearbyCellsOf(*itr, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
for (Creature* cre : updateList)
VisitNearbyCellsOf(cre, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
}
}
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();) // pussywizard: transports updated after VisitNearbyCellsOf, grids around are loaded, everything ok
// Update transports - pussywizard: transports updated after VisitNearbyCellsOf, grids around are loaded, everything ok
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
{
MotionTransport* transport = *_transportsUpdateIter;
++_transportsUpdateIter;
if (!transport->IsInWorld())
continue;
transport->Update(t_diff);
if (transport->IsInWorld())
transport->Update(t_diff);
}
SendObjectUpdates();
@ -1674,14 +1665,16 @@ bool Map::IsUnderWater(uint32 phaseMask, float x, float y, float z, float collis
bool Map::HasEnoughWater(WorldObject const* searcher, float x, float y, float z) const
{
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(searcher->GetPhaseMask(), x, y, z, searcher->GetCollisionHeight(), MAP_ALL_LIQUIDS);
return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0 && HasEnoughWater(searcher, liquidData);
}
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(
searcher->GetPhaseMask(), x, y, z, searcher->GetCollisionHeight(), MAP_ALL_LIQUIDS);
if ((liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) == 0)
return false;
bool Map::HasEnoughWater(WorldObject const* searcher, LiquidData const& liquidData) const
{
float minHeightInWater = searcher->GetMinHeightInWater();
return liquidData.Level > INVALID_HEIGHT && liquidData.Level > liquidData.DepthLevel && liquidData.Level - liquidData.DepthLevel >= minHeightInWater;
return liquidData.Level > INVALID_HEIGHT &&
liquidData.Level > liquidData.DepthLevel &&
liquidData.Level - liquidData.DepthLevel >= minHeightInWater;
}
char const* Map::GetMapName() const

View File

@ -22,6 +22,7 @@
#include "SpellInfo.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "SpellAuraEffects.h"
#include "sunwell_plateau.h"
enum Quotes
@ -83,6 +84,10 @@ struct boss_sacrolash : public BossAI
_isSisterDead = false;
BossAI::Reset();
me->SetLootMode(0);
if (Creature* alythess = instance->GetCreature(DATA_ALYTHESS))
if (!alythess->IsAlive())
alythess->Respawn(true);
}
void DoAction(int32 param) override
@ -104,18 +109,6 @@ struct boss_sacrolash : public BossAI
}
}
void EnterEvadeMode(EvadeReason why) override
{
BossAI::EnterEvadeMode(why);
if (Creature* alythess = instance->GetCreature(DATA_ALYTHESS))
{
if (!alythess->IsAlive())
alythess->Respawn(true);
else if (!alythess->IsInEvadeMode())
alythess->AI()->EnterEvadeMode(why);
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
@ -191,6 +184,10 @@ struct boss_alythess : public BossAI
_isSisterDead = false;
BossAI::Reset();
me->SetLootMode(0);
if (Creature* sacrolash = instance->GetCreature(DATA_SACROLASH))
if (!sacrolash->IsAlive())
sacrolash->Respawn(true);
}
void DoAction(int32 param) override
@ -212,18 +209,6 @@ struct boss_alythess : public BossAI
}
}
void EnterEvadeMode(EvadeReason why) override
{
BossAI::EnterEvadeMode(why);
if (Creature* sacrolash = instance->GetCreature(DATA_SACROLASH))
{
if (!sacrolash->IsAlive())
sacrolash->Respawn(true);
else if (!sacrolash->IsInEvadeMode())
sacrolash->AI()->EnterEvadeMode(why);
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
@ -381,8 +366,15 @@ public:
return ValidateSpellInfo({ _touchSpell });
}
void OnPeriodic(AuraEffect const* /*aurEff*/)
void OnPeriodic(AuraEffect const* aurEff)
{
if (aurEff->GetId() == SPELL_FLAME_SEAR)
{
uint32 tick = aurEff->GetTickNumber();
if (tick % 2 != 0 || tick > 10)
return;
}
if (Unit* owner = GetOwner()->ToUnit())
owner->CastSpell(owner, _touchSpell, true);
}

View File

@ -37,6 +37,7 @@ public:
return;
uint32 playerGUID = player->GetGUID().GetCounter();
bool isAlliance = player->GetTeamId() == TEAM_ALLIANCE;
for (auto const& [mailId, servMail] : serverMailStore)
{
@ -45,12 +46,14 @@ public:
stmt->SetData(1, mailId);
// Capture servMail by value
auto callback = [session, servMailWrapper = std::reference_wrapper<ServerMail const>(servMail)](PreparedQueryResult result)
auto callback = [session, servMailWrapper = std::reference_wrapper<ServerMail const>(servMail), isAlliance](PreparedQueryResult result)
{
ServerMail const& servMail = servMailWrapper.get(); // Dereference the wrapper to get the original object
if (!result)
{
std::vector<ServerMailItems> const& items = isAlliance ? servMail.itemsA : servMail.itemsH;
sObjectMgr->SendServerMail(
session->GetPlayer(),
servMail.id,
@ -58,10 +61,7 @@ public:
servMail.reqPlayTime,
servMail.moneyA,
servMail.moneyH,
servMail.itemA,
servMail.itemCountA,
servMail.itemH,
servMail.itemCountH,
items,
servMail.subject,
servMail.body,
servMail.active