mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-16 17:44:08 +00:00
refactor: vendor, donation and trade game messages as structs
Converts the vendor, donation vendor and trade game messages to
NetGameMsgs in VendorMessages.{h,cpp} and TradeMessages.{h,cpp}:
VendorOpenWindow and VendorTransactionResult (SendToClient: the old
functions never broadcast), VendorStatusUpdate, ServerTradeInvite,
ServerTradeInitialReply, ServerTradeFinalReply, ServerTradeAccept,
ServerTradeCancel and ServerTradeUpdate, and the received
RequestVendorStatusUpdate, BuyFromVendor, SellToVendor,
BuybackFromVendor, AddDonationItem, RemoveDonationItem,
ConfirmDonationOnPlayer, CancelDonationOnPlayer, ClientTradeRequest,
ClientTradeCancel, ClientTradeAccept and ClientTradeUpdate. A trade
offer entry (the client's inventory item layout, optional fields and
config block included) is TradeItemEntry, shared by both trade updates.
Selling and buying back move into VendorComponent (SellToVendor,
BuybackFromVendor), adding and confirming donations into
DonationVendorComponent, and VendorComponent builds its own status
update and transaction results. Only the VENDOR component sends its
stock, as before. The received messages are registered in
GameMessageHandler's map, the switch cases and the old functions are
deleted. Handler logic is unchanged.
No wire change and no change in recipients. Verified byte for byte
against a frozen verbatim copy of the old functions over an input grid
(to one client and broadcast), received messages compared with the old
handlers' read sequences (every optional field of a trade entry,
raw and compressed config blocks) and truncated payloads rejected, hand
computed golden bytes, round trips, and a deliberate width mutation made
the tests fail. ConfirmDonationOnPlayer still accepts a message without
its vendor ID, since the old handler read nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -710,53 +710,6 @@ void GameMessages::SendRemoveSkill(Entity* entity, TSkillID skillID) {
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendVendorOpenWindow(Entity* entity, const SystemAddress& sysAddr) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(entity->GetObjectID());
|
||||
bitStream.Write(MessageType::Game::VENDOR_OPEN_WINDOW);
|
||||
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr, bool bUpdateOnly) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
VendorComponent* vendor = static_cast<VendorComponent*>(entity->GetComponent(eReplicaComponentType::VENDOR));
|
||||
if (!vendor) return;
|
||||
|
||||
auto vendorItems = vendor->GetInventory();
|
||||
|
||||
bitStream.Write(entity->GetObjectID());
|
||||
bitStream.Write(MessageType::Game::VENDOR_STATUS_UPDATE);
|
||||
|
||||
bitStream.Write(bUpdateOnly);
|
||||
bitStream.Write<uint32_t>(vendorItems.size());
|
||||
|
||||
|
||||
for (const auto& item : vendorItems) {
|
||||
bitStream.Write(item.lot);
|
||||
bitStream.Write(item.sortPriority);
|
||||
}
|
||||
|
||||
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr, eVendorTransactionResult result) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
|
||||
bitStream.Write(entity->GetObjectID());
|
||||
bitStream.Write(MessageType::Game::VENDOR_TRANSACTION_RESULT);
|
||||
bitStream.Write(result);
|
||||
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendMatchResponse(Entity* entity, const SystemAddress& sysAddr, int response) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
@@ -1405,264 +1358,6 @@ void GameMessages::SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJ
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
//Trading:
|
||||
|
||||
void GameMessages::SendServerTradeInvite(LWOOBJID objectId, bool bNeedInvitePopUp, LWOOBJID i64Requestor, std::u16string wsName, const SystemAddress& sysAddr) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(objectId);
|
||||
bitStream.Write(MessageType::Game::SERVER_TRADE_INVITE);
|
||||
|
||||
bitStream.Write(bNeedInvitePopUp);
|
||||
bitStream.Write(i64Requestor);
|
||||
bitStream.Write<uint32_t>(wsName.size());
|
||||
for (const auto character : wsName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
|
||||
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendServerTradeInitialReply(LWOOBJID objectId, LWOOBJID i64Invitee, int32_t resultType, std::u16string wsName, const SystemAddress& sysAddr) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(objectId);
|
||||
bitStream.Write(MessageType::Game::SERVER_TRADE_INITIAL_REPLY);
|
||||
|
||||
bitStream.Write(i64Invitee);
|
||||
bitStream.Write(resultType);
|
||||
bitStream.Write<uint32_t>(wsName.size());
|
||||
for (const auto character : wsName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
|
||||
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendServerTradeFinalReply(LWOOBJID objectId, bool bResult, LWOOBJID i64Invitee, std::u16string wsName, const SystemAddress& sysAddr) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(objectId);
|
||||
bitStream.Write(MessageType::Game::SERVER_TRADE_FINAL_REPLY);
|
||||
|
||||
bitStream.Write(bResult);
|
||||
bitStream.Write(i64Invitee);
|
||||
bitStream.Write<uint32_t>(wsName.size());
|
||||
for (const auto character : wsName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
|
||||
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendServerTradeAccept(LWOOBJID objectId, bool bFirst, const SystemAddress& sysAddr) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(objectId);
|
||||
bitStream.Write(MessageType::Game::SERVER_TRADE_ACCEPT);
|
||||
|
||||
bitStream.Write(bFirst);
|
||||
|
||||
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendServerTradeCancel(LWOOBJID objectId, const SystemAddress& sysAddr) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(objectId);
|
||||
bitStream.Write(MessageType::Game::SERVER_TRADE_CANCEL);
|
||||
|
||||
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, const std::vector<TradeItem>& items, const SystemAddress& sysAddr) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(objectId);
|
||||
bitStream.Write(MessageType::Game::SERVER_TRADE_UPDATE);
|
||||
|
||||
bitStream.Write(false);
|
||||
bitStream.Write(coins);
|
||||
bitStream.Write<uint32_t>(items.size());
|
||||
|
||||
for (const auto& item : items) {
|
||||
bitStream.Write(item.itemId);
|
||||
bitStream.Write(item.itemId);
|
||||
|
||||
bitStream.Write(item.itemLot);
|
||||
bitStream.Write0();
|
||||
bitStream.Write1();
|
||||
bitStream.Write(item.itemCount);
|
||||
bitStream.Write0();
|
||||
bitStream.Write0();
|
||||
bitStream.Write0();
|
||||
bitStream.Write0();
|
||||
}
|
||||
|
||||
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::HandleClientTradeRequest(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
// Check if the player has restricted trade access
|
||||
auto* character = entity->GetCharacter();
|
||||
const bool restrictTradeOnMute = UserManager::Instance()->GetMuteRestrictTrade();
|
||||
|
||||
if (character->HasPermission(ePermissionMap::RestrictedTradeAccess) || (restrictTradeOnMute && character->GetParentUser()->GetIsMuted())) {
|
||||
// Send a message to the player
|
||||
ChatPackets::SendSystemMessage(
|
||||
sysAddr,
|
||||
u"Your character has restricted trade access."
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool bNeedInvitePopUp = inStream.ReadBit();
|
||||
LWOOBJID i64Invitee;
|
||||
|
||||
inStream.Read(i64Invitee);
|
||||
|
||||
auto* invitee = Game::entityManager->GetEntity(i64Invitee);
|
||||
|
||||
if (invitee != nullptr && invitee->IsPlayer()) {
|
||||
character = invitee->GetCharacter();
|
||||
|
||||
if (character->HasPermission(ePermissionMap::RestrictedTradeAccess) || (restrictTradeOnMute && character->GetParentUser()->GetIsMuted())) {
|
||||
// Send a message to the player
|
||||
ChatPackets::SendSystemMessage(
|
||||
sysAddr,
|
||||
u"The character you are trying to trade with has restricted trade access."
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("Trade request to (%llu)", i64Invitee);
|
||||
|
||||
const auto& trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID());
|
||||
|
||||
if (trade != nullptr) {
|
||||
if (!trade->IsParticipant(i64Invitee)) {
|
||||
TradingManager::Instance()->CancelTrade(entity->GetObjectID(), trade->GetTradeId());
|
||||
|
||||
TradingManager::Instance()->NewTrade(entity->GetObjectID(), i64Invitee);
|
||||
}
|
||||
} else {
|
||||
TradingManager::Instance()->NewTrade(entity->GetObjectID(), i64Invitee);
|
||||
}
|
||||
|
||||
SendServerTradeInvite(
|
||||
i64Invitee,
|
||||
bNeedInvitePopUp,
|
||||
entity->GetObjectID(),
|
||||
GeneralUtils::UTF8ToUTF16(entity->GetCharacter()->GetName()),
|
||||
invitee->GetSystemAddress()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void GameMessages::HandleClientTradeCancel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
const auto& trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID());
|
||||
|
||||
if (trade == nullptr) return;
|
||||
|
||||
LOG("Trade canceled from (%llu)", entity->GetObjectID());
|
||||
|
||||
TradingManager::Instance()->CancelTrade(entity->GetObjectID(), trade->GetTradeId());
|
||||
}
|
||||
|
||||
void GameMessages::HandleClientTradeAccept(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
bool bFirst = inStream.ReadBit();
|
||||
|
||||
LOG("Trade accepted from (%llu) -> (%d)", entity->GetObjectID(), bFirst);
|
||||
|
||||
const auto& trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID());
|
||||
|
||||
if (trade == nullptr) return;
|
||||
|
||||
trade->SetAccepted(entity->GetObjectID(), bFirst);
|
||||
}
|
||||
|
||||
void GameMessages::HandleClientTradeUpdate(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
uint64_t currency;
|
||||
uint32_t itemCount;
|
||||
|
||||
inStream.Read(currency);
|
||||
inStream.Read(itemCount);
|
||||
if (itemCount > MAX_MESSAGE_LENGTH) return;
|
||||
|
||||
LOG("Trade update from (%llu) -> (%llu), (%i)", entity->GetObjectID(), currency, itemCount);
|
||||
|
||||
std::vector<TradeItem> items{};
|
||||
|
||||
for (size_t i = 0; i < itemCount; i++) {
|
||||
LWOOBJID itemId;
|
||||
LWOOBJID itemId2;
|
||||
|
||||
inStream.Read(itemId);
|
||||
inStream.Read(itemId2);
|
||||
|
||||
LOT lot = 0;
|
||||
LWOOBJID unknown1 = 0;
|
||||
uint32_t unknown2 = 0;
|
||||
uint16_t slot = 0;
|
||||
uint32_t unknown3 = 0;
|
||||
uint32_t ldfSize = 0;
|
||||
bool unknown4;
|
||||
|
||||
inStream.Read(lot);
|
||||
if (inStream.ReadBit()) {
|
||||
inStream.Read(unknown1);
|
||||
}
|
||||
if (inStream.ReadBit()) {
|
||||
inStream.Read(unknown2);
|
||||
}
|
||||
if (inStream.ReadBit()) {
|
||||
inStream.Read(slot);
|
||||
}
|
||||
if (inStream.ReadBit()) {
|
||||
inStream.Read(unknown3);
|
||||
}
|
||||
if (inStream.ReadBit()) // No
|
||||
{
|
||||
inStream.Read(ldfSize);
|
||||
bool compressed = inStream.ReadBit();
|
||||
if (compressed) {
|
||||
uint32_t ldfCompressedSize = 0;
|
||||
inStream.Read(ldfCompressedSize);
|
||||
inStream.IgnoreBytes(ldfCompressedSize);
|
||||
} else {
|
||||
inStream.IgnoreBytes(ldfSize);
|
||||
}
|
||||
}
|
||||
unknown4 = inStream.ReadBit();
|
||||
|
||||
items.push_back({ itemId, lot, unknown2 });
|
||||
|
||||
LOG("Trade item from (%llu) -> (%llu)/(%llu), (%i), (%llu), (%i), (%i)", entity->GetObjectID(), itemId, itemId2, lot, unknown1, unknown2, unknown3);
|
||||
}
|
||||
|
||||
const auto& trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID());
|
||||
|
||||
if (trade == nullptr) return;
|
||||
|
||||
trade->SetCoins(entity->GetObjectID(), currency);
|
||||
trade->SetItems(entity->GetObjectID(), items);
|
||||
trade->SendUpdateToOther(entity->GetObjectID());
|
||||
}
|
||||
|
||||
//Pets:
|
||||
|
||||
void GameMessages::SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId) {
|
||||
@@ -1966,149 +1661,6 @@ void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream& inStream,
|
||||
}
|
||||
|
||||
|
||||
void GameMessages::HandleBuyFromVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
bool bConfirmed{}; // This doesn't appear to do anything. Further research is needed.
|
||||
bool countIsDefault{};
|
||||
int count = 1;
|
||||
LOT item;
|
||||
|
||||
inStream.Read(bConfirmed);
|
||||
inStream.Read(countIsDefault);
|
||||
if (countIsDefault) inStream.Read(count);
|
||||
inStream.Read(item);
|
||||
|
||||
User* user = UserManager::Instance()->GetUser(sysAddr);
|
||||
if (!user) return;
|
||||
Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar());
|
||||
if (!player) return;
|
||||
|
||||
// handle buying normal items
|
||||
auto* vendorComponent = entity->GetComponent<VendorComponent>();
|
||||
if (vendorComponent) {
|
||||
vendorComponent->Buy(player, item, count);
|
||||
return;
|
||||
}
|
||||
|
||||
// handle buying achievement items
|
||||
auto* achievementVendorComponent = entity->GetComponent<AchievementVendorComponent>();
|
||||
if (achievementVendorComponent) {
|
||||
achievementVendorComponent->Buy(player, item, count);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle buying properties
|
||||
auto* propertyVendorComponent = entity->GetComponent<PropertyVendorComponent>();
|
||||
if (propertyVendorComponent) {
|
||||
propertyVendorComponent->OnBuyFromVendor(player, bConfirmed, item, count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GameMessages::HandleSellToVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
bool countIsDefault{};
|
||||
int count = 1;
|
||||
LWOOBJID iObjID;
|
||||
|
||||
inStream.Read(countIsDefault);
|
||||
if (countIsDefault) inStream.Read(count);
|
||||
inStream.Read(iObjID);
|
||||
|
||||
User* user = UserManager::Instance()->GetUser(sysAddr);
|
||||
if (!user) return;
|
||||
Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar());
|
||||
if (!player) return;
|
||||
Character* character = player->GetCharacter();
|
||||
if (!character) return;
|
||||
InventoryComponent* inv = static_cast<InventoryComponent*>(player->GetComponent(eReplicaComponentType::INVENTORY));
|
||||
if (!inv) return;
|
||||
|
||||
VendorComponent* vend = static_cast<VendorComponent*>(entity->GetComponent(eReplicaComponentType::VENDOR));
|
||||
if (!vend) return;
|
||||
|
||||
Item* item = inv->FindItemById(iObjID);
|
||||
if (!item) return;
|
||||
|
||||
CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||
CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
||||
|
||||
int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), eReplicaComponentType::ITEM);
|
||||
CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID);
|
||||
|
||||
// Items with a base value of 0 or max int are special items that should not be sold if they're not sub items
|
||||
if (itemComp.baseValue == 0 || itemComp.baseValue == UINT_MAX) {
|
||||
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::SELL_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
float sellScalar = vend->GetSellScalar();
|
||||
if (Inventory::IsValidItem(itemComp.currencyLOT)) {
|
||||
const auto altCurrency = static_cast<uint32_t>(itemComp.altCurrencyCost * sellScalar) * count;
|
||||
inv->AddItem(itemComp.currencyLOT, std::floor(altCurrency), eLootSourceType::VENDOR); // Return alt currencies like faction tokens.
|
||||
}
|
||||
|
||||
inv->MoveItemToInventory(item, eInventoryType::VENDOR_BUYBACK, count, true, false, true);
|
||||
character->SetCoins(std::floor(character->GetCoins() + (static_cast<uint32_t>(itemComp.baseValue * sellScalar) * count)), eLootSourceType::VENDOR);
|
||||
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::SELL_SUCCESS);
|
||||
}
|
||||
|
||||
void GameMessages::HandleBuybackFromVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
bool confirmed = false;
|
||||
bool countIsDefault{};
|
||||
int count = 1;
|
||||
LWOOBJID iObjID;
|
||||
|
||||
inStream.Read(confirmed);
|
||||
inStream.Read(countIsDefault);
|
||||
if (countIsDefault) inStream.Read(count);
|
||||
inStream.Read(iObjID);
|
||||
|
||||
//if (!confirmed) return; they always built in this confirmed garbage... but never used it?
|
||||
|
||||
User* user = UserManager::Instance()->GetUser(sysAddr);
|
||||
if (!user) return;
|
||||
Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar());
|
||||
if (!player) return;
|
||||
Character* character = player->GetCharacter();
|
||||
if (!character) return;
|
||||
InventoryComponent* inv = static_cast<InventoryComponent*>(player->GetComponent(eReplicaComponentType::INVENTORY));
|
||||
if (!inv) return;
|
||||
|
||||
VendorComponent* vend = static_cast<VendorComponent*>(entity->GetComponent(eReplicaComponentType::VENDOR));
|
||||
if (!vend) return;
|
||||
|
||||
Item* item = inv->FindItemById(iObjID);
|
||||
if (!item) return;
|
||||
|
||||
CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||
CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
||||
|
||||
int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), eReplicaComponentType::ITEM);
|
||||
CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID);
|
||||
|
||||
float sellScalar = vend->GetSellScalar();
|
||||
|
||||
const auto cost = static_cast<uint32_t>(std::floor(((itemComp.baseValue * sellScalar) * count)));
|
||||
|
||||
if (character->GetCoins() < cost) {
|
||||
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Inventory::IsValidItem(itemComp.currencyLOT)) {
|
||||
const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * sellScalar) * count;
|
||||
if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost || !inv->RemoveItem(itemComp.currencyLOT, altCurrencyCost, eInventoryType::ALL)) {
|
||||
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_FAIL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//inv->RemoveItem(count, -1, iObjID);
|
||||
inv->MoveItemToInventory(item, Inventory::FindInventoryTypeForLot(item->GetLot()), count, true, false);
|
||||
character->SetCoins(character->GetCoins() - cost, eLootSourceType::VENDOR);
|
||||
//Game::entityManager->SerializeEntity(player); // so inventory updates
|
||||
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_SUCCESS);
|
||||
}
|
||||
|
||||
void GameMessages::HandleParseChatMessage(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
std::u16string wsString;
|
||||
int iClientState;
|
||||
@@ -2603,105 +2155,6 @@ void GameMessages::HandleZoneSummaryDismissed(RakNet::BitStream& inStream, Entit
|
||||
entity->TriggerEvent(eTriggerEventType::ZONE_SUMMARY_DISMISSED, target);
|
||||
};
|
||||
|
||||
void GameMessages::HandleAddDonationItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
uint32_t count = 1;
|
||||
bool hasCount = false;
|
||||
inStream.Read(hasCount);
|
||||
if (hasCount) inStream.Read(count);
|
||||
LWOOBJID itemId = LWOOBJID_EMPTY;
|
||||
inStream.Read(itemId);
|
||||
if (!itemId) return;
|
||||
|
||||
auto* donationVendorComponent = entity->GetComponent<DonationVendorComponent>();
|
||||
if (!donationVendorComponent) return;
|
||||
if (donationVendorComponent->GetActivityID() == 0) {
|
||||
LOG("WARNING: Trying to dontate to a vendor with no activity");
|
||||
return;
|
||||
}
|
||||
User* user = UserManager::Instance()->GetUser(sysAddr);
|
||||
if (!user) return;
|
||||
Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar());
|
||||
if (!player) return;
|
||||
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
||||
if (!characterComponent) return;
|
||||
auto* inventoryComponent = player->GetComponent<InventoryComponent>();
|
||||
if (!inventoryComponent) return;
|
||||
Item* item = inventoryComponent->FindItemById(itemId);
|
||||
if (!item) return;
|
||||
if (item->GetCount() < count) return;
|
||||
characterComponent->SetCurrentInteracting(entity->GetObjectID());
|
||||
inventoryComponent->MoveItemToInventory(item, eInventoryType::DONATION, count, true, false, true);
|
||||
}
|
||||
|
||||
void GameMessages::HandleRemoveDonationItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
bool confirmed = false;
|
||||
inStream.Read(confirmed);
|
||||
uint32_t count = 1;
|
||||
bool hasCount = false;
|
||||
inStream.Read(hasCount);
|
||||
if (hasCount) inStream.Read(count);
|
||||
LWOOBJID itemId = LWOOBJID_EMPTY;
|
||||
inStream.Read(itemId);
|
||||
if (!itemId) return;
|
||||
|
||||
User* user = UserManager::Instance()->GetUser(sysAddr);
|
||||
if (!user) return;
|
||||
Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar());
|
||||
if (!player) return;
|
||||
|
||||
auto* inventoryComponent = player->GetComponent<InventoryComponent>();
|
||||
if (!inventoryComponent) return;
|
||||
|
||||
Item* item = inventoryComponent->FindItemById(itemId);
|
||||
if (!item) return;
|
||||
if (item->GetCount() < count) return;
|
||||
inventoryComponent->MoveItemToInventory(item, eInventoryType::BRICKS, count, true, false, true);
|
||||
}
|
||||
|
||||
void GameMessages::HandleConfirmDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity) {
|
||||
const auto [inventoryComponent, missionComponent, characterComponent] = entity->GetComponentsMut<InventoryComponent, MissionComponent, CharacterComponent>();
|
||||
if (!inventoryComponent || !missionComponent || !characterComponent || !characterComponent->GetCurrentInteracting()) return;
|
||||
|
||||
auto* donationEntity = Game::entityManager->GetEntity(characterComponent->GetCurrentInteracting());
|
||||
if (!donationEntity) return;
|
||||
auto* donationVendorComponent = donationEntity->GetComponent<DonationVendorComponent>();
|
||||
if (!donationVendorComponent) return;
|
||||
if (donationVendorComponent->GetActivityID() == 0) {
|
||||
LOG("WARNING: Trying to dontate to a vendor with no activity");
|
||||
return;
|
||||
}
|
||||
auto* inventory = inventoryComponent->GetInventory(eInventoryType::DONATION);
|
||||
if (!inventory) return;
|
||||
auto items = inventory->GetItems();
|
||||
if (!items.empty()) {
|
||||
uint32_t count = 0;
|
||||
for (auto& [itemID, item] : items) {
|
||||
count += item->GetCount();
|
||||
EconomyLedger::RecordItemsUnsuppressed(entity, item->GetLot(), -static_cast<int64_t>(item->GetCount()), EconomyLedger::DONATION_SOURCE);
|
||||
item->RemoveFromInventory();
|
||||
}
|
||||
missionComponent->Progress(eMissionTaskType::DONATION, 0, LWOOBJID_EMPTY, "", count);
|
||||
LeaderboardManager::SaveScore(entity->GetObjectID(), donationVendorComponent->GetActivityID(), count);
|
||||
donationVendorComponent->SubmitDonation(count);
|
||||
Game::entityManager->SerializeEntity(donationEntity);
|
||||
}
|
||||
characterComponent->SetCurrentInteracting(LWOOBJID_EMPTY);
|
||||
}
|
||||
|
||||
void GameMessages::HandleCancelDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity) {
|
||||
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
||||
if (!inventoryComponent) return;
|
||||
auto* inventory = inventoryComponent->GetInventory(eInventoryType::DONATION);
|
||||
if (!inventory) return;
|
||||
auto items = inventory->GetItems();
|
||||
for (auto& [itemID, item] : items) {
|
||||
inventoryComponent->MoveItemToInventory(item, eInventoryType::BRICKS, item->GetCount(), false, false, true);
|
||||
}
|
||||
auto* characterComponent = entity->GetComponent<CharacterComponent>();
|
||||
if (!characterComponent) return;
|
||||
characterComponent->SetCurrentInteracting(LWOOBJID_EMPTY);
|
||||
}
|
||||
|
||||
void GameMessages::SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
Reference in New Issue
Block a user