trading post try fix crash

This commit is contained in:
luis
2026-03-15 21:18:19 -03:00
parent 6902181f28
commit dfe864e477
7 changed files with 117 additions and 14 deletions
@@ -19,6 +19,7 @@
#include "PerkProgramData.h"
#include "PerkProgramMgr.h"
#include "PerksProgramPacketsCommon.h"
#include "PerksProgramPackets.h"
#include "Config.h"
#include "DatabaseEnv.h"
#include "ObjectMgr.h"
@@ -39,17 +40,21 @@ void WorldSession::HandlePerkProgramRequestPurchase(WorldPackets::PerksProgram::
if (!_player)
return;
//GetPerkProgramMgr()->BuyItem(packet.PerksVendorItemID, packet.vendorGuid);
GetPerkProgramMgr()->BuyItem(packet.VendorItemID, ObjectGuid::Empty);
}
void WorldSession::HandlePerkProgamSetForzenVendorItem(WorldPackets::PerksProgram::PerksProgramSetFrozenVendorItem& packet)
void WorldSession::HandlePerkProgramSetFrozenVendorItem(WorldPackets::PerksProgram::PerksProgramSetFrozenVendorItem& packet)
{
if (!_player)
return;
GetPerkProgramMgr()->SetFrozenItem(packet.VendorItemID, packet.VendorItemID == -1);
}
void WorldSession::HandlePerkProgramPendingReward(WorldPackets::PerksProgram::PerksProgramPendingReward& packet)
{
if (!_player)
return;
GetPerkProgramMgr()->SendPendingRewards();
}
@@ -13,6 +13,8 @@
#include "DB2Stores.h"
#include <sstream>
#include "GameTime.h"
#include <random>
#include <chrono>
PerkProgramDataStoreMgr::PerkProgramDataStoreMgr() {};
@@ -47,11 +49,19 @@ void PerkProgramDataStoreMgr::LoadPerkVendorItem()
return;
}
uint32 validCount = 0;
for (PerksVendorItemEntry const* itemVendor : sPerksVendorItemStore)
{
if (!itemVendor)
continue;
// Validate item data
if (itemVendor->Cost > 1000000) // Reasonable maximum cost
{
TC_LOG_WARN("server.loading", ">> PerksVendorItem {} has excessive cost {}, skipping", itemVendor->ID, itemVendor->Cost);
continue;
}
PerkProgramData::PerkVendorItem vendorItem;
vendorItem.Id = itemVendor->ID;
vendorItem.ItemID = itemVendor->ItemID;
@@ -60,13 +70,15 @@ void PerkProgramDataStoreMgr::LoadPerkVendorItem()
vendorItem.TransmogSet = 0;
vendorItem.ItemModifiedAppearanceID = 0;
vendorItem.ToyItem = 0;
vendorItem.AvailableUntil = 0; // Initialize to 0 (no expiration)
vendorItem.Cost = itemVendor->Cost;
vendorItem.CategoryId = itemVendor->PerksVendorCategoryID;
_vendorTemplates.insert(std::make_pair(itemVendor->ID, vendorItem));
validCount++;
}
TC_LOG_INFO("server.loading", ">> Loaded {} PerkPrograms Vendor Items Templates", uint32(_vendorTemplates.size()));
TC_LOG_INFO("server.loading", ">> Loaded {} PerkPrograms Vendor Items Templates ({} valid)", uint32(_vendorTemplates.size()), validCount);
}
std::unordered_map<uint32, PerkProgramData::PerkVendorItem> PerkProgramDataStoreMgr::GetVendorItems()
@@ -88,8 +100,11 @@ PerkProgramData::PerkVendorItem const* PerkProgramDataStoreMgr::GetRandomVendorI
if (_vendorTemplates.empty())
return nullptr;
// Use proper random number generation
static thread_local std::mt19937 generator(std::random_device{}());
std::uniform_int_distribution<size_t> distribution(0, _vendorTemplates.size() - 1);
auto it = _vendorTemplates.begin();
std::advance(it, rand() % _vendorTemplates.size());
std::advance(it, distribution(generator));
return &it->second;
}
+75 -8
View File
@@ -37,7 +37,8 @@ using namespace PerkPrograms;
PerkProgramManager::PerkProgramManager(WorldSession* session)
{
_session = session;
if (session->GetPlayer())
m_player = nullptr;
if (session && session->GetPlayer())
m_player = session->GetPlayer();
m_currencyAmount = 0;
@@ -49,6 +50,17 @@ PerkProgramManager::~PerkProgramManager()
void PerkProgramManager::SendVendorItems(Creature* vendor, std::vector<uint32> purchasedItems)
{
// Additional safety check - verify this pointer is valid
if (this == nullptr)
return;
if (!_session || !vendor)
return;
// Validate session is still valid
if (_session->GetPlayer() != m_player)
m_player = _session->GetPlayer();
WorldPackets::PerksProgram::PerksProgramResult perks;
perks.Type = PerkPrograms::RESULT_AVAILABLE_ITEMS;
@@ -71,7 +83,8 @@ void PerkProgramManager::SendVendorItems(Creature* vendor, std::vector<uint32> p
if (cameraId != 0)
{
std::list<Creature*> list;
_session->GetPlayer()->GetCreatureListWithEntryInGrid(list, cameraId, 100);
if (_session->GetPlayer())
_session->GetPlayer()->GetCreatureListWithEntryInGrid(list, cameraId, 100);
for (auto cr1 : list)
{
@@ -93,8 +106,12 @@ void PerkProgramManager::SendVendorItems(Creature* vendor, std::vector<uint32> p
vendorItem.OriginalPrice = items.second.CategoryId;
vendorItem.Disabled = false;
vendorItem.AvailableUntil = items.second.AvailableUntil;
// Skip items that are no longer available
if (items.second.AvailableUntil > 0 && GameTime::GetGameTime() > items.second.AvailableUntil)
continue;
perks.Params.VendorItem.FrozenPerksVendorItems.emplace_back(vendorItem);
}
_session->SendPacket(perks.Write());
@@ -121,7 +138,7 @@ bool PerkProgramManager::IsAccountWideItem(uint32 item)
bool PerkProgramManager::IsItemAlreadyOwned(PerkProgramData::PerkVendorItem const* vendorItem)
{
if (!vendorItem)
if (!vendorItem || !m_player)
return true;
switch (vendorItem->CategoryId)
@@ -145,7 +162,7 @@ bool PerkProgramManager::IsItemAlreadyOwned(PerkProgramData::PerkVendorItem cons
void PerkProgramManager::GrantItem(PerkProgramData::PerkVendorItem const* vendorItem)
{
if (!vendorItem)
if (!vendorItem || !m_player)
return;
switch (vendorItem->CategoryId)
@@ -187,7 +204,7 @@ void PerkProgramManager::GrantItem(PerkProgramData::PerkVendorItem const* vendor
void PerkProgramManager::RemoveGrantedItem(PerkProgramData::PerkVendorItem const* vendorItem)
{
if (!vendorItem)
if (!vendorItem || !m_player)
return;
switch (vendorItem->CategoryId)
@@ -213,6 +230,12 @@ void PerkProgramManager::RemoveGrantedItem(PerkProgramData::PerkVendorItem const
void PerkProgramManager::BuyItem(uint32 itemId, ObjectGuid /*vendor*/)
{
if (!m_player)
{
SendPerksProgramError(6);
return;
}
auto const* vendorItem = sPerkProgramDataStore->GetVendorItem(itemId);
if (!vendorItem)
{
@@ -245,6 +268,9 @@ void PerkProgramManager::BuyItem(uint32 itemId, ObjectGuid /*vendor*/)
void PerkProgramManager::SendBuyItemResult(int32 itemId)
{
if (!_session)
return;
WorldPackets::PerksProgram::PerksProgramResult perks;
perks.Type = PerkPrograms::RESULT_BUY_ITEM;
perks.Params.BuyItem.VendorItemID = itemId;
@@ -259,15 +285,23 @@ void PerkProgramManager::SendBuyItemResult(int32 itemId)
void PerkProgramManager::SendCurrencyRefresh()
{
if (!_session)
return;
WorldPackets::PerksProgram::PerksProgramResult perks;
perks.Type = PerkPrograms::RESULT_CURRENCY_REFRESH;
perks.Params.Currency.CurrencyAmount = m_currencyAmount;
_session->SendPacket(perks.Write());
}
void PerkProgramManager::SendPerksProgramError(uint32 errorCode)
{
if (!_session)
return;
WorldPackets::PerksProgram::PerksProgramResult perks;
perks.Type = PerkPrograms::RESULT_ERROR;
perks.Params.Error.ErrorCode = errorCode;
_session->SendPacket(perks.Write());
}
@@ -278,6 +312,12 @@ void PerkProgramManager::RecordPurchase(uint32 itemId, time_t purchaseTime)
void PerkProgramManager::RefundItem(int32 itemId)
{
if (!m_player)
{
SendPerksProgramError(6);
return;
}
auto it = std::find_if(m_recentPurchases.begin(), m_recentPurchases.end(),
[itemId](std::pair<uint32, time_t> const& p) { return p.first == static_cast<uint32>(itemId); });
@@ -293,6 +333,13 @@ void PerkProgramManager::RefundItem(int32 itemId)
return;
}
// Additional safety check for very old purchases
if (it->second > GameTime::GetGameTime())
{
SendPerksProgramError(5);
return;
}
auto const* vendorItem = sPerkProgramDataStore->GetVendorItem(itemId);
if (!vendorItem)
return;
@@ -310,6 +357,9 @@ void PerkProgramManager::RefundItem(int32 itemId)
void PerkProgramManager::SendRefundSuccess(int32 itemId)
{
if (!_session)
return;
WorldPackets::PerksProgram::PerksProgramResult perks;
perks.Type = PerkPrograms::RESULT_REFUND_SUCCESS;
perks.Params.BuyItem.VendorItemID = itemId;
@@ -318,6 +368,12 @@ void PerkProgramManager::SendRefundSuccess(int32 itemId)
void PerkProgramManager::CartCheckout(std::vector<uint32> const& vendorItemIDs)
{
if (!m_player)
{
SendPerksProgramError(6);
return;
}
uint32 totalCost = 0;
for (uint32 itemId : vendorItemIDs)
@@ -359,6 +415,9 @@ void PerkProgramManager::CartCheckout(std::vector<uint32> const& vendorItemIDs)
void PerkProgramManager::SendCartCheckoutSuccess()
{
if (!_session)
return;
WorldPackets::PerksProgram::PerksProgramResult perks;
perks.Type = PerkPrograms::RESULT_PURCHASE_CART;
_session->SendPacket(perks.Write());
@@ -366,8 +425,12 @@ void PerkProgramManager::SendCartCheckoutSuccess()
void PerkProgramManager::SendPerksProgramStatus()
{
if (!_session)
return;
WorldPackets::PerksProgram::PerksProgramResult perks;
perks.Type = PerkPrograms::RESULT_CURRENCY_REFRESH;
perks.Params.Currency.CurrencyAmount = m_currencyAmount;
_session->SendPacket(perks.Write());
}
@@ -377,6 +440,9 @@ void PerkProgramManager::SendPendingRewards()
void PerkProgramManager::SetFrozenItem(int32 itemId, bool clear)
{
if (!_session)
return;
if (clear)
{
m_frozenItems.clear();
@@ -408,13 +474,14 @@ void PerkProgramManager::RemoveTrackedActivity(uint32 activityId)
{
auto it = std::find(m_trackedActivities.begin(), m_trackedActivities.end(), activityId);
if (it != m_trackedActivities.end())
{
m_trackedActivities.erase(it);
}
}
void PerkProgramManager::SendPerksProgramActivities()
{
if (!_session)
return;
WorldPackets::PerksProgram::PerksProgramActivityUpdate activity;
activity.TimeUntilStart = GameTime::GetGameTime();
@@ -73,6 +73,12 @@ WorldPacket const* PerksProgramResult::Write()
for (auto&& frozenPerksVendorItem : Params.VendorItem.FrozenPerksVendorItems)
_worldPacket << frozenPerksVendorItem;
break;
case 11: //ResultTypes::CurrencyRefresh:
_worldPacket << Params.Currency.CurrencyAmount;
break;
case 10: //ResultTypes::Error:
_worldPacket << Params.Error.ErrorCode;
break;
default:
break;
}
@@ -95,6 +95,16 @@ public:
ObjectGuid VendorGuid;
ObjectGuid ModelSceneCameraGuid;
} VendorItem;
struct
{
uint32 CurrencyAmount = 0;
} Currency;
struct
{
uint32 ErrorCode = 0;
} Error;
} Params = {};
};
+1 -1
View File
@@ -882,7 +882,7 @@ void OpcodeTable::InitializeClientOpcodes()
DEFINE_HANDLER(CMSG_PERKS_PROGRAM_REQUEST_PENDING_REWARDS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandlePerkProgramPendingReward);
DEFINE_HANDLER(CMSG_PERKS_PROGRAM_REQUEST_PURCHASE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandlePerkProgramRequestPurchase);
DEFINE_HANDLER(CMSG_PERKS_PROGRAM_REQUEST_REFUND, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_PERKS_PROGRAM_SET_FROZEN_VENDOR_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandlePerkProgamSetForzenVendorItem);
DEFINE_HANDLER(CMSG_PERKS_PROGRAM_SET_FROZEN_VENDOR_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandlePerkProgramSetFrozenVendorItem);
DEFINE_HANDLER(CMSG_PERKS_PROGRAM_STATUS_REQUEST, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGetPerkProgramRequest);
DEFINE_HANDLER(CMSG_PETITION_BUY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionBuy);
DEFINE_HANDLER(CMSG_PETITION_RENAME_GUILD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePetitionRenameGuild);
+1 -1
View File
@@ -1553,7 +1553,7 @@ class TC_GAME_API WorldSession
//PERKS
void HandleGetPerkProgramRequest(WorldPackets::PerksProgram::PerksProgramStatusRequest& packet);
void HandlePerkProgramRequestPurchase(WorldPackets::PerksProgram::PerksProgramRequestPurchase& packet);
void HandlePerkProgamSetForzenVendorItem(WorldPackets::PerksProgram::PerksProgramSetFrozenVendorItem& packet);
void HandlePerkProgramSetFrozenVendorItem(WorldPackets::PerksProgram::PerksProgramSetFrozenVendorItem& packet);
void HandlePerkProgramPendingReward(WorldPackets::PerksProgram::PerksProgramPendingReward& packet);
//wowcommunity