[Feature] Enable bazaar window 'Find Trader' functionality (#4560)

* First pass to enable trader 'Find Trader' functionality

* Move SendBulkTraders out of zoning routines and send as part of the opening of the bazaar search window.
Add zone instance to SendBulkTraders to support multi-instanced bazaars.
This commit is contained in:
Mitch Freeman 2024-12-12 03:25:12 -04:00 committed by GitHub
parent 66a7dd0143
commit 6172c49b08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 187 additions and 134 deletions

View File

@ -8,13 +8,14 @@ std::vector<BazaarSearchResultsFromDB_Struct>
Bazaar::GetSearchResults( Bazaar::GetSearchResults(
SharedDatabase &db, SharedDatabase &db,
BazaarSearchCriteria_Struct search, BazaarSearchCriteria_Struct search,
uint32 char_zone_id uint32 char_zone_id,
int32 char_zone_instance_id
) )
{ {
LogTrading( LogTrading(
"Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] " "Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] "
"max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] " "max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] "
"search_scope [{}] char_zone_id [{}]", "search_scope [{}] char_zone_id [{}], char_zone_instance_id [{}]",
search.item_name, search.item_name,
search.min_cost, search.min_cost,
search.max_cost, search.max_cost,
@ -26,7 +27,8 @@ Bazaar::GetSearchResults(
search.trader_entity_id, search.trader_entity_id,
search.trader_id, search.trader_id,
search.search_scope, search.search_scope,
char_zone_id char_zone_id,
char_zone_instance_id
); );
std::string search_criteria_trader("TRUE "); std::string search_criteria_trader("TRUE ");
@ -34,14 +36,19 @@ Bazaar::GetSearchResults(
if (search.search_scope == NonRoFBazaarSearchScope) { if (search.search_scope == NonRoFBazaarSearchScope) {
search_criteria_trader.append( search_criteria_trader.append(
fmt::format( fmt::format(
" AND trader.char_entity_id = {} AND trader.char_zone_id = {}", " AND trader.char_entity_id = {} AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
search.trader_entity_id, search.trader_entity_id,
Zones::BAZAAR Zones::BAZAAR,
char_zone_instance_id
) )
); );
} }
else if (search.search_scope == Local_Scope) { else if (search.search_scope == Local_Scope) {
search_criteria_trader.append(fmt::format(" AND trader.char_zone_id = {}", char_zone_id)); search_criteria_trader.append(fmt::format(
" AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
char_zone_id,
char_zone_instance_id)
);
} }
else if (search.trader_id > 0) { else if (search.trader_id > 0) {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id)); search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
@ -62,7 +69,7 @@ Bazaar::GetSearchResults(
std::string query = fmt::format( std::string query = fmt::format(
"SELECT COUNT(item_id), trader.char_id, trader.item_id, trader.item_sn, trader.item_charges, trader.item_cost, " "SELECT COUNT(item_id), trader.char_id, trader.item_id, trader.item_sn, trader.item_charges, trader.item_cost, "
"trader.slot_id, SUM(trader.item_charges), trader.char_zone_id, trader.char_entity_id, character_data.name, " "trader.slot_id, SUM(trader.item_charges), trader.char_zone_id, trader.char_entity_id, character_data.name, "
"aug_slot_1, aug_slot_2, aug_slot_3, aug_slot_4, aug_slot_5, aug_slot_6 " "aug_slot_1, aug_slot_2, aug_slot_3, aug_slot_4, aug_slot_5, aug_slot_6, trader.char_zone_instance_id "
"FROM trader, character_data " "FROM trader, character_data "
"WHERE {} AND trader.char_id = character_data.id " "WHERE {} AND trader.char_id = character_data.id "
"GROUP BY trader.item_sn, trader.item_charges, trader.char_id", "GROUP BY trader.item_sn, trader.item_charges, trader.char_id",
@ -122,19 +129,20 @@ Bazaar::GetSearchResults(
continue; continue;
} }
r.count = Strings::ToInt(row[0]); r.count = Strings::ToInt(row[0]);
r.trader_id = Strings::ToInt(row[1]); r.trader_id = Strings::ToInt(row[1]);
r.serial_number = Strings::ToInt(row[3]); r.serial_number = Strings::ToInt(row[3]);
r.cost = Strings::ToInt(row[5]); r.cost = Strings::ToInt(row[5]);
r.slot_id = Strings::ToInt(row[6]); r.slot_id = Strings::ToInt(row[6]);
r.sum_charges = Strings::ToInt(row[7]); r.sum_charges = Strings::ToInt(row[7]);
r.stackable = item->Stackable; r.stackable = item->Stackable;
r.icon_id = item->Icon; r.icon_id = item->Icon;
r.trader_zone_id = Strings::ToInt(row[8]); r.trader_zone_id = Strings::ToInt(row[8]);
r.trader_entity_id = Strings::ToInt(row[9]); r.trader_zone_instance_id = Strings::ToInt(row[17]);
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3])); r.trader_entity_id = Strings::ToInt(row[9]);
r.item_name = fmt::format("{:.63}\0", item->Name); r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str()); r.item_name = fmt::format("{:.63}\0", item->Name);
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
LogTradingDetail( LogTradingDetail(
"Searching against item [{}] ({}) for trader [{}]", "Searching against item [{}] ({}) for trader [{}]",

View File

@ -7,7 +7,7 @@
class Bazaar { class Bazaar {
public: public:
static std::vector<BazaarSearchResultsFromDB_Struct> static std::vector<BazaarSearchResultsFromDB_Struct>
GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id); GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id, int char_zone_instance_id);
}; };

View File

@ -5770,6 +5770,17 @@ MODIFY COLUMN `exp_modifier` float NOT NULL DEFAULT 1.0 AFTER `aa_modifier`;
CREATE INDEX idx_character_expires ON data_buckets (character_id, expires); CREATE INDEX idx_character_expires ON data_buckets (character_id, expires);
CREATE INDEX idx_npc_expires ON data_buckets (npc_id, expires); CREATE INDEX idx_npc_expires ON data_buckets (npc_id, expires);
CREATE INDEX idx_bot_expires ON data_buckets (bot_id, expires); CREATE INDEX idx_bot_expires ON data_buckets (bot_id, expires);
)"
},
ManifestEntry{
.version = 9286,
.description = "2024_11_26_bazaar_find_trader.sql",
.check = "SHOW COLUMNS FROM `trader` LIKE 'char_zone_instance_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `trader`
ADD COLUMN `char_zone_instance_id` INT NULL DEFAULT '0' AFTER `char_zone_id`;
)" )"
} }
// -- template; copy/paste this when you need to create a new entry // -- template; copy/paste this when you need to create a new entry

