mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-22 11:11:30 +00:00
Start Trader with new unique_id
This commit is contained in:
parent
69cfa3cdbe
commit
868815e658
@ -3780,12 +3780,36 @@ struct Trader2_Struct {
|
|||||||
std::string serial_number[EQ::invtype::BAZAAR_SIZE];
|
std::string serial_number[EQ::invtype::BAZAAR_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClickTrader2_Struct {
|
struct BazaarTraderDetails {
|
||||||
|
uint64 item_id;
|
||||||
|
std::string unique_id;
|
||||||
|
uint64 cost;
|
||||||
|
uint64 serial_number; // backwards compatibility. Not used for RoF2 as of March 2025
|
||||||
|
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(item_id),
|
||||||
|
CEREAL_NVP(unique_id),
|
||||||
|
CEREAL_NVP(cost),
|
||||||
|
CEREAL_NVP(serial_number)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ClickTraderNew_Struct {
|
||||||
uint32 action;
|
uint32 action;
|
||||||
uint32 unknown_004;
|
std::vector<BazaarTraderDetails> items;
|
||||||
uint64 items[EQ::invtype::BAZAAR_SIZE];
|
|
||||||
uint32 item_cost[EQ::invtype::BAZAAR_SIZE];
|
template<class Archive>
|
||||||
std::string serial_number[EQ::invtype::BAZAAR_SIZE];
|
void serialize(Archive &archive)
|
||||||
|
{
|
||||||
|
archive(
|
||||||
|
CEREAL_NVP(action),
|
||||||
|
CEREAL_NVP(items)
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GetItems2_Struct {
|
struct GetItems2_Struct {
|
||||||
|
|||||||
@ -40,6 +40,7 @@ class EvolveInfo; // Stores information about an evolving item family
|
|||||||
#include "../common/deity.h"
|
#include "../common/deity.h"
|
||||||
#include "../common/memory_buffer.h"
|
#include "../common/memory_buffer.h"
|
||||||
#include "../common/repositories/character_evolving_items_repository.h"
|
#include "../common/repositories/character_evolving_items_repository.h"
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
|||||||
@ -6167,30 +6167,31 @@ namespace RoF2
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case structs::RoF2BazaarTraderBuyerActions::BeginTraderMode: {
|
case structs::RoF2BazaarTraderBuyerActions::BeginTraderMode: {
|
||||||
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
DECODE_LENGTH_EXACT(structs::BeginTrader_Struct);
|
||||||
SETUP_DIRECT_DECODE(ClickTrader2_Struct, structs::BeginTrader_Struct);
|
|
||||||
|
unsigned char *eq_buffer = __packet->pBuffer;
|
||||||
|
auto eq = (RoF2::structs::BeginTrader_Struct *) eq_buffer;
|
||||||
|
|
||||||
|
ClickTraderNew_Struct out{};
|
||||||
|
out.action = TraderOn;
|
||||||
|
for (auto i = 0; i < RoF2::invtype::BAZAAR_SIZE; i++) {
|
||||||
|
BazaarTraderDetails btd{};
|
||||||
|
btd.unique_id = eq->item_unique_ids[i].item_unique_id;
|
||||||
|
btd.cost = eq->item_cost[i];
|
||||||
|
out.items.push_back(btd);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss{};
|
||||||
|
cereal::BinaryOutputArchive ar(ss);
|
||||||
|
{
|
||||||
|
ar(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
__packet->size = static_cast<uint32>(ss.str().length());
|
||||||
|
__packet->pBuffer = new unsigned char[__packet->size]{};
|
||||||
|
memcpy(__packet->pBuffer, ss.str().data(), __packet->size);
|
||||||
|
safe_delete_array(eq_buffer);
|
||||||
|
|
||||||
LogTrading("(RoF2) BeginTraderMode action <green>[{}]", action);
|
LogTrading("(RoF2) BeginTraderMode action <green>[{}]", action);
|
||||||
|
|
||||||
emu->action = TraderOn;
|
|
||||||
std::copy_n(eq->item_cost, RoF2::invtype::BAZAAR_SIZE, emu->item_cost);
|
|
||||||
std::transform(
|
|
||||||
std::begin(eq->items),
|
|
||||||
std::end(eq->items),
|
|
||||||
std::begin(emu->serial_number),
|
|
||||||
[&](const structs::TraderItemSerial_Struct x) {
|
|
||||||
return std::string(x.serial_number);
|
|
||||||
});
|
|
||||||
//std::ranges::copy(eq->items->serial_number, emu->serial_number);
|
|
||||||
//std::copy_n(eq->items->serial_number, RoF2::invtype::BAZAAR_SIZE, emu->serial_number);
|
|
||||||
// std::transform(
|
|
||||||
// std::begin(eq->items),
|
|
||||||
// std::end(eq->items),
|
|
||||||
// std::begin(emu->serial_number),
|
|
||||||
// [&](const structs::TraderItemSerial_Struct x) {
|
|
||||||
// return Strings::ToUnsignedBigInt(x.serial_number,0);
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case structs::RoF2BazaarTraderBuyerActions::EndTraderMode: {
|
case structs::RoF2BazaarTraderBuyerActions::EndTraderMode: {
|
||||||
|
|||||||
@ -3554,19 +3554,21 @@ struct WhoAllPlayerPart4 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderItemSerial_Struct {
|
struct TraderItemSerial_Struct {
|
||||||
char serial_number[17];
|
char item_unique_id[17];
|
||||||
uint8 unknown_018;
|
uint8 unknown_018;
|
||||||
|
|
||||||
void operator=(const char* a) {
|
TraderItemSerial_Struct& operator=(const char* a) {
|
||||||
//auto _tmp = fmt::format("{:016}", a);
|
strn0cpy(this->item_unique_id, a, sizeof(this->item_unique_id));
|
||||||
strn0cpy(this->serial_number, a, sizeof(this->serial_number));
|
unknown_018 = 0;
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BeginTrader_Struct {
|
struct BeginTrader_Struct {
|
||||||
/*0000*/ uint32 action;
|
/*0000*/ uint32 action;
|
||||||
/*0004*/ TraderItemSerial_Struct items[200];
|
/*0004*/ TraderItemSerial_Struct item_unique_ids[RoF2::invtype::BAZAAR_SIZE];
|
||||||
/*3604*/ uint32 item_cost[200];
|
/*3604*/ uint32 item_cost[RoF2::invtype::BAZAAR_SIZE];
|
||||||
/*4404*/
|
/*4404*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -374,6 +374,7 @@ public:
|
|||||||
uint16 FindTraderItem(std::string &SerialNumber,uint16 Quantity);
|
uint16 FindTraderItem(std::string &SerialNumber,uint16 Quantity);
|
||||||
uint32 FindTraderItemSerialNumber(int32 ItemID);
|
uint32 FindTraderItemSerialNumber(int32 ItemID);
|
||||||
EQ::ItemInstance* FindTraderItemBySerialNumber(std::string &serial_number);
|
EQ::ItemInstance* FindTraderItemBySerialNumber(std::string &serial_number);
|
||||||
|
EQ::ItemInstance* FindTraderItemByUniqueID(std::string &unique_id);
|
||||||
void FindAndNukeTraderItem(std::string &serial_number, int16 quantity, Client* customer, uint16 trader_slot);
|
void FindAndNukeTraderItem(std::string &serial_number, int16 quantity, Client* customer, uint16 trader_slot);
|
||||||
void NukeTraderItem(uint16 slot, int16 charges, int16 quantity, Client* customer, uint16 trader_slot, const std::string &serial_number, int32 item_id = 0);
|
void NukeTraderItem(uint16 slot, int16 charges, int16 quantity, Client* customer, uint16 trader_slot, const std::string &serial_number, int32 item_id = 0);
|
||||||
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
||||||
|
|||||||
113
zone/trading.cpp
113
zone/trading.cpp
@ -782,23 +782,6 @@ void Client::TraderShowItems()
|
|||||||
auto outapp = new EQApplicationPacket(OP_Trader, packet_size);
|
auto outapp = new EQApplicationPacket(OP_Trader, packet_size);
|
||||||
|
|
||||||
memcpy(outapp->pBuffer, ss.str().data(), packet_size);
|
memcpy(outapp->pBuffer, ss.str().data(), packet_size);
|
||||||
// // uint32 item_limit = trader_items.size() >= GetInv().GetLookup()->InventoryTypeSize.Bazaar ?
|
|
||||||
// // GetInv().GetLookup()->InventoryTypeSize.Bazaar :
|
|
||||||
// // trader_items.size();
|
|
||||||
// uint32 item_limit = GetInv().GetLookup()->InventoryTypeSize.Bazaar;
|
|
||||||
// //FIX
|
|
||||||
//
|
|
||||||
// for (int i = 0; i < trader_items.size(); i++) {
|
|
||||||
// data->items[i].cost = trader_items.at(i).item_cost;
|
|
||||||
// strn0cpy(data->items[i].sn, trader_items.at(i).item_sn.data(), sizeof(data->items[i].sn[i]));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for (int i = trader_items.size(); i < item_limit; i++) {
|
|
||||||
// data->items[i].cost = 0;
|
|
||||||
// strn0cpy(data->items[i].sn, "0000000000000000", sizeof(data->items[i].sn));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// data->action = ListTraderItems;
|
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@ -841,40 +824,20 @@ void Client::Trader_CustomerBrowsing(Client *Customer)
|
|||||||
void Client::TraderStartTrader(const EQApplicationPacket *app)
|
void Client::TraderStartTrader(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
uint32 max_items = GetInv().GetLookup()->InventoryTypeSize.Bazaar;
|
uint32 max_items = GetInv().GetLookup()->InventoryTypeSize.Bazaar;
|
||||||
auto in = (ClickTrader2_Struct *) app->pBuffer;
|
|
||||||
auto inv = GetTraderItems();
|
auto inv = GetTraderItems();
|
||||||
bool trade_items_valid = true;
|
bool trade_items_valid = true;
|
||||||
std::vector<TraderRepository::Trader> trader_items{};
|
std::vector<TraderRepository::Trader> trader_items{};
|
||||||
|
ClickTraderNew_Struct in;
|
||||||
|
|
||||||
//Check inventory for no-trade items
|
EQ::Util::MemoryStreamReader ss(reinterpret_cast<char *>(app->pBuffer), app->size);
|
||||||
// for (auto i = 0; i < max_items; i++) {
|
cereal::BinaryInputArchive ar(ss);
|
||||||
// if (inv->items[i] == 0 || inv->serial_number[i].empty()) {
|
{
|
||||||
// continue;
|
ar(in);
|
||||||
// }
|
|
||||||
//
|
|
||||||
// auto inst = FindTraderItemBySerialNumber(inv->serial_number[i]);
|
|
||||||
// if (inst) {
|
|
||||||
// if (inst->GetItem() && inst->GetItem()->NoDrop == 0) {
|
|
||||||
// Message(
|
|
||||||
// Chat::Red,
|
|
||||||
// fmt::format(
|
|
||||||
// "Item: {} is NODROP and found in a Trader's Satchel. Please remove and restart trader mode",
|
|
||||||
// inst->GetItem()->Name
|
|
||||||
// ).c_str()
|
|
||||||
// );
|
|
||||||
// TraderEndTrader();
|
|
||||||
// safe_delete(inv);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < max_items; i++) {
|
|
||||||
if (inv->items[i] == 0 || inv->serial_number[i].empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const inst = FindTraderItemBySerialNumber(inv->serial_number[i]);
|
uint32 slot_id = 0;
|
||||||
|
for (auto &i: in.items) {
|
||||||
|
auto const inst = FindTraderItemByUniqueID(i.unique_id);
|
||||||
if (!inst) {
|
if (!inst) {
|
||||||
trade_items_valid = false;
|
trade_items_valid = false;
|
||||||
break;
|
break;
|
||||||
@ -886,18 +849,14 @@ void Client::TraderStartTrader(const EQApplicationPacket *app)
|
|||||||
Chat::Red,
|
Chat::Red,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"Item: {} is NODROP and found in a Trader's Satchel. Please remove and restart trader mode",
|
"Item: {} is NODROP and found in a Trader's Satchel. Please remove and restart trader mode",
|
||||||
inst->GetItem()->Name
|
inst->GetItem()->Name)
|
||||||
).c_str()
|
.c_str());
|
||||||
);
|
|
||||||
TraderEndTrader();
|
TraderEndTrader();
|
||||||
safe_delete(inv);
|
safe_delete(inv);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = std::find(std::begin(in->serial_number), std::end(in->serial_number), inv->serial_number[i]);
|
|
||||||
if (inst && it != std::end(in->serial_number)) {
|
|
||||||
inst->SetPrice(in->item_cost[i]);
|
|
||||||
TraderRepository::Trader trader_item{};
|
TraderRepository::Trader trader_item{};
|
||||||
|
|
||||||
trader_item.id = 0;
|
trader_item.id = 0;
|
||||||
@ -906,10 +865,10 @@ void Client::TraderStartTrader(const EQApplicationPacket *app)
|
|||||||
trader_item.char_zone_id = GetZoneID();
|
trader_item.char_zone_id = GetZoneID();
|
||||||
trader_item.char_zone_instance_id = GetInstanceID();
|
trader_item.char_zone_instance_id = GetInstanceID();
|
||||||
trader_item.item_charges = inst->GetCharges() == 0 ? 1 : inst->GetCharges();
|
trader_item.item_charges = inst->GetCharges() == 0 ? 1 : inst->GetCharges();
|
||||||
trader_item.item_cost = inst->GetPrice();
|
trader_item.item_cost = i.cost;
|
||||||
trader_item.item_id = inst->GetID();
|
trader_item.item_id = inst->GetID();
|
||||||
trader_item.item_sn = in->serial_number[i];
|
trader_item.item_sn = i.unique_id;
|
||||||
trader_item.slot_id = i;
|
trader_item.slot_id = slot_id;
|
||||||
trader_item.listing_date = time(nullptr);
|
trader_item.listing_date = time(nullptr);
|
||||||
if (inst->IsAugmented()) {
|
if (inst->IsAugmented()) {
|
||||||
auto augs = inst->GetAugmentIDs();
|
auto augs = inst->GetAugmentIDs();
|
||||||
@ -922,22 +881,9 @@ void Client::TraderStartTrader(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
trader_items.emplace_back(trader_item);
|
trader_items.emplace_back(trader_item);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (inst) {
|
|
||||||
Message(
|
|
||||||
Chat::Red,
|
|
||||||
fmt::format(
|
|
||||||
"Item: {} has no price set. Please set a price and try again.",
|
|
||||||
inst->GetItem()->Name
|
|
||||||
).c_str()
|
|
||||||
);
|
|
||||||
trade_items_valid = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!trade_items_valid) {
|
if (!trade_items_valid || trader_items.empty()) {
|
||||||
Message(Chat::Red, "You are not able to become a trader at this time. Invalid item found.");
|
Message(Chat::Red, "You are not able to become a trader at this time. Invalid item found.");
|
||||||
TraderEndTrader();
|
TraderEndTrader();
|
||||||
safe_delete(inv);
|
safe_delete(inv);
|
||||||
@ -1105,7 +1051,7 @@ uint32 Client::FindTraderItemSerialNumber(int32 ItemID) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EQ::ItemInstance *Client::FindTraderItemBySerialNumber(std::string &serial_number)
|
EQ::ItemInstance *Client::FindTraderItemBySerialNumber(std::string &unique_id)
|
||||||
{
|
{
|
||||||
EQ::ItemInstance *item = nullptr;
|
EQ::ItemInstance *item = nullptr;
|
||||||
int16 slot_id = 0;
|
int16 slot_id = 0;
|
||||||
@ -1118,7 +1064,7 @@ EQ::ItemInstance *Client::FindTraderItemBySerialNumber(std::string &serial_numbe
|
|||||||
slot_id = EQ::InventoryProfile::CalcSlotId(i, x);
|
slot_id = EQ::InventoryProfile::CalcSlotId(i, x);
|
||||||
item = GetInv().GetItem(slot_id);
|
item = GetInv().GetItem(slot_id);
|
||||||
if (item) {
|
if (item) {
|
||||||
if (item->GetUniqueID().compare(serial_number) == 0) {
|
if (item->GetUniqueID().compare(unique_id) == 0) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1126,11 +1072,36 @@ EQ::ItemInstance *Client::FindTraderItemBySerialNumber(std::string &serial_numbe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogTrading("Couldn't find item! Serial No. was [{}]", serial_number);
|
LogTrading("Couldn't find item! Serial No. was [{}]", unique_id);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EQ::ItemInstance *Client::FindTraderItemByUniqueID(std::string &unique_id)
|
||||||
|
{
|
||||||
|
EQ::ItemInstance *item = nullptr;
|
||||||
|
int16 slot_id = 0;
|
||||||
|
|
||||||
|
for (int16 i = EQ::invslot::GENERAL_BEGIN; i <= EQ::invslot::GENERAL_END; i++) {
|
||||||
|
item = GetInv().GetItem(i);
|
||||||
|
if (item && item->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) {
|
||||||
|
for (int16 x = EQ::invbag::SLOT_BEGIN; x <= EQ::invbag::SLOT_END; x++) {
|
||||||
|
// we already have the parent bag and a contents iterator..why not just iterate the bag!??
|
||||||
|
slot_id = EQ::InventoryProfile::CalcSlotId(i, x);
|
||||||
|
item = GetInv().GetItem(slot_id);
|
||||||
|
if (item) {
|
||||||
|
if (item->GetUniqueID().compare(unique_id) == 0) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogTrading("Couldn't find item! Serial No. was [{}]", unique_id);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
GetItems2_Struct *Client::GetTraderItems()
|
GetItems2_Struct *Client::GetTraderItems()
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user