New BazaarSearch query routine

This commit is contained in:
Mitch Freeman 2025-04-13 09:48:38 -03:00
parent 8f79ce25de
commit 116040914c
7 changed files with 165 additions and 50 deletions

View File

@ -262,39 +262,78 @@ Bazaar::GetSearchResults(
} }
std::vector<BazaarSearchResultsFromDB_Struct> all_entries; std::vector<BazaarSearchResultsFromDB_Struct> all_entries;
std::vector<std::string> trader_items_ids{}; std::unordered_set<std::string> trader_items_ids{};
auto const trader_results = TraderRepository::GetBazaarTraderDetails(db, search_criteria_trader); // auto const trader_results = TraderRepository::GetBazaarTraderDetails(db, search_criteria_trader, search.max_results);
if (trader_results.empty()) { auto const item_results = TraderRepository::GetBazaarTraderDetails(
LogTradingDetail("Bazaar - No traders found in bazaar search."); db,
return all_entries; search_criteria_trader,
} search.item_name,
for (auto const &i: trader_results) {
trader_items_ids.push_back(std::to_string(i.trader.item_id));
}
auto const item_results = ItemsRepository::GetItemsForBazaarSearch(
content_db,
trader_items_ids,
std::string(search.item_name),
field_criteria_items, field_criteria_items,
where_criteria_items, where_criteria_items,
search.max_results search.max_results
); );
// if (trader_results.empty()) {
// LogTradingDetail("Bazaar - No traders found in bazaar search.");
// return all_entries;
// }
// for (auto const &i: trader_results) {
// trader_items_ids.emplace(std::to_string(i.trader.item_id));
// //trader_items_ids.push_back(std::to_string(i.trader.item_id));
// }
// auto const item_results = ItemsRepository::GetItemsForBazaarSearch(
// content_db,
// trader_items_ids,
// std::string(search.item_name),
// field_criteria_items,
// where_criteria_items,
// search.max_results
// );
if (item_results.empty()) { if (item_results.empty()) {
LogTradingDetail("Bazaar - No items found in bazaar search."); LogTradingDetail("Bazaar - No items found in bazaar search.");
return all_entries; return all_entries;
} }
all_entries.reserve(trader_results.size()); //all_entries.reserve(trader_results.size());
for (auto const& t:trader_results) { // for (auto const& t:trader_results) {
if (!item_results.contains(t.trader.item_id)) { // if (!item_results.contains(t.trader.item_id)) {
continue; // continue;
} // }
//
// BazaarSearchResultsFromDB_Struct r{};
// r.count = 1;
// r.trader_id = t.trader.character_id;
// r.item_unique_id = t.trader.item_unique_id;
// r.cost = t.trader.item_cost;
// r.slot_id = t.trader.slot_id;
// r.charges = t.trader.item_charges;
// r.stackable = item_results.at(t.trader.item_id).stackable;
// r.icon_id = item_results.at(t.trader.item_id).icon;
// r.trader_zone_id = t.trader.char_zone_id;
// r.trader_zone_instance_id = t.trader.char_zone_instance_id;
// r.trader_entity_id = t.trader.char_entity_id;
// r.item_name = fmt::format("{:.63}\0", item_results.at(t.trader.item_id).name);
// r.trader_name = fmt::format("{:.63}\0", t.trader_name);
// r.item_stat = item_results.at(t.trader.item_id).stats;
//
// if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
// if (convert ||
// char_zone_id != Zones::BAZAAR ||
// (char_zone_id == Zones::BAZAAR && r.trader_zone_instance_id != char_zone_instance_id)
// ) {
// r.trader_id = TraderRepository::TRADER_CONVERT_ID + r.trader_zone_instance_id;
// }
// }
//
// all_entries.push_back(r);
// }
for (auto const& t:item_results) {
BazaarSearchResultsFromDB_Struct r{}; BazaarSearchResultsFromDB_Struct r{};
r.count = 1; r.count = 1;
r.trader_id = t.trader.character_id; r.trader_id = t.trader.character_id;
@ -302,14 +341,14 @@ Bazaar::GetSearchResults(
r.cost = t.trader.item_cost; r.cost = t.trader.item_cost;
r.slot_id = t.trader.slot_id; r.slot_id = t.trader.slot_id;
r.charges = t.trader.item_charges; r.charges = t.trader.item_charges;
r.stackable = item_results.at(t.trader.item_id).stackable; r.stackable = t.stackable;
r.icon_id = item_results.at(t.trader.item_id).icon; r.icon_id = t.icon;
r.trader_zone_id = t.trader.char_zone_id; r.trader_zone_id = t.trader.char_zone_id;
r.trader_zone_instance_id = t.trader.char_zone_instance_id; r.trader_zone_instance_id = t.trader.char_zone_instance_id;
r.trader_entity_id = t.trader.char_entity_id; r.trader_entity_id = t.trader.char_entity_id;
r.item_name = fmt::format("{:.63}\0", item_results.at(t.trader.item_id).name); r.item_name = fmt::format("{:.63}\0", t.name);
r.trader_name = fmt::format("{:.63}\0", t.trader_name); r.trader_name = fmt::format("{:.63}\0", t.trader_name);
r.item_stat = item_results.at(t.trader.item_id).stats; r.item_stat = t.stats;
if (RuleB(Bazaar, UseAlternateBazaarSearch)) { if (RuleB(Bazaar, UseAlternateBazaarSearch)) {
if (convert || if (convert ||
@ -323,9 +362,9 @@ Bazaar::GetSearchResults(
all_entries.push_back(r); all_entries.push_back(r);
} }
if (all_entries.size() > search.max_results) { // if (all_entries.size() > search.max_results) {
all_entries.resize(search.max_results); // all_entries.resize(search.max_results);
} // }
LogTrading("Returning [{}] items from search results", all_entries.size()); LogTrading("Returning [{}] items from search results", all_entries.size());

View File

@ -47,7 +47,7 @@ public:
static std::unordered_map<uint32, Bazaar_Results> GetItemsForBazaarSearch( static std::unordered_map<uint32, Bazaar_Results> GetItemsForBazaarSearch(
Database& db, Database& db,
const std::vector<std::string> &search_ids, const std::unordered_set<std::string> &search_ids,
const std::string &name, const std::string &name,
const std::string &field_criteria_items, const std::string &field_criteria_items,
const std::string &where_criteria_items, const std::string &where_criteria_items,
@ -57,7 +57,7 @@ public:
auto query = fmt::format( auto query = fmt::format(
"SELECT id, name, stackable, icon, {} " "SELECT id, name, stackable, icon, {} "
"FROM items " "FROM items "
"WHERE `name` LIKE '%%{}%%' AND {} AND id IN({}) " "WHERE `name` LIKE '%{}%' AND {} AND id IN({}) "
"ORDER BY id ASC", "ORDER BY id ASC",
field_criteria_items, field_criteria_items,
Strings::Escape(name), Strings::Escape(name),

View File

@ -29,8 +29,12 @@ public:
}; };
struct BazaarTraderSearch_Struct { struct BazaarTraderSearch_Struct {
Trader trader; Trader trader;
std::string trader_name; std::string trader_name;
std::string name;
bool stackable;
uint32 icon;
uint32 stats;
}; };
struct WelcomeData_Struct { struct WelcomeData_Struct {
@ -296,22 +300,50 @@ public:
static std::vector<BazaarTraderSearch_Struct> GetBazaarTraderDetails( static std::vector<BazaarTraderSearch_Struct> GetBazaarTraderDetails(
Database &db, Database &db,
std::string &search_criteria_trader const std::string &search_criteria_trader,
const std::string &name,
const std::string &field_criteria_items,
const std::string &where_criteria_items,
uint32 max_results
) )
{ {
std::vector<BazaarTraderSearch_Struct> all_entries{}; std::vector<BazaarTraderSearch_Struct> all_entries{};
auto query = fmt::format( auto query_2 = fmt::format(
"WITH ranked_trader_items AS ("
"SELECT trader.id, trader.character_id, trader.item_id, trader.item_unique_id, trader.augment_one, " "SELECT trader.id, trader.character_id, trader.item_id, trader.item_unique_id, trader.augment_one, "
"trader.augment_two, trader.augment_three, trader.augment_four, trader.augment_five, trader.augment_six, " "trader.augment_two, trader.augment_three, trader.augment_four, trader.augment_five, trader.augment_six, "
"trader.item_charges, trader.item_cost, trader.slot_id, trader.char_entity_id, trader.char_zone_id, " "trader.item_charges, trader.item_cost, trader.slot_id, trader.char_entity_id, trader.char_zone_id, "
"trader.char_zone_instance_id, trader.active_transaction, c.`name` FROM `trader` " "trader.char_zone_instance_id, trader.active_transaction, c.`name`, "
"items.name AS n1, items.stackable, items.icon, {}, "
"ROW_NUMBER() OVER (PARTITION BY trader.character_id) AS row_num "
"FROM trader "
"INNER JOIN character_data AS c ON trader.character_id = c.id " "INNER JOIN character_data AS c ON trader.character_id = c.id "
"WHERE {} ORDER BY trader.character_id ASC", "JOIN peq642024_content.items AS items ON trader.item_id = items.id "
search_criteria_trader "WHERE items.`name` LIKE '%{}%' AND {} AND {}"
") "
"SELECT * FROM ranked_trader_items "
"WHERE row_num <= '{}';",
field_criteria_items,
Strings::Escape(name),
where_criteria_items,
search_criteria_trader,
max_results
); );
auto results = db.QueryDatabase(query); // auto query = fmt::format(
// "SELECT trader.id, trader.character_id, trader.item_id, trader.item_unique_id, trader.augment_one, "
// "trader.augment_two, trader.augment_three, trader.augment_four, trader.augment_five, trader.augment_six, "
// "trader.item_charges, trader.item_cost, trader.slot_id, trader.char_entity_id, trader.char_zone_id, "
// "trader.char_zone_instance_id, trader.active_transaction, c.`name` FROM `trader` "
// "INNER JOIN character_data AS c ON trader.character_id = c.id "
// "WHERE {} "
// "GROUP BY trader.item_id "
// "ORDER BY trader.character_id ASC",
// search_criteria_trader
// );
auto results = db.QueryDatabase(query_2);
if (results.RowCount() == 0) { if (results.RowCount() == 0) {
return all_entries; return all_entries;
@ -339,6 +371,10 @@ public:
e.trader.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0; e.trader.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
e.trader.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0; e.trader.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
e.trader_name = row[17] ? row[17] : std::string(""); e.trader_name = row[17] ? row[17] : std::string("");
e.name = row[18] ? row[18] : "";
e.stackable = atoi(row[19]) ? true : false;
e.icon = row[20] ? static_cast<int32_t>(atoi(row[20])) : 0;
e.stats = row[21] ? static_cast<int32_t>(atoi(row[21])) : 0;
all_entries.push_back(e); all_entries.push_back(e);
} }

View File

@ -970,3 +970,22 @@ bool Strings::IsValidJson(const std::string &json)
return result; return result;
} }
std::string Strings::Implode(const std::string& glue, std::unordered_set<std::string> src)
{
if (src.empty()) {
return {};
}
std::ostringstream output;
std::unordered_set<std::string>::iterator src_iter;
for (src_iter = src.begin(); src_iter != src.end(); src_iter++) {
output << *src_iter << glue;
}
std::string final_output = output.str();
final_output.resize(output.str().size() - glue.size());
return final_output;
}

View File

@ -42,6 +42,7 @@
#include <vector> #include <vector>
#include <cstdarg> #include <cstdarg>
#include <type_traits> #include <type_traits>
#include <unordered_set>
#ifdef _WIN32 #ifdef _WIN32
#include <ctype.h> #include <ctype.h>
@ -79,6 +80,7 @@ public:
static std::string Escape(const std::string &s); static std::string Escape(const std::string &s);
static std::string GetBetween(const std::string &s, std::string start_delim, std::string stop_delim); static std::string GetBetween(const std::string &s, std::string start_delim, std::string stop_delim);
static std::string Implode(const std::string& glue, std::vector<std::string> src); static std::string Implode(const std::string& glue, std::vector<std::string> src);
static std::string Implode(const std::string& glue, std::unordered_set<std::string> src);
static std::string Join(const std::vector<std::string> &ar, const std::string &delim); static std::string Join(const std::vector<std::string> &ar, const std::string &delim);
static std::string Join(const std::vector<uint32_t> &ar, const std::string &delim); static std::string Join(const std::vector<uint32_t> &ar, const std::string &delim);
static std::string MillisecondsToTime(int duration); static std::string MillisecondsToTime(int duration);

View File

@ -15456,7 +15456,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
break; break;
} }
default: { default: {
LogTrading("Unknown size for OP_Trader: [{}]\n", app->size); //LogTradingDetail("Unknown size for OP_Trader: [{}]", app->size);
} }
} }
} }

View File

@ -1399,8 +1399,20 @@ static void BazaarAuditTrail(const char *seller, const char *buyer, const char *
void Client::BuyTraderItem(const EQApplicationPacket *app) void Client::BuyTraderItem(const EQApplicationPacket *app)
{ {
auto in = reinterpret_cast<TraderBuy_Struct *>(app->pBuffer); struct Checks {
auto trader = entity_list.GetClientByID(in->trader_id); bool take_customer_money {false};
bool give_trader_money {false};
bool give_customer_item {false};
bool take_trader_item {false};
uint64 customer_money {false};
uint64 trader_money {false};
EQ::ItemInstance *trader_item {nullptr};
EQ::ItemInstance *customer_item {nullptr};
};
Checks checks{};
auto in = reinterpret_cast<TraderBuy_Struct *>(app->pBuffer);
auto trader = entity_list.GetClientByID(in->trader_id);
if (!trader || !trader->IsTrader()) { if (!trader || !trader->IsTrader()) {
Message(Chat::Red, "The trader could not be found."); Message(Chat::Red, "The trader could not be found.");
@ -1436,6 +1448,8 @@ void Client::BuyTraderItem(const EQApplicationPacket *app)
if (CheckLoreConflict(inst_copy->GetItem())) { if (CheckLoreConflict(inst_copy->GetItem())) {
MessageString(Chat::Red, DUPLICATE_LORE); MessageString(Chat::Red, DUPLICATE_LORE);
in->method = BazaarByParcel;
in->sub_action = DataOutDated;
TradeRequestFailed(app); TradeRequestFailed(app);
return; return;
} }
@ -1474,6 +1488,7 @@ void Client::BuyTraderItem(const EQApplicationPacket *app)
TradeRequestFailed(app); TradeRequestFailed(app);
return; return;
} }
checks.take_customer_money = true;
if (!trader->RemoveItemByItemUniqueId(buy_inst->GetUniqueID(), quantity)) { if (!trader->RemoveItemByItemUniqueId(buy_inst->GetUniqueID(), quantity)) {
AddMoneyToPP(total_cost, true); AddMoneyToPP(total_cost, true);
@ -1481,8 +1496,10 @@ void Client::BuyTraderItem(const EQApplicationPacket *app)
TradeRequestFailed(app); TradeRequestFailed(app);
return; return;
} }
checks.take_trader_item = true;
trader->AddMoneyToPP(total_cost, true); trader->AddMoneyToPP(total_cost, true);
checks.give_trader_money = true;
if (!PutItemInInventoryWithStacking(inst_copy.get())) { if (!PutItemInInventoryWithStacking(inst_copy.get())) {
AddMoneyToPP(total_cost, true); AddMoneyToPP(total_cost, true);
@ -1492,6 +1509,7 @@ void Client::BuyTraderItem(const EQApplicationPacket *app)
TradeRequestFailed(app); TradeRequestFailed(app);
return; return;
} }
checks.give_customer_item = true;
auto [slot_id, merchant_data] = GetDataFromMerchantListByItemUniqueId(buy_inst->GetUniqueID()); auto [slot_id, merchant_data] = GetDataFromMerchantListByItemUniqueId(buy_inst->GetUniqueID());
auto [item_id, merchant_quantity, item_unique_id] = merchant_data; auto [item_id, merchant_quantity, item_unique_id] = merchant_data;
@ -2576,21 +2594,22 @@ void Client::TraderUpdateItem(const EQApplicationPacket *app)
} }
} }
else { else {
for (auto const i : result) { if (customer) {
auto [slot_id, merchant_data] = customer->GetDataFromMerchantListByItemUniqueId(i.item_unique_id); for (auto const i : result) {
auto [item_id, merchant_quantity, item_unique_id] = merchant_data; auto [slot_id, merchant_data] = customer->GetDataFromMerchantListByItemUniqueId(i.item_unique_id);
std::unique_ptr<EQ::ItemInstance> vendor_inst_copy(inst ? inst->Clone() : nullptr); auto [item_id, merchant_quantity, item_unique_id] = merchant_data;
vendor_inst_copy->SetUniqueID(i.item_unique_id); std::unique_ptr<EQ::ItemInstance> vendor_inst_copy(inst ? inst->Clone() : nullptr);
vendor_inst_copy->SetMerchantCount(i.item_charges); vendor_inst_copy->SetUniqueID(i.item_unique_id);
vendor_inst_copy->SetMerchantSlot(slot_id); vendor_inst_copy->SetMerchantCount(i.item_charges);
vendor_inst_copy->SetPrice(new_price); vendor_inst_copy->SetMerchantSlot(slot_id);
customer->SendItemPacket(slot_id, vendor_inst_copy.get(), ItemPacketMerchant); vendor_inst_copy->SetPrice(new_price);
} customer->SendItemPacket(slot_id, vendor_inst_copy.get(), ItemPacketMerchant);
}
customer->Message( customer->Message(
Chat::Red, Chat::Red,
fmt::format("Trader {} updated the price of item {}", GetCleanName(), inst->GetItem()->Name).c_str() fmt::format("Trader {} updated the price of item {}", GetCleanName(), inst->GetItem()->Name).c_str()
); );
}
} }
in->sub_action = BazaarPriceChange_UpdatePrice; in->sub_action = BazaarPriceChange_UpdatePrice;