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:
Aaron Kimbrell
2026-09-26 18:44:43 -05:00
parent 73c7ab939e
commit e9ab4f5418
17 changed files with 1790 additions and 646 deletions

View File

@@ -35,6 +35,8 @@
#include "BuildingMessages.h"
#include "RacingMessages.h"
#include "MissionMessages.h"
#include "TradeMessages.h"
#include "VendorMessages.h"
#include "EffectsMessages.h"
#include "InventoryMessages.h"
#include "PetMessages.h"
@@ -139,6 +141,22 @@ namespace {
{ UN_USE_BBB_MODEL, []() { return std::make_unique<UnUseBBBModel>(); } },
{ BBB_LOAD_ITEM_REQUEST, []() { return std::make_unique<BBBLoadItemRequest>(); } },
{ BBB_SAVE_REQUEST, []() { return std::make_unique<BBBSaveRequest>(); } },
// Vendors and donation vendors
{ REQUEST_VENDOR_STATUS_UPDATE, []() { return std::make_unique<RequestVendorStatusUpdate>(); } },
{ BUY_FROM_VENDOR, []() { return std::make_unique<BuyFromVendor>(); } },
{ SELL_TO_VENDOR, []() { return std::make_unique<SellToVendor>(); } },
{ BUYBACK_FROM_VENDOR, []() { return std::make_unique<BuybackFromVendor>(); } },
{ ADD_DONATION_ITEM, []() { return std::make_unique<AddDonationItem>(); } },
{ REMOVE_DONATION_ITEM, []() { return std::make_unique<RemoveDonationItem>(); } },
{ CONFIRM_DONATION_ON_PLAYER, []() { return std::make_unique<ConfirmDonationOnPlayer>(); } },
{ CANCEL_DONATION_ON_PLAYER, []() { return std::make_unique<CancelDonationOnPlayer>(); } },
// Trading
{ CLIENT_TRADE_REQUEST, []() { return std::make_unique<ClientTradeRequest>(); } },
{ CLIENT_TRADE_CANCEL, []() { return std::make_unique<ClientTradeCancel>(); } },
{ CLIENT_TRADE_ACCEPT, []() { return std::make_unique<ClientTradeAccept>(); } },
{ CLIENT_TRADE_UPDATE, []() { return std::make_unique<ClientTradeUpdate>(); } },
};
};
@@ -464,18 +482,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
entity->Smash(entity->GetObjectID());
break;
case MessageType::Game::BUY_FROM_VENDOR:
GameMessages::HandleBuyFromVendor(inStream, entity, sysAddr);
break;
case MessageType::Game::SELL_TO_VENDOR:
GameMessages::HandleSellToVendor(inStream, entity, sysAddr);
break;
case MessageType::Game::BUYBACK_FROM_VENDOR:
GameMessages::HandleBuybackFromVendor(inStream, entity, sysAddr);
break;
case MessageType::Game::REBUILD_CANCEL:
GameMessages::HandleQuickBuildCancel(inStream, entity);
break;
@@ -489,20 +495,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
break;
// Trading
case MessageType::Game::CLIENT_TRADE_REQUEST:
GameMessages::HandleClientTradeRequest(inStream, entity, sysAddr);
break;
case MessageType::Game::CLIENT_TRADE_CANCEL:
GameMessages::HandleClientTradeCancel(inStream, entity, sysAddr);
break;
case MessageType::Game::CLIENT_TRADE_ACCEPT:
GameMessages::HandleClientTradeAccept(inStream, entity, sysAddr);
break;
case MessageType::Game::CLIENT_TRADE_UPDATE:
GameMessages::HandleClientTradeUpdate(inStream, entity, sysAddr);
break;
// Racing: most racing messages are registered in g_MessageHandlers
case MessageType::Game::ACKNOWLEDGE_POSSESSION:
GameMessages::HandleAcknowledgePossession(inStream, entity, sysAddr);
break;
@@ -565,21 +557,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
case MessageType::Game::ZONE_SUMMARY_DISMISSED:
GameMessages::HandleZoneSummaryDismissed(inStream, entity);
break;
case MessageType::Game::ADD_DONATION_ITEM:
GameMessages::HandleAddDonationItem(inStream, entity, sysAddr);
break;
case MessageType::Game::REMOVE_DONATION_ITEM:
GameMessages::HandleRemoveDonationItem(inStream, entity, sysAddr);
break;
case MessageType::Game::CONFIRM_DONATION_ON_PLAYER:
GameMessages::HandleConfirmDonationOnPlayer(inStream, entity);
break;
case MessageType::Game::CANCEL_DONATION_ON_PLAYER:
GameMessages::HandleCancelDonationOnPlayer(inStream, entity);
break;
case MessageType::Game::REQUEST_VENDOR_STATUS_UPDATE:
GameMessages::SendVendorStatusUpdate(entity, sysAddr, true);
break;
default:
LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
break;