View File

@ -3742,7 +3742,8 @@ struct GetItems_Struct{
struct BecomeTrader_Struct { struct BecomeTrader_Struct {
uint32 action; uint32 action;
uint32 zone_id; uint16 zone_id;
uint16 zone_instance_id;
uint32 trader_id; uint32 trader_id;
uint32 entity_id; uint32 entity_id;
char trader_name[64]; char trader_name[64];
@ -6347,6 +6348,7 @@ enum BazaarTraderBarterActions {
TraderAck2 = 22, TraderAck2 = 22,
AddTraderToBazaarWindow = 24, AddTraderToBazaarWindow = 24,
RemoveTraderFromBazaarWindow = 25, RemoveTraderFromBazaarWindow = 25,
FirstOpenSearch = 26,
ClickTrader = 28, ClickTrader = 28,
DeliveryCostUpdate = 29 DeliveryCostUpdate = 29
}; };
@ -6386,6 +6388,7 @@ struct BazaarSearchResultsFromDB_Struct {
uint32 icon_id; uint32 icon_id;
uint32 sum_charges; uint32 sum_charges;
uint32 trader_zone_id; uint32 trader_zone_id;
int32 trader_zone_instance_id;
uint32 trader_entity_id; uint32 trader_entity_id;
uint32 item_stat; uint32 item_stat;
bool stackable; bool stackable;
@ -6407,6 +6410,7 @@ struct BazaarSearchResultsFromDB_Struct {
CEREAL_NVP(icon_id), CEREAL_NVP(icon_id),
CEREAL_NVP(sum_charges), CEREAL_NVP(sum_charges),
CEREAL_NVP(trader_zone_id), CEREAL_NVP(trader_zone_id),
CEREAL_NVP(trader_zone_instance_id),
CEREAL_NVP(trader_entity_id), CEREAL_NVP(trader_entity_id),
CEREAL_NVP(item_stat), CEREAL_NVP(item_stat),
CEREAL_NVP(stackable), CEREAL_NVP(stackable),

View File

@ -583,19 +583,21 @@ namespace RoF2
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BecomeTrader_Struct)); auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BecomeTrader_Struct));
auto eq = (BecomeTrader_Struct *) outapp->pBuffer; auto eq = (BecomeTrader_Struct *) outapp->pBuffer;
eq->action = emu->action; eq->action = emu->action;
eq->entity_id = emu->entity_id; eq->entity_id = emu->entity_id;
eq->trader_id = emu->trader_id; eq->trader_id = emu->trader_id;
eq->zone_id = emu->zone_id; eq->zone_id = emu->zone_id;
eq->zone_instance_id = emu->zone_instance_id;
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name)); strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
LogTrading( LogTrading(
"(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] zone_id <green>[{}]", "(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] "
"zone_id <green>[{}] zone_instance_id <green>[{}]",
eq->action, eq->action,
eq->trader_id, eq->trader_id,
eq->entity_id, eq->entity_id,
eq->zone_id eq->zone_id,
); eq->zone_instance_id);
dest->FastQueuePacket(&outapp); dest->FastQueuePacket(&outapp);
break; break;
} }
@ -6218,6 +6220,11 @@ namespace RoF2
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
break; break;
} }
case structs::RoF2BazaarTraderBuyerActions::FirstOpenSearch: {
__packet->SetOpcode(OP_BazaarSearch);
LogTrading("(RoF2) First time opening Bazaar Search since zoning. Action <green>[{}]", action);
break;
}
case structs::RoF2BazaarTraderBuyerActions::WelcomeMessage: { case structs::RoF2BazaarTraderBuyerActions::WelcomeMessage: {
__packet->SetOpcode(OP_BazaarSearch); __packet->SetOpcode(OP_BazaarSearch);
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action); LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);

