diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index dac02de2c..bcd8f1ad7 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -3729,13 +3729,34 @@ struct Trader_Struct { /*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE]; }; -struct Trader3_Struct { +struct TraderItems_Struct { + std::string serial_number; + uint32 item_id; + uint64 item_cost; + + template + void serialize(Archive &archive) + { + archive( + CEREAL_NVP(serial_number), + CEREAL_NVP(item_id), + CEREAL_NVP(item_cost) + ); + } +}; + +struct TraderClientMessaging_Struct { /*000*/ uint32 action; - /*004*/ uint32 unknown_004; - ///*008*/ uint64 items[EQ::invtype::BAZAAR_SIZE]; - /*008*/ char serial_number[17][EQ::invtype::BAZAAR_SIZE]; - char unknown[1]{}; - /*648*/ uint32 item_cost[EQ::invtype::BAZAAR_SIZE]; + /*008*/ std::vector items; + + template + void serialize(Archive &archive) + { + archive( + CEREAL_NVP(action), + CEREAL_NVP(items) + ); + } }; struct ClickTrader_Struct { diff --git a/common/item_instance.cpp b/common/item_instance.cpp index 5aadebf63..e401511fa 100644 --- a/common/item_instance.cpp +++ b/common/item_instance.cpp @@ -160,6 +160,7 @@ EQ::ItemInstance::ItemInstance(const ItemInstance& copy) m_serial_number2 = copy.m_serial_number2; if (copy.GetSerialNumber2().empty()) { + LogError("Creating Serial Number as part of Clone command"); CreateSerialNumber2(); } diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index e3aaa977d..7fba9c3f6 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -4115,27 +4115,37 @@ namespace RoF2 break; } case ListTraderItems: { - ENCODE_LENGTH_EXACT(Trader3_Struct); - SETUP_DIRECT_ENCODE(Trader3_Struct, structs::ClickTrader_Struct); LogTrading("(RoF2) action [{}]", action); - eq->action = structs::RoF2BazaarTraderBuyerActions::ListTraderItems; - std::transform( - std::begin(emu->serial_number), - std::end(emu->serial_number), - std::begin(eq->items), - [&](const char* x) { - return x; - } - ); -// std::ranges::copy(emu->serial_number, eq->items.begin(), eq->items.end()); - std::copy_n( - std::begin(emu->item_cost), - EQ::invtype::BAZAAR_SIZE, - std::begin(eq->item_cost) - ); + EQApplicationPacket *in = *p; + *p = nullptr; - FINISH_ENCODE(); + TraderClientMessaging_Struct tcm{}; + EQ::Util::MemoryStreamReader ss(reinterpret_cast(in->pBuffer), in->size); + cereal::BinaryInputArchive ar(ss); + { ar(tcm); } + + auto buffer = new char[4404]{}; //4404 is the fixed size of the packet for 200 item limit of RoF2 + auto pos = buffer; + + VARSTRUCT_ENCODE_TYPE(uint32, pos, structs::RoF2BazaarTraderBuyerActions::ListTraderItems); + for (auto const &t: tcm.items) { + strn0cpy(pos, t.serial_number.data(), t.serial_number.length() + 1); + pos += 3600; + VARSTRUCT_ENCODE_TYPE(uint32, pos, t.item_cost); + pos -= 3604 - 18; + } + + for (int i = tcm.items.size(); i < EQ::invtype::BAZAAR_SIZE; i++) { + strn0cpy(pos, "0000000000000000", 18); + pos += 18; + } + + safe_delete_array(in->pBuffer); + in->pBuffer = reinterpret_cast(buffer); + in->size = 4404; + + dest->FastQueuePacket(&in); break; } case TraderAck2: { diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 1c2b62c4f..839cfa784 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -650,6 +650,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, // put item into inventory if (to_slot == EQ::invslot::slotCursor) { + inst->CreateSerialNumber2(); PushItemOnCursor(*inst); SendItemPacket(EQ::invslot::slotCursor, inst, ItemPacketLimbo); } else { diff --git a/zone/trading.cpp b/zone/trading.cpp index 2b902153a..9defe0709 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -756,20 +756,49 @@ bool Client::CheckTradeNonDroppable() void Client::TraderShowItems() { - auto outapp = new EQApplicationPacket(OP_Trader, sizeof(Trader3_Struct)); - auto data = (Trader3_Struct *) outapp->pBuffer; + std::stringstream ss{}; + cereal::BinaryOutputArchive ar(ss); - auto trader_items = TraderRepository::GetWhere(database, fmt::format("`char_id` = '{}'", CharacterID())); - uint32 item_limit = trader_items.size() >= GetInv().GetLookup()->InventoryTypeSize.Bazaar ? - GetInv().GetLookup()->InventoryTypeSize.Bazaar : - trader_items.size(); - //FIX - for (int i = 0; i < item_limit; i++) { - data->item_cost[i] = trader_items.at(i).item_cost; - strn0cpy(data->serial_number[i], trader_items.at(i).item_sn.data(), sizeof(data->serial_number[i])); + auto trader_items = TraderRepository::GetWhere(database, fmt::format("`char_id` = '{}'", CharacterID())); + if (trader_items.empty()) { + return; } - data->action = ListTraderItems; + TraderClientMessaging_Struct tcm{}; + tcm.action = ListTraderItems; + + for (auto const &t: trader_items) { + TraderItems_Struct items{}; + items.serial_number = t.item_sn; + items.item_id = t.item_id; + items.item_cost = t.item_cost; + + tcm.items.push_back(items); + } + + { ar(tcm); } + + uint32 packet_size = ss.str().length(); + auto outapp = new EQApplicationPacket(OP_Trader, 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); safe_delete(outapp);