View File

@ -3119,7 +3119,8 @@ enum RoF2BazaarTraderBuyerActions {
BazaarInspect = 18, BazaarInspect = 18,
ClickTrader = 28, ClickTrader = 28,
ItemMove = 19, ItemMove = 19,
ReconcileItems = 20 ReconcileItems = 20,
FirstOpenSearch = 26
}; };
enum RoF2BuyerActions { enum RoF2BuyerActions {

View File

@ -28,13 +28,14 @@ public:
uint32_t aug_slot_4; uint32_t aug_slot_4;
uint32_t aug_slot_5; uint32_t aug_slot_5;
uint32_t aug_slot_6; uint32_t aug_slot_6;
int32_t item_sn; uint32_t item_sn;
int32_t item_charges; int32_t item_charges;
uint64_t item_cost; uint32_t item_cost;
uint8_t slot_id; uint8_t slot_id;
uint32_t char_entity_id; uint32_t char_entity_id;
uint32_t char_zone_id; uint32_t char_zone_id;
int8_t active_transaction; int32_t char_zone_instance_id;
uint8_t active_transaction;
}; };
static std::string PrimaryKey() static std::string PrimaryKey()
@ -60,6 +61,7 @@ public:
"slot_id", "slot_id",
"char_entity_id", "char_entity_id",
"char_zone_id", "char_zone_id",
"char_zone_instance_id",
"active_transaction", "active_transaction",
}; };
} }
@ -82,6 +84,7 @@ public:
"slot_id", "slot_id",
"char_entity_id", "char_entity_id",
"char_zone_id", "char_zone_id",
"char_zone_instance_id",
"active_transaction", "active_transaction",
}; };
} }
@ -123,22 +126,23 @@ public:
{ {
Trader e{}; Trader e{};
e.id = 0; e.id = 0;
e.char_id = 0; e.char_id = 0;
e.item_id = 0; e.item_id = 0;
e.aug_slot_1 = 0; e.aug_slot_1 = 0;
e.aug_slot_2 = 0; e.aug_slot_2 = 0;
e.aug_slot_3 = 0; e.aug_slot_3 = 0;
e.aug_slot_4 = 0; e.aug_slot_4 = 0;
e.aug_slot_5 = 0; e.aug_slot_5 = 0;
e.aug_slot_6 = 0; e.aug_slot_6 = 0;
e.item_sn = 0; e.item_sn = 0;
e.item_charges = 0; e.item_charges = 0;
e.item_cost = 0; e.item_cost = 0;
e.slot_id = 0; e.slot_id = 0;
e.char_entity_id = 0; e.char_entity_id = 0;
e.char_zone_id = 0; e.char_zone_id = 0;
e.active_transaction = 0; e.char_zone_instance_id = 0;
e.active_transaction = 0;
return e; return e;
} }
@ -175,22 +179,23 @@ public:
if (results.RowCount() == 1) { if (results.RowCount() == 1) {
Trader e{}; Trader e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0; e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0; e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0; e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0; e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0; e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0; e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0; e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0; e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0; e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0; e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0; e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0; e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0; e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0; e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0; e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0; e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
return e; return e;
} }
@ -238,7 +243,8 @@ public:
v.push_back(columns[12] + " = " + std::to_string(e.slot_id)); v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
v.push_back(columns[13] + " = " + std::to_string(e.char_entity_id)); v.push_back(columns[13] + " = " + std::to_string(e.char_entity_id));
v.push_back(columns[14] + " = " + std::to_string(e.char_zone_id)); v.push_back(columns[14] + " = " + std::to_string(e.char_zone_id));
v.push_back(columns[15] + " = " + std::to_string(e.active_transaction)); v.push_back(columns[15] + " = " + std::to_string(e.char_zone_instance_id));
v.push_back(columns[16] + " = " + std::to_string(e.active_transaction));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
fmt::format( fmt::format(
@ -275,6 +281,7 @@ public:
v.push_back(std::to_string(e.slot_id)); v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id)); v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id)); v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction)); v.push_back(std::to_string(e.active_transaction));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
@ -320,6 +327,7 @@ public:
v.push_back(std::to_string(e.slot_id)); v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id)); v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id)); v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction)); v.push_back(std::to_string(e.active_transaction));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
@ -354,22 +362,23 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
Trader e{}; Trader e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0; e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0; e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0; e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0; e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0; e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0; e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0; e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0; e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0; e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0; e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0; e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0; e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0; e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0; e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0; e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0; e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -394,22 +403,23 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) { for (auto row = results.begin(); row != results.end(); ++row) {
Trader e{}; Trader e{};
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0; e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0; e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0; e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0; e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0; e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0; e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0; e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0; e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0; e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0; e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0; e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0; e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0; e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0; e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0; e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0; e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
all_entries.push_back(e); all_entries.push_back(e);
} }
@ -499,6 +509,7 @@ public:
v.push_back(std::to_string(e.slot_id)); v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id)); v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id)); v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction)); v.push_back(std::to_string(e.active_transaction));
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
@ -537,6 +548,7 @@ public:
v.push_back(std::to_string(e.slot_id)); v.push_back(std::to_string(e.slot_id));
v.push_back(std::to_string(e.char_entity_id)); v.push_back(std::to_string(e.char_entity_id));
v.push_back(std::to_string(e.char_zone_id)); v.push_back(std::to_string(e.char_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction)); v.push_back(std::to_string(e.active_transaction));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");

View File

@ -16,6 +16,7 @@ public:
struct DistinctTraders_Struct { struct DistinctTraders_Struct {
uint32 trader_id; uint32 trader_id;
uint32 zone_id; uint32 zone_id;
uint32 zone_instance_id;
uint32 entity_id; uint32 entity_id;
std::string trader_name; std::string trader_name;
}; };
@ -35,7 +36,8 @@ public:
GetBazaarSearchResults( GetBazaarSearchResults(
SharedDatabase &db, SharedDatabase &db,
BazaarSearchCriteria_Struct search, BazaarSearchCriteria_Struct search,
uint32 char_zone_id uint32 char_zone_id,
int32 char_zone_instance_id
); );
static BulkTraders_Struct GetDistinctTraders(Database &db) static BulkTraders_Struct GetDistinctTraders(Database &db)
@ -44,7 +46,7 @@ public:
std::vector<DistinctTraders_Struct> distinct_traders; std::vector<DistinctTraders_Struct> distinct_traders;
auto results = db.QueryDatabase( auto results = db.QueryDatabase(
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_entity_id, c.name " "SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
"FROM trader AS t " "FROM trader AS t "
"JOIN character_data AS c ON t.char_id = c.id;" "JOIN character_data AS c ON t.char_id = c.id;"
); );
@ -54,10 +56,11 @@ public:
for (auto row: results) { for (auto row: results) {
DistinctTraders_Struct e{}; DistinctTraders_Struct e{};
e.trader_id = Strings::ToInt(row[0]); e.trader_id = Strings::ToInt(row[0]);
e.zone_id = Strings::ToInt(row[1]); e.zone_id = Strings::ToInt(row[1]);
e.entity_id = Strings::ToInt(row[2]); e.zone_instance_id = Strings::ToInt(row[2]);
e.trader_name = row[3] ? row[3] : ""; e.entity_id = Strings::ToInt(row[3]);
e.trader_name = row[4] ? row[4] : "";
all_entries.name_length += e.trader_name.length() + 1; all_entries.name_length += e.trader_name.length() + 1;
all_entries.traders.push_back(e); all_entries.traders.push_back(e);

View File

@ -42,7 +42,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/ */
#define CURRENT_BINARY_DATABASE_VERSION 9285 #define CURRENT_BINARY_DATABASE_VERSION 9286
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
#endif #endif

View File

@ -912,10 +912,6 @@ void Client::CompleteConnect()
CastToClient()->FastQueuePacket(&outapp); CastToClient()->FastQueuePacket(&outapp);
} }
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
SendBulkBazaarTraders();
}
// TODO: load these states // TODO: load these states
// We at least will set them to the correct state for now // We at least will set them to the correct state for now
if (m_ClientVersionBit & EQ::versions::maskUFAndLater && GetPet()) { if (m_ClientVersionBit & EQ::versions::maskUFAndLater && GetPet()) {
@ -3921,6 +3917,10 @@ void Client::Handle_OP_BazaarSearch(const EQApplicationPacket *app)
SendBazaarWelcome(); SendBazaarWelcome();
break; break;
} }
case FirstOpenSearch: {
SendBulkBazaarTraders();
break;
}
default: { default: {
LogError("Malformed BazaarSearch_Struct packet received, ignoring\n"); LogError("Malformed BazaarSearch_Struct packet received, ignoring\n");
} }

View File

@ -1093,15 +1093,16 @@ void Client::TraderStartTrader(const EQApplicationPacket *app)
inst->SetPrice(in->item_cost[i]); inst->SetPrice(in->item_cost[i]);
TraderRepository::Trader trader_item{}; TraderRepository::Trader trader_item{};
trader_item.id = 0; trader_item.id = 0;
trader_item.char_entity_id = GetID(); trader_item.char_entity_id = GetID();
trader_item.char_id = CharacterID(); trader_item.char_id = CharacterID();
trader_item.char_zone_id = GetZoneID(); trader_item.char_zone_id = GetZoneID();
trader_item.item_charges = inst->GetCharges() == 0 ? 1 : inst->GetCharges(); trader_item.char_zone_instance_id = GetInstanceID();
trader_item.item_cost = inst->GetPrice(); trader_item.item_charges = inst->GetCharges() == 0 ? 1 : inst->GetCharges();
trader_item.item_id = inst->GetID(); trader_item.item_cost = inst->GetPrice();
trader_item.item_sn = in->serial_number[i]; trader_item.item_id = inst->GetID();
trader_item.slot_id = i; trader_item.item_sn = in->serial_number[i];
trader_item.slot_id = i;
if (inst->IsAugmented()) { if (inst->IsAugmented()) {
auto augs = inst->GetAugmentIDs(); auto augs = inst->GetAugmentIDs();
trader_item.aug_slot_1 = augs.at(0); trader_item.aug_slot_1 = augs.at(0);
@ -1796,7 +1797,7 @@ void Client::SendBarterWelcome()
void Client::DoBazaarSearch(BazaarSearchCriteria_Struct search_criteria) void Client::DoBazaarSearch(BazaarSearchCriteria_Struct search_criteria)
{ {
auto results = Bazaar::GetSearchResults(database, search_criteria, GetZoneID()); auto results = Bazaar::GetSearchResults(database, search_criteria, GetZoneID(), GetInstanceID());
if (results.empty()) { if (results.empty()) {
SendBazaarDone(GetID()); SendBazaarDone(GetID());
return; return;
@ -2940,9 +2941,11 @@ void Client::SendBecomeTrader(BazaarTraderBarterActions action, uint32 entity_id
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct)); auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct));
auto data = (BecomeTrader_Struct *) outapp->pBuffer; auto data = (BecomeTrader_Struct *) outapp->pBuffer;
data->action = action; data->action = action;
data->entity_id = trader->GetID(); data->entity_id = trader->GetID();
data->trader_id = trader->CharacterID(); data->trader_id = trader->CharacterID();
data->zone_id = trader->GetZoneID();
data->zone_instance_id = trader->GetInstanceID();
strn0cpy(data->trader_name, trader->GetCleanName(), sizeof(data->trader_name)); strn0cpy(data->trader_name, trader->GetCleanName(), sizeof(data->trader_name));
QueuePacket(outapp); QueuePacket(outapp);
@ -3088,14 +3091,15 @@ void Client::TraderPriceUpdate(const EQApplicationPacket *app)
auto item_detail = FindTraderItemBySerialNumber(newgis->serial_number[i]); auto item_detail = FindTraderItemBySerialNumber(newgis->serial_number[i]);
TraderRepository::Trader trader_item{}; TraderRepository::Trader trader_item{};
trader_item.id = 0; trader_item.id = 0;
trader_item.char_entity_id = GetID(); trader_item.char_entity_id = GetID();
trader_item.char_id = CharacterID(); trader_item.char_id = CharacterID();
trader_item.char_zone_id = GetZoneID(); trader_item.char_zone_id = GetZoneID();
trader_item.item_charges = newgis->charges[i]; trader_item.char_zone_instance_id = GetInstanceID();
trader_item.item_cost = tpus->NewPrice; trader_item.item_charges = newgis->charges[i];
trader_item.item_id = newgis->items[i]; trader_item.item_cost = tpus->NewPrice;
trader_item.item_sn = newgis->serial_number[i]; trader_item.item_id = newgis->items[i];
trader_item.item_sn = newgis->serial_number[i];
if (item_detail->IsAugmented()) { if (item_detail->IsAugmented()) {
auto augs = item_detail->GetAugmentIDs(); auto augs = item_detail->GetAugmentIDs();
trader_item.aug_slot_1 = augs.at(0); trader_item.aug_slot_1 = augs.at(0);
@ -3224,7 +3228,8 @@ void Client::SendBulkBazaarTraders()
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, results.count); VARSTRUCT_ENCODE_TYPE(uint32, bufptr, results.count);
for (auto t : results.traders) { for (auto t : results.traders) {
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.zone_id); VARSTRUCT_ENCODE_TYPE(uint16, bufptr, t.zone_id);
VARSTRUCT_ENCODE_TYPE(uint16, bufptr, t.zone_instance_id);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.trader_id); VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.trader_id);
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.entity_id); VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.entity_id);
VARSTRUCT_ENCODE_STRING(bufptr, t.trader_name.c_str()); VARSTRUCT_ENCODE_STRING(bufptr, t.trader_name.c_str());

View File

@ -3929,9 +3929,11 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
out->action = 0; out->action = 0;
} }
} }
out->entity_id = in->entity_id;
out->zone_id = in->zone_id; out->entity_id = in->entity_id;
out->trader_id = in->trader_id; out->zone_id = in->zone_id;
out->zone_instance_id = in->instance_id;
out->trader_id = in->trader_id;
strn0cpy(out->trader_name, in->trader_name, sizeof(out->trader_name)); strn0cpy(out->trader_name, in->trader_name, sizeof(out->trader_name));
c.second->QueuePacket(outapp); c.second->QueuePacket(outapp);