diff --git a/changelog.txt b/changelog.txt index 1bc585aa1..402ef67de 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 05/10/2016 == +Uleat: Converted client translators' 'SerializeItem()' to recursive, single buffer methodology. Titanium SerializeItem() now adds a null term between parent items instead of the invoking function + == 05/08/2016 == Uleat: Re-coded Titanium client translator 'SerializeItem()' to use coded property assignments over file enumerated ones diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 2fb93343a..49e644412 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -24,7 +24,7 @@ namespace RoF static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id, uint8 depth); // server to client inventory location converters static inline structs::InventorySlot_Struct ServerToRoFSlot(uint32 serverSlot); @@ -531,70 +531,52 @@ namespace RoF ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { - + if (!in->size) { in->size = 4; in->pBuffer = new uchar[in->size]; - - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); delete in; - return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + InternalSerializedItem_Struct* eq = (InternalSerializedItem_Struct*)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - for (int r = 0; r < ItemCount; r++, eq++) { + ss.write((const char*)&item_count, sizeof(uint32)); - uint32 Length = 0; + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ss, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ss.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); - - if (Serialized) { - - uchar *OldBuffer = in->pBuffer; - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ss.tellp(); } - delete[] __emu_buffer; + std::string serialized = ss.str(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); + + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -1505,29 +1487,37 @@ namespace RoF ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; + //ItemPacket_Struct* old_item_pkt = (ItemPacket_Struct*)__emu_buffer; + //InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(old_item_pkt->SerializedItem); + InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(&__emu_buffer[4]); - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - if (!serialized) { + ss.write((const char*)__emu_buffer, 4); + + SerializeItem(ss, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ss.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + + std::string serialized = ss.str(); + + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + //ItemPacket_Struct* new_item_pkt = (ItemPacket_Struct*)in->pBuffer; + //new_item_pkt->PacketType = old_item_pkt->PacketType; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -5190,53 +5180,43 @@ namespace RoF return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); - + RoF::structs::ItemSerializationHeader hdr; //sprintf(hdr.unknown000, "06e0002Y1W00"); snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID); - hdr.stacksize = stackable ? charges : 1; + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; structs::InventorySlot_Struct slot_id = ServerToRoFSlot(slot_id_in); - hdr.slot_type = (merchant_slot == 0) ? slot_id.Type : 9; // 9 is merchant 20 is reclaim items? - hdr.main_slot = (merchant_slot == 0) ? slot_id.Slot : merchant_slot; - hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubIndex : 0xffff; - hdr.unknown013 = (merchant_slot == 0) ? slot_id.AugIndex : 0xffff; + hdr.slot_type = (inst->GetMerchantSlot() ? inventory::TypeMerchant : slot_id.Type); + hdr.main_slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id.Slot); + hdr.sub_slot = (inst->GetMerchantSlot() ? 0xffff : slot_id.SubIndex); + hdr.aug_slot = (inst->GetMerchantSlot() ? 0xffff : slot_id.AugIndex); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - //hdr.merchant_slot = (merchant_slot == 0) ? 1 : 0xffffffff; - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; hdr.isEvolving = item->EvolvingItem; + ss.write((const char*)&hdr, sizeof(RoF::structs::ItemSerializationHeader)); if (item->EvolvingItem > 0) { RoF::structs::EvolvingItem evotop; + evotop.unknown001 = 0; evotop.unknown002 = 0; evotop.unknown003 = 0; @@ -5245,31 +5225,36 @@ namespace RoF evotop.progress = 0; evotop.Activated = 1; evotop.evomaxlevel = item->EvolvingMax; + ss.write((const char*)&evotop, sizeof(RoF::structs::EvolvingItem)); } + //ORNAMENT IDFILE / ICON + int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); uint32 ornaIcon = 0; uint32 heroModel = 0; - if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) - { - char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); - //Mainhand - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); - //Offhand - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); + if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { ornaIcon = inst->GetOrnamentationIcon(); heroModel = inst->GetOrnamentHeroModel(Inventory::CalcMaterialFromSlot(slot_id_in)); + + char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + + //Mainhand + ss.write(tmp, strlen(tmp)); + ss.write("\0", 1); + + //Offhand + ss.write(tmp, strlen(tmp)); + ss.write("\0", 1); } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); // no main hand Ornamentation - ss.write((const char*)&null_term, sizeof(uint8)); // no off hand Ornamentation + else { + ss.write("\0", 1); // no main hand Ornamentation + ss.write("\0", 1); // no off hand Ornamentation } RoF::structs::ItemSerializationHeaderFinish hdrf; + hdrf.ornamentIcon = ornaIcon; hdrf.unknowna1 = 0xffffffff; hdrf.ornamentHeroModel = heroModel; @@ -5282,37 +5267,19 @@ namespace RoF ss.write((const char*)&hdrf, sizeof(RoF::structs::ItemSerializationHeaderFinish)); if (strlen(item->Name) > 0) - { ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->Lore) > 0) - { ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->IDFile) > 0) - { ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); - ss.write((const char*)&null_term, sizeof(uint8)); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody struct is %i bytes", sizeof(RoF::structs::ItemBodyStruct)); + ss.write("\0", 1); + RoF::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(RoF::structs::ItemBodyStruct)); @@ -5363,12 +5330,8 @@ namespace RoF ibs.BaneDmgAmt = item->BaneDmgAmt; ibs.Magic = item->Magic; ibs.CastTime_ = item->CastTime_; - ibs.ReqLevel = item->ReqLevel; - if (item->ReqLevel > 100) - ibs.ReqLevel = 100; - ibs.RecLevel = item->RecLevel; - if (item->RecLevel > 100) - ibs.RecLevel = 100; + ibs.ReqLevel = ((item->ReqLevel > 100) ? 100 : item->ReqLevel); + ibs.RecLevel = ((item->RecLevel > 100) ? 100 : item->RecLevel); ibs.RecSkill = item->RecSkill; ibs.BardType = item->BardType; ibs.BardValue = item->BardValue; @@ -5410,16 +5373,9 @@ namespace RoF //charm text if (strlen(item->CharmFile) > 0) - { ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody secondary struct is %i bytes", sizeof(RoF::structs::ItemSecondaryBodyStruct)); RoF::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(RoF::structs::ItemSecondaryBodyStruct)); @@ -5427,11 +5383,10 @@ namespace RoF isbs.augdistiller = 65535; isbs.augrestrict = item->AugRestrict; - for (int x = AUG_INDEX_BEGIN; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < consts::ITEM_COMMON_SIZE; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -5451,16 +5406,9 @@ namespace RoF ss.write((const char*)&isbs, sizeof(RoF::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody tertiary struct is %i bytes", sizeof(RoF::structs::ItemTertiaryBodyStruct)); RoF::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(RoF::structs::ItemTertiaryBodyStruct)); @@ -5482,7 +5430,7 @@ namespace RoF itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; @@ -5499,7 +5447,6 @@ namespace RoF // Effect Structures Broken down to allow variable length strings for effect names int32 effect_unknown = 0; - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody Click effect struct is %i bytes", sizeof(RoF::structs::ClickEffectStruct)); RoF::structs::ClickEffectStruct ices; memset(&ices, 0, sizeof(RoF::structs::ClickEffectStruct)); @@ -5515,18 +5462,11 @@ namespace RoF ss.write((const char*)&ices, sizeof(RoF::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody proc effect struct is %i bytes", sizeof(RoF::structs::ProcEffectStruct)); RoF::structs::ProcEffectStruct ipes; memset(&ipes, 0, sizeof(RoF::structs::ProcEffectStruct)); @@ -5539,18 +5479,11 @@ namespace RoF ss.write((const char*)&ipes, sizeof(RoF::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody worn effect struct is %i bytes", sizeof(RoF::structs::WornEffectStruct)); RoF::structs::WornEffectStruct iwes; memset(&iwes, 0, sizeof(RoF::structs::WornEffectStruct)); @@ -5562,14 +5495,8 @@ namespace RoF ss.write((const char*)&iwes, sizeof(RoF::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -5584,14 +5511,8 @@ namespace RoF ss.write((const char*)&ifes, sizeof(RoF::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -5606,14 +5527,8 @@ namespace RoF ss.write((const char*)&ises, sizeof(RoF::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -5636,12 +5551,11 @@ namespace RoF ss.write((const char*)&null_term, sizeof(uint8)); } else */ - ss.write((const char*)&null_term, sizeof(uint8)); + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody Quaternary effect struct is %i bytes", sizeof(RoF::structs::ItemQuaternaryBodyStruct)); RoF::structs::ItemQuaternaryBodyStruct iqbs; memset(&iqbs, 0, sizeof(RoF::structs::ItemQuaternaryBodyStruct)); @@ -5667,70 +5581,47 @@ namespace RoF iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - iqbs.clairvoyance = item->Clairvoyance; + iqbs.Clairvoyance = item->Clairvoyance; iqbs.unknown28 = 0; iqbs.unknown30 = 0; iqbs.unknown39 = 1; - - iqbs.subitem_count = 0; - - char *SubSerializations[10]; // - - uint32 SubLengths[10]; - - for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++x) { - - SubSerializations[x] = nullptr; - - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); - - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); - } - } - + ss.write((const char*)&iqbs, sizeof(RoF::structs::ItemQuaternaryBodyStruct)); - for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++x) { + std::stringstream::pos_type count_pos = ss.tellp(); + uint32 subitem_count = 0; - if (SubSerializations[x]) { + ss.write((const char*)&subitem_count, sizeof(uint32)); - ss.write((const char*)&x, sizeof(uint32)); + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; - ss.write(SubSerializations[x], SubLengths[x]); + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; - safe_delete_array(SubSerializations[x]); - } + ss.write((const char*)&index, sizeof(uint32)); + + SerializeItem(ss, sub, SubSlotNumber, (depth + 1)); + ++subitem_count; } - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); + if (subitem_count) { + std::stringstream::pos_type cur_pos = ss.tellp(); + ss.seekp(count_pos); - *length = ss.tellp(); - return item_serial; + ss.write((const char*)&subitem_count, sizeof(uint32)); + + ss.seekp(cur_pos); + } } static inline structs::InventorySlot_Struct ServerToRoFSlot(uint32 serverSlot) diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 005b1d298..43cc31d55 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -24,7 +24,7 @@ namespace RoF2 static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth, ItemPacketType packet_type); + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id, uint8 depth, ItemPacketType packet_type); // server to client inventory location converters static inline structs::InventorySlot_Struct ServerToRoF2Slot(uint32 serverSlot, ItemPacketType PacketType = ItemPacketInvalid); @@ -602,70 +602,52 @@ namespace RoF2 ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { - + if (!in->size) { in->size = 4; in->pBuffer = new uchar[in->size]; - - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); delete in; - return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + InternalSerializedItem_Struct* eq = (InternalSerializedItem_Struct*)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - for (int r = 0; r < ItemCount; r++, eq++) { + ss.write((const char*)&item_count, sizeof(uint32)); - uint32 Length = 0; + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ss, (const ItemInst*)eq->inst, eq->slot_id, 0, ItemPacketCharInventory); + if (ss.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0, ItemPacketCharInventory); - - if (Serialized) { - - uchar *OldBuffer = in->pBuffer; - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ss.tellp(); } - delete[] __emu_buffer; + std::string serialized = ss.str(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); + + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -1576,29 +1558,37 @@ namespace RoF2 ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; + ItemPacket_Struct* old_item_pkt = (ItemPacket_Struct*)__emu_buffer; + //InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(old_item_pkt->SerializedItem); + InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(&__emu_buffer[4]); - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0, old_item_pkt->PacketType); + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - if (!serialized) { + ss.write((const char*)__emu_buffer, 4); + + SerializeItem(ss, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0, old_item_pkt->PacketType); + if (ss.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + + std::string serialized = ss.str(); + + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + //ItemPacket_Struct* new_item_pkt = (ItemPacket_Struct*)in->pBuffer; + //new_item_pkt->PacketType = old_item_pkt->PacketType; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -5461,52 +5451,43 @@ namespace RoF2 return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth, ItemPacketType packet_type) + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id_in, uint8 depth, ItemPacketType packet_type) { - int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); - + RoF2::structs::ItemSerializationHeader hdr; //sprintf(hdr.unknown000, "06e0002Y1W00"); snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID); - hdr.stacksize = stackable ? charges : 1; + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; structs::InventorySlot_Struct slot_id = ServerToRoF2Slot(slot_id_in, packet_type); - hdr.slot_type = (merchant_slot == 0) ? slot_id.Type : 9; // 9 is merchant 20 is reclaim items? - hdr.main_slot = (merchant_slot == 0) ? slot_id.Slot : merchant_slot; - hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubIndex : 0xffff; - hdr.aug_slot = (merchant_slot == 0) ? slot_id.AugIndex : 0xffff; + hdr.slot_type = (inst->GetMerchantSlot() ? inventory::TypeMerchant : slot_id.Type); + hdr.main_slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id.Slot); + hdr.sub_slot = (inst->GetMerchantSlot() ? 0xffff : slot_id.SubIndex); + hdr.aug_slot = (inst->GetMerchantSlot() ? 0xffff : slot_id.AugIndex); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; hdr.isEvolving = item->EvolvingItem; + ss.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader)); if (item->EvolvingItem > 0) { RoF2::structs::EvolvingItem evotop; + evotop.unknown001 = 0; evotop.unknown002 = 0; evotop.unknown003 = 0; @@ -5515,31 +5496,36 @@ namespace RoF2 evotop.progress = 0; evotop.Activated = 1; evotop.evomaxlevel = item->EvolvingMax; + ss.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem)); } + //ORNAMENT IDFILE / ICON + int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); uint32 ornaIcon = 0; uint32 heroModel = 0; - if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) - { - char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); - //Mainhand - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); - //Offhand - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); + if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { ornaIcon = inst->GetOrnamentationIcon(); heroModel = inst->GetOrnamentHeroModel(Inventory::CalcMaterialFromSlot(slot_id_in)); + + char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + + //Mainhand + ss.write(tmp, strlen(tmp)); + ss.write("\0", 1); + + //Offhand + ss.write(tmp, strlen(tmp)); + ss.write("\0", 1); } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); // no main hand Ornamentation - ss.write((const char*)&null_term, sizeof(uint8)); // no off hand Ornamentation + else { + ss.write("\0", 1); // no main hand Ornamentation + ss.write("\0", 1); // no off hand Ornamentation } RoF2::structs::ItemSerializationHeaderFinish hdrf; + hdrf.ornamentIcon = ornaIcon; hdrf.unknowna1 = 0xffffffff; hdrf.ornamentHeroModel = heroModel; @@ -5552,37 +5538,19 @@ namespace RoF2 ss.write((const char*)&hdrf, sizeof(RoF2::structs::ItemSerializationHeaderFinish)); if (strlen(item->Name) > 0) - { ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->Lore) > 0) - { ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->IDFile) > 0) - { ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); - ss.write((const char*)&null_term, sizeof(uint8)); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody struct is %i bytes", sizeof(RoF2::structs::ItemBodyStruct)); + ss.write("\0", 1); + RoF2::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(RoF2::structs::ItemBodyStruct)); @@ -5633,12 +5601,8 @@ namespace RoF2 ibs.BaneDmgAmt = item->BaneDmgAmt; ibs.Magic = item->Magic; ibs.CastTime_ = item->CastTime_; - ibs.ReqLevel = item->ReqLevel; - if (item->ReqLevel > 100) - ibs.ReqLevel = 100; - ibs.RecLevel = item->RecLevel; - if (item->RecLevel > 100) - ibs.RecLevel = 100; + ibs.ReqLevel = ((item->ReqLevel > 100) ? 100 : item->ReqLevel); + ibs.RecLevel = ((item->RecLevel > 100) ? 100 : item->RecLevel); ibs.RecSkill = item->RecSkill; ibs.BardType = item->BardType; ibs.BardValue = item->BardValue; @@ -5680,16 +5644,9 @@ namespace RoF2 //charm text if (strlen(item->CharmFile) > 0) - { ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody secondary struct is %i bytes", sizeof(RoF2::structs::ItemSecondaryBodyStruct)); RoF2::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(RoF2::structs::ItemSecondaryBodyStruct)); @@ -5697,11 +5654,10 @@ namespace RoF2 isbs.augrestrict2 = -1; isbs.augrestrict = item->AugRestrict; - for (int x = AUG_INDEX_BEGIN; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < consts::ITEM_COMMON_SIZE; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -5721,16 +5677,9 @@ namespace RoF2 ss.write((const char*)&isbs, sizeof(RoF2::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody tertiary struct is %i bytes", sizeof(RoF2::structs::ItemTertiaryBodyStruct)); RoF2::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(RoF2::structs::ItemTertiaryBodyStruct)); @@ -5752,7 +5701,7 @@ namespace RoF2 itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; @@ -5769,7 +5718,6 @@ namespace RoF2 // Effect Structures Broken down to allow variable length strings for effect names int32 effect_unknown = 0; - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody Click effect struct is %i bytes", sizeof(RoF2::structs::ClickEffectStruct)); RoF2::structs::ClickEffectStruct ices; memset(&ices, 0, sizeof(RoF2::structs::ClickEffectStruct)); @@ -5785,18 +5733,11 @@ namespace RoF2 ss.write((const char*)&ices, sizeof(RoF2::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody proc effect struct is %i bytes", sizeof(RoF2::structs::ProcEffectStruct)); RoF2::structs::ProcEffectStruct ipes; memset(&ipes, 0, sizeof(RoF2::structs::ProcEffectStruct)); @@ -5809,18 +5750,11 @@ namespace RoF2 ss.write((const char*)&ipes, sizeof(RoF2::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody worn effect struct is %i bytes", sizeof(RoF2::structs::WornEffectStruct)); RoF2::structs::WornEffectStruct iwes; memset(&iwes, 0, sizeof(RoF2::structs::WornEffectStruct)); @@ -5832,14 +5766,8 @@ namespace RoF2 ss.write((const char*)&iwes, sizeof(RoF2::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -5854,14 +5782,8 @@ namespace RoF2 ss.write((const char*)&ifes, sizeof(RoF2::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -5876,14 +5798,8 @@ namespace RoF2 ss.write((const char*)&ises, sizeof(RoF2::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -5906,12 +5822,11 @@ namespace RoF2 ss.write((const char*)&null_term, sizeof(uint8)); } else */ - ss.write((const char*)&null_term, sizeof(uint8)); + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody Quaternary effect struct is %i bytes", sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); RoF2::structs::ItemQuaternaryBodyStruct iqbs; memset(&iqbs, 0, sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); @@ -5937,83 +5852,57 @@ namespace RoF2 iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - iqbs.clairvoyance = item->Clairvoyance; + iqbs.Clairvoyance = item->Clairvoyance; //unknown18; //Power Source Capacity or evolve filename? //evolve_string; // Some String, but being evolution related is just a guess iqbs.Heirloom = 0; iqbs.Placeable = 0; - iqbs.unknown28 = -1; iqbs.unknown30 = -1; - iqbs.NoZone = 0; iqbs.NoGround = 0; iqbs.unknown37a = 0; // (guessed position) New to RoF2 iqbs.unknown38 = 0; - iqbs.unknown39 = 1; - - iqbs.subitem_count = 0; - - char *SubSerializations[10]; // - - uint32 SubLengths[10]; - - for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++x) { - - SubSerializations[x] = nullptr; - - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); - - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1, packet_type); - } - } - + ss.write((const char*)&iqbs, sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); - for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++x) { + std::stringstream::pos_type count_pos = ss.tellp(); + uint32 subitem_count = 0; - if (SubSerializations[x]) { + ss.write((const char*)&subitem_count, sizeof(uint32)); - ss.write((const char*)&x, sizeof(uint32)); + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; - ss.write(SubSerializations[x], SubLengths[x]); + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; - safe_delete_array(SubSerializations[x]); - } + ss.write((const char*)&index, sizeof(uint32)); + + SerializeItem(ss, sub, SubSlotNumber, (depth + 1), packet_type); + ++subitem_count; } - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); + if (subitem_count) { + std::stringstream::pos_type cur_pos = ss.tellp(); + ss.seekp(count_pos); - *length = ss.tellp(); - return item_serial; + ss.write((const char*)&subitem_count, sizeof(uint32)); + + ss.seekp(cur_pos); + } } static inline structs::InventorySlot_Struct ServerToRoF2Slot(uint32 serverSlot, ItemPacketType PacketType) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 0e457a0d1..7464f22cd 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -4795,7 +4795,7 @@ struct ItemQuaternaryBodyStruct int32 HeroicSVCorrup; int32 HealAmt; int32 SpellDmg; - int32 clairvoyance; + int32 Clairvoyance; uint8 unknown18; //Power Source Capacity or evolve filename? uint32 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; @@ -4833,7 +4833,6 @@ struct ItemQuaternaryBodyStruct uint8 unknown37a; // New to RoF2 - Probably variable length string uint8 unknown38; // 0 uint8 unknown39; // 1 - uint32 subitem_count; }; struct AugmentInfo_Struct diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 4c7ecc1c1..a143e32ce 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -4530,7 +4530,7 @@ struct ItemSerializationHeader /*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ? /*026*/ uint16 main_slot; /*028*/ uint16 sub_slot; -/*030*/ uint16 unknown013; // 0xffff +/*030*/ uint16 aug_slot; // 0xffff /*032*/ uint32 price; /*036*/ uint32 merchant_slot; //1 if not a merchant item /*040*/ uint32 scaled_value; //0 @@ -4794,7 +4794,7 @@ struct ItemQuaternaryBodyStruct int32 HeroicSVCorrup; int32 HealAmt; int32 SpellDmg; - int32 clairvoyance; + int32 Clairvoyance; uint8 unknown18; //Power Source Capacity or evolve filename? uint32 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; @@ -4821,7 +4821,6 @@ struct ItemQuaternaryBodyStruct uint32 unknown_RoF8; uint8 unknown38; // 0 uint8 unknown39; // 1 - uint32 subitem_count; }; struct AugmentInfo_Struct diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 48b7248ed..9902447b8 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -22,7 +22,7 @@ namespace SoD static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id, uint8 depth); // server to client inventory location converters static inline uint32 ServerToSoDSlot(uint32 ServerSlot); @@ -335,30 +335,23 @@ namespace SoD ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { - + if (!in->size) { in->size = 4; - in->pBuffer = new uchar[in->size]; - - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); - return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); @@ -366,39 +359,28 @@ namespace SoD return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + InternalSerializedItem_Struct* eq = (InternalSerializedItem_Struct*)in->pBuffer; - for (int r = 0; r < ItemCount; r++, eq++) { + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - uint32 Length = 0; - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); + ss.write((const char*)&item_count, sizeof(uint32)); - if (Serialized) { + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ss, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ss.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - uchar *OldBuffer = in->pBuffer; - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ss.tellp(); } - delete[] __emu_buffer; + std::string serialized = ss.str(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); + + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -1036,29 +1018,37 @@ namespace SoD ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; + //ItemPacket_Struct* old_item_pkt = (ItemPacket_Struct*)__emu_buffer; + //InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(old_item_pkt->SerializedItem); + InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(&__emu_buffer[4]); - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - if (!serialized) { + ss.write((const char*)__emu_buffer, 4); + + SerializeItem(ss, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ss.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + + std::string serialized = ss.str(); + + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + //ItemPacket_Struct* new_item_pkt = (ItemPacket_Struct*)in->pBuffer; + //new_item_pkt->PacketType = old_item_pkt->PacketType; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -3550,34 +3540,26 @@ namespace SoD return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); + SoD::structs::ItemSerializationHeader hdr; - hdr.stacksize = stackable ? charges : 1; + + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; int32 slot_id = ServerToSoDSlot(slot_id_in); - hdr.slot = (merchant_slot == 0) ? slot_id : merchant_slot; + hdr.slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; @@ -3590,41 +3572,23 @@ namespace SoD ss.write((const char*)&hdr, sizeof(SoD::structs::ItemSerializationHeader)); if (strlen(item->Name) > 0) - { ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->Lore) > 0) - { ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->IDFile) > 0) - { ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); SoD::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(SoD::structs::ItemBodyStruct)); ibs.id = item->ID; // weight is uint8 in the struct, and some weights exceed that, so capping at 255. - ibs.weight = (item->Weight > 255) ? 255 : item->Weight; + ibs.weight = ((item->Weight > 255) ? 255 : item->Weight); ibs.norent = item->NoRent; ibs.nodrop = item->NoDrop; ibs.attune = item->Attuneable; @@ -3710,14 +3674,8 @@ namespace SoD //charm text if (strlen(item->CharmFile) > 0) - { ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); SoD::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(SoD::structs::ItemSecondaryBodyStruct)); @@ -3725,11 +3683,10 @@ namespace SoD isbs.augtype = item->AugType; isbs.augrestrict = item->AugRestrict; - for (int x = 0; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < consts::ITEM_COMMON_SIZE; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -3749,14 +3706,8 @@ namespace SoD ss.write((const char*)&isbs, sizeof(SoD::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); SoD::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(SoD::structs::ItemTertiaryBodyStruct)); @@ -3776,7 +3727,7 @@ namespace SoD itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; @@ -3800,14 +3751,8 @@ namespace SoD ss.write((const char*)&ices, sizeof(SoD::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 @@ -3823,14 +3768,8 @@ namespace SoD ss.write((const char*)&ipes, sizeof(SoD::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 @@ -3845,14 +3784,8 @@ namespace SoD ss.write((const char*)&iwes, sizeof(SoD::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -3867,14 +3800,8 @@ namespace SoD ss.write((const char*)&ifes, sizeof(SoD::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -3889,14 +3816,8 @@ namespace SoD ss.write((const char*)&ises, sizeof(SoD::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects @@ -3926,67 +3847,44 @@ namespace SoD iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - iqbs.clairvoyance = item->Clairvoyance; - - iqbs.subitem_count = 0; - - char *SubSerializations[10]; // - - uint32 SubLengths[10]; - - for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++x) { - - SubSerializations[x] = nullptr; - - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); - - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); - } - } - + iqbs.Clairvoyance = item->Clairvoyance; + ss.write((const char*)&iqbs, sizeof(SoD::structs::ItemQuaternaryBodyStruct)); - for (int x = 0; x < 10; ++x) { + std::stringstream::pos_type count_pos = ss.tellp(); + uint32 subitem_count = 0; - if (SubSerializations[x]) { + ss.write((const char*)&subitem_count, sizeof(uint32)); - ss.write((const char*)&x, sizeof(uint32)); + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; - ss.write(SubSerializations[x], SubLengths[x]); + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; - safe_delete_array(SubSerializations[x]); - } + ss.write((const char*)&index, sizeof(uint32)); + + SerializeItem(ss, sub, SubSlotNumber, (depth + 1)); + ++subitem_count; } - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); + if (subitem_count) { + std::stringstream::pos_type cur_pos = ss.tellp(); + ss.seekp(count_pos); - *length = ss.tellp(); - return item_serial; + ss.write((const char*)&subitem_count, sizeof(uint32)); + + ss.seekp(cur_pos); + } } static inline uint32 ServerToSoDSlot(uint32 serverSlot) diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 20e2a56b4..7f1b76d52 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -4184,10 +4184,9 @@ struct ItemQuaternaryBodyStruct int32 HeroicSVCorrup; int32 HealAmt; int32 SpellDmg; - int32 clairvoyance; + int32 Clairvoyance; uint8 unknown18; //Power Source Capacity or evolve filename? uint32 evolve_string; // Some String, but being evolution related is just a guess - uint32 subitem_count; }; struct AugmentInfo_Struct diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index ef0220f57..e2526cb45 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -22,7 +22,7 @@ namespace SoF static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id, uint8 depth); // server to client inventory location converters static inline uint32 ServerToSoFSlot(uint32 serverSlot); @@ -317,26 +317,23 @@ namespace SoF ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { + if (!in->size) { in->size = 4; in->pBuffer = new uchar[in->size]; - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); @@ -344,41 +341,28 @@ namespace SoF return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + InternalSerializedItem_Struct* eq = (InternalSerializedItem_Struct*)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - for (int r = 0; r < ItemCount; r++, eq++) { + ss.write((const char*)&item_count, sizeof(uint32)); - uint32 Length = 0; + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ss, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ss.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); - - if (Serialized) { - uchar *OldBuffer = in->pBuffer; - - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ss.tellp(); } - delete[] __emu_buffer; + std::string serialized = ss.str(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); + + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -834,29 +818,37 @@ namespace SoF ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; + //ItemPacket_Struct* old_item_pkt = (ItemPacket_Struct*)__emu_buffer; + //InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(old_item_pkt->SerializedItem); + InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(&__emu_buffer[4]); - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - if (!serialized) { + ss.write((const char*)__emu_buffer, 4); + + SerializeItem(ss, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ss.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + + std::string serialized = ss.str(); + + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + //ItemPacket_Struct* new_item_pkt = (ItemPacket_Struct*)in->pBuffer; + //new_item_pkt->PacketType = old_item_pkt->PacketType; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -2873,34 +2865,26 @@ namespace SoF return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); + SoF::structs::ItemSerializationHeader hdr; - hdr.stacksize = stackable ? charges : 1; + + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; int32 slot_id = ServerToSoFSlot(slot_id_in); - hdr.slot = (merchant_slot == 0) ? slot_id : merchant_slot; + hdr.slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; @@ -2912,41 +2896,23 @@ namespace SoF ss.write((const char*)&hdr, sizeof(SoF::structs::ItemSerializationHeader)); if (strlen(item->Name) > 0) - { ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->Lore) > 0) - { ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->IDFile) > 0) - { ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); SoF::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(SoF::structs::ItemBodyStruct)); ibs.id = item->ID; // weight is uint8 in the struct, and some weights exceed that, so capping at 255. - ibs.weight = (item->Weight > 255) ? 255 : item->Weight; + ibs.weight = ((item->Weight > 255) ? 255 : item->Weight); ibs.norent = item->NoRent; ibs.nodrop = item->NoDrop; ibs.attune = item->Attuneable; @@ -3032,14 +2998,8 @@ namespace SoF //charm text if (strlen(item->CharmFile) > 0) - { ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); SoF::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(SoF::structs::ItemSecondaryBodyStruct)); @@ -3047,11 +3007,10 @@ namespace SoF isbs.augtype = item->AugType; isbs.augrestrict = item->AugRestrict; - for (int x = 0; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < consts::ITEM_COMMON_SIZE; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -3071,14 +3030,8 @@ namespace SoF ss.write((const char*)&isbs, sizeof(SoF::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); SoF::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(SoF::structs::ItemTertiaryBodyStruct)); @@ -3098,7 +3051,7 @@ namespace SoF itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; @@ -3122,14 +3075,8 @@ namespace SoF ss.write((const char*)&ices, sizeof(SoF::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 @@ -3145,14 +3092,8 @@ namespace SoF ss.write((const char*)&ipes, sizeof(SoF::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 @@ -3167,14 +3108,8 @@ namespace SoF ss.write((const char*)&iwes, sizeof(SoF::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -3189,14 +3124,8 @@ namespace SoF ss.write((const char*)&ifes, sizeof(SoF::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -3211,14 +3140,8 @@ namespace SoF ss.write((const char*)&ises, sizeof(SoF::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects @@ -3248,64 +3171,43 @@ namespace SoF iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - //iqbs.clairvoyance = item->Clairvoyance; - - iqbs.subitem_count = 0; - - char *SubSerializations[10]; // - - uint32 SubLengths[10]; - - for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++x) { - - SubSerializations[x] = nullptr; - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); - - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); - } - } - + ss.write((const char*)&iqbs, sizeof(SoF::structs::ItemQuaternaryBodyStruct)); - for (int x = 0; x < 10; ++x) { + std::stringstream::pos_type count_pos = ss.tellp(); + uint32 subitem_count = 0; - if (SubSerializations[x]) { - ss.write((const char*)&x, sizeof(uint32)); - ss.write(SubSerializations[x], SubLengths[x]); + ss.write((const char*)&subitem_count, sizeof(uint32)); - safe_delete_array(SubSerializations[x]); - } + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; + + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; + + ss.write((const char*)&index, sizeof(uint32)); + + SerializeItem(ss, sub, SubSlotNumber, (depth + 1)); + ++subitem_count; } - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); + if (subitem_count) { + std::stringstream::pos_type cur_pos = ss.tellp(); + ss.seekp(count_pos); - *length = ss.tellp(); - return item_serial; + ss.write((const char*)&subitem_count, sizeof(uint32)); + + ss.seekp(cur_pos); + } } static inline uint32 ServerToSoFSlot(uint32 serverSlot) diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index d78277721..521d66477 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -4039,7 +4039,6 @@ struct ItemQuaternaryBodyStruct int32 HealAmt; int32 SpellDmg; uint32 evolve_string; // Some String, but being evolution related is just a guess - uint32 subitem_count; }; struct AugmentInfo_Struct diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 98b3b64f9..cdfbf0250 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -20,7 +20,7 @@ namespace Titanium static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - std::string SerializeItem(const ItemInst *inst, int16 slot_id_in, uint8 depth); + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id_in, uint8 depth); // server to client inventory location converters static inline int16 ServerToTitaniumSlot(uint32 serverSlot); @@ -260,11 +260,11 @@ namespace Titanium ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; + uchar* __emu_buffer = in->pBuffer; int itemcount = in->size / sizeof(InternalSerializedItem_Struct); if (itemcount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { @@ -272,26 +272,25 @@ namespace Titanium delete in; return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + InternalSerializedItem_Struct* eq = (InternalSerializedItem_Struct*)in->pBuffer; //do the transform... - std::string serial_string; - for (int r = 0; r < itemcount; r++, eq++) { - std::string serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, 0); // assumed move operation: string& = string&& - if (!serialized.empty()) { - serial_string.append(serialized); - serial_string.push_back('\0'); - } - else { - Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); + for (int r = 0; r < itemcount; r++, eq++) { + SerializeItem(ss, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ss.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); + + last_pos = ss.tellp(); } - // do we need to account for a trailing null escape? - in->size = serial_string.size(); - in->pBuffer = new unsigned char[in->size]; - memcpy(in->pBuffer, serial_string.c_str(), serial_string.size()); + std::string serialized = ss.str(); + + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); delete[] __emu_buffer; @@ -716,27 +715,34 @@ namespace Titanium ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + uchar* __emu_buffer = in->pBuffer; + //ItemPacket_Struct* old_item_pkt = (ItemPacket_Struct*)__emu_buffer; + //InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(old_item_pkt->SerializedItem); + InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(&__emu_buffer[4]); - std::string serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, 0); // assumed move operation: string& = string&& - if (serialized.empty()) { + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); + + ss.write((const char*)__emu_buffer, 4); + + SerializeItem(ss, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ss.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = serialized.size() + 5; // ItemPacketType + Serialization + \0 - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized.c_str(), serialized.size()); - new_item_pkt->SerializedItem[serialized.size()] = '\0'; + std::string serialized = ss.str(); + + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + //ItemPacket_Struct* new_item_pkt = (ItemPacket_Struct*)in->pBuffer; + //new_item_pkt->PacketType = old_item_pkt->PacketType; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); delete[] __emu_buffer; @@ -2077,301 +2083,241 @@ namespace Titanium } // file scope helper methods - std::string SerializeItem(const ItemInst *inst, int16 slot_id_in, uint8 depth) + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - std::string serialization; const char* protection = "\\\\\\\\\\"; const Item_Struct* item = inst->GetUnscaledItem(); - serialization = StringFormat("%.*s%s", (depth ? (depth - 1) : 0), protection, (depth ? "\"" : "")); // For leading quotes (and protection) if a subitem; + ss << StringFormat("%.*s%s", (depth ? (depth - 1) : 0), protection, (depth ? "\"" : "")); // For leading quotes (and protection) if a subitem; // Instance data - serialization.append( - StringFormat( - "%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|", - (inst->IsStackable() ? inst->GetCharges() : 0), // stack count - 0, // unknown - (!inst->GetMerchantSlot() ? slot_id_in : inst->GetMerchantSlot()), // inst slot/merchant slot - inst->GetPrice(), // merchant price - (!inst->GetMerchantSlot() ? 1 : inst->GetMerchantCount()), // inst count/merchant count - (inst->IsScaling() ? (inst->GetExp() / 100) : 0), // inst experience - (!inst->GetMerchantSlot() ? inst->GetSerialNumber() : inst->GetMerchantSlot()), // merchant serial number - inst->GetRecastTimestamp(), // recast timestamp - ((inst->IsStackable() ? ((inst->GetItem()->ItemType == ItemTypePotion) ? 1 : 0) : inst->GetCharges())), // charge count - (inst->IsAttuned() ? 1 : 0), // inst attuned - 0 // unknown - ) - ); - - serialization.append(StringFormat("%.*s\"", depth, protection)); // Quotes (and protection, if needed) around static data + ss << itoa((inst->IsStackable() ? inst->GetCharges() : 0)); // stack count + ss << '|' << itoa(0); // unknown + ss << '|' << itoa((!inst->GetMerchantSlot() ? slot_id_in : inst->GetMerchantSlot())); // inst slot/merchant slot + ss << '|' << itoa(inst->GetPrice()); // merchant price + ss << '|' << itoa((!inst->GetMerchantSlot() ? 1 : inst->GetMerchantCount())); // inst count/merchant count + ss << '|' << itoa((inst->IsScaling() ? (inst->GetExp() / 100) : 0)); // inst experience + ss << '|' << itoa((!inst->GetMerchantSlot() ? inst->GetSerialNumber() : inst->GetMerchantSlot())); // merchant serial number + ss << '|' << itoa(inst->GetRecastTimestamp()); // recast timestamp + ss << '|' << itoa(((inst->IsStackable() ? ((inst->GetItem()->ItemType == ItemTypePotion) ? 1 : 0) : inst->GetCharges()))); // charge count + ss << '|' << itoa((inst->IsAttuned() ? 1 : 0)); // inst attuned + ss << '|' << itoa(0); // unknown + ss << '|'; - serialization.append(StringFormat("%i", item->ItemClass)); // item->ItemClass so we can do |%s instead of %s| - - serialization.append( - StringFormat( - "|%s|%s|%s|%i|%i|%i|%i|%i|%i|%i|%i|%s|%s|%i|%i", - item->Name, - item->Lore, - item->IDFile, - item->ID, - ((item->Weight > 255) ? 255 : item->Weight), - item->NoRent, - item->NoDrop, - item->Size, - item->Slots, - item->Price, - item->Icon, - "0", // unknown - "0", // unknown - item->BenefitFlag, - item->Tradeskills - ) - ); + ss << StringFormat("%.*s\"", depth, protection); // Quotes (and protection, if needed) around static data - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i", - item->CR, - item->DR, - item->PR, - item->MR, - item->FR, - item->AStr, - item->ASta, - item->AAgi, - item->ADex, - item->ACha, - item->AInt, - item->AWis, - item->HP, - item->Mana, - item->AC - ) - ); + // Item data + ss << itoa(item->ItemClass); + ss << '|' << item->Name; + ss << '|' << item->Lore; + ss << '|' << item->IDFile; + ss << '|' << itoa(item->ID); + ss << '|' << itoa(((item->Weight > 255) ? 255 : item->Weight)); + ss << '|' << itoa(item->NoRent); + ss << '|' << itoa(item->NoDrop); + ss << '|' << itoa(item->Size); + ss << '|' << itoa(item->Slots); + ss << '|' << itoa(item->Price); + ss << '|' << itoa(item->Icon); + ss << '|' << "0"; + ss << '|' << "0"; + ss << '|' << itoa(item->BenefitFlag); + ss << '|' << itoa(item->Tradeskills); - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i", - item->Deity, - item->SkillModValue, - item->SkillModMax, - item->SkillModType, - item->BaneDmgRace, - item->BaneDmgAmt, - item->BaneDmgBody, - item->Magic, - item->CastTime_, - item->ReqLevel, - item->BardType, - item->BardValue, - item->Light, - item->Delay - ) - ); + ss << '|' << itoa(item->CR); + ss << '|' << itoa(item->DR); + ss << '|' << itoa(item->PR); + ss << '|' << itoa(item->MR); + ss << '|' << itoa(item->FR); - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%i|%i|%i|%i|%i|%s|%i|%i|%i|%i", - item->RecLevel, - item->RecSkill, - item->ElemDmgType, - item->ElemDmgAmt, - item->Range, - item->Damage, - item->Color, - item->Classes, - item->Races, - "0", // unknown - item->MaxCharges, - item->ItemType, - item->Material, - item->SellRate - ) - ); + ss << '|' << itoa(item->AStr); + ss << '|' << itoa(item->ASta); + ss << '|' << itoa(item->AAgi); + ss << '|' << itoa(item->ADex); + ss << '|' << itoa(item->ACha); + ss << '|' << itoa(item->AInt); + ss << '|' << itoa(item->AWis); - serialization.append( - StringFormat( - "|%s|%i|%s|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i", - "0", // unknown - item->CastTime_, - "0", // unknown - item->ProcRate, - item->CombatEffects, - item->Shielding, - item->StunResist, - item->StrikeThrough, - item->ExtraDmgSkill, - item->ExtraDmgAmt, - item->SpellShield, - item->Avoidance, - item->Accuracy, - item->CharmFileID - ) - ); + ss << '|' << itoa(item->HP); + ss << '|' << itoa(item->Mana); + ss << '|' << itoa(item->AC); + ss << '|' << itoa(item->Deity); - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%i|%i|%i|%i|%s", - item->FactionMod1, - item->FactionMod2, - item->FactionMod3, - item->FactionMod4, - item->FactionAmt1, - item->FactionAmt2, - item->FactionAmt3, - item->FactionAmt4, - item->CharmFile - ) - ); + ss << '|' << itoa(item->SkillModValue); + ss << '|' << itoa(item->SkillModMax); + ss << '|' << itoa(item->SkillModType); - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i", - item->AugType, - item->AugSlotType[0], - item->AugSlotVisible[0], - item->AugSlotType[1], - item->AugSlotVisible[1], - item->AugSlotType[2], - item->AugSlotVisible[2], - item->AugSlotType[3], - item->AugSlotVisible[3], - item->AugSlotType[4], - item->AugSlotVisible[4] - ) - ); + ss << '|' << itoa(item->BaneDmgRace); + ss << '|' << itoa(item->BaneDmgAmt); + ss << '|' << itoa(item->BaneDmgBody); - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%i|%i|%i|%i|%i|%s|%i|%i|%i|%i|%i|%i", - item->LDoNTheme, - item->LDoNPrice, - item->LDoNSold, - item->BagType, - item->BagSlots, - item->BagSize, - item->BagWR, - item->Book, - item->BookType, - item->Filename, - item->BaneDmgRaceAmt, - item->AugRestrict, - item->LoreGroup, - item->PendingLoreFlag, - item->ArtifactFlag, - item->SummonedFlag - ) - ); + ss << '|' << itoa(item->Magic); + ss << '|' << itoa(item->CastTime_); + ss << '|' << itoa(item->ReqLevel); + ss << '|' << itoa(item->BardType); + ss << '|' << itoa(item->BardValue); + ss << '|' << itoa(item->Light); + ss << '|' << itoa(item->Delay); - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i", - item->Favor, - item->FVNoDrop, - item->Endur, - item->DotShielding, - item->Attack, - item->Regen, - item->ManaRegen, - item->EnduranceRegen, - item->Haste, - item->DamageShield, - item->RecastDelay, - item->RecastType, - item->GuildFavor, - item->AugDistiller - ) - ); + ss << '|' << itoa(item->RecLevel); + ss << '|' << itoa(item->RecSkill); - serialization.append( - StringFormat( - "|%s|%s|%i|%i|%s|%i|%i|%i|%i|%i|%i", - "0", // unknown - "0", // unknown - item->Attuneable, - item->NoPet, - "0", // unknown - item->PointType, - item->PotionBelt, - item->PotionBeltSlots, - item->StackSize, - item->NoTransfer, - item->Stackable - ) - ); + ss << '|' << itoa(item->ElemDmgType); + ss << '|' << itoa(item->ElemDmgAmt); - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%s", - item->Click.Effect, - item->Click.Type, - item->Click.Level2, - item->Click.Level, - "0" // Click name - ) - ); + ss << '|' << itoa(item->Range); + ss << '|' << itoa(item->Damage); - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%s", - item->Proc.Effect, - item->Proc.Type, - item->Proc.Level2, - item->Proc.Level, - "0" // Proc name - ) - ); + ss << '|' << itoa(item->Color); + ss << '|' << itoa(item->Classes); + ss << '|' << itoa(item->Races); + ss << '|' << "0"; - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%s", - item->Worn.Effect, - item->Worn.Type, - item->Worn.Level2, - item->Worn.Level, - "0" // Worn name - ) - ); + ss << '|' << itoa(item->MaxCharges); + ss << '|' << itoa(item->ItemType); + ss << '|' << itoa(item->Material); + ss << '|' << StringFormat("%f", item->SellRate); - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%s", - item->Focus.Effect, - item->Focus.Type, - item->Focus.Level2, - item->Focus.Level, - "0" // Focus name - ) - ); + ss << '|' << "0"; + ss << '|' << itoa(item->CastTime_); + ss << '|' << "0"; - serialization.append( - StringFormat( - "|%i|%i|%i|%i|%s", - item->Scroll.Effect, - item->Scroll.Type, - item->Scroll.Level2, - item->Scroll.Level, - "0" // Scroll name - ) - ); + ss << '|' << itoa(item->ProcRate); + ss << '|' << itoa(item->CombatEffects); + ss << '|' << itoa(item->Shielding); + ss << '|' << itoa(item->StunResist); + ss << '|' << itoa(item->StrikeThrough); + ss << '|' << itoa(item->ExtraDmgSkill); + ss << '|' << itoa(item->ExtraDmgAmt); + ss << '|' << itoa(item->SpellShield); + ss << '|' << itoa(item->Avoidance); + ss << '|' << itoa(item->Accuracy); - serialization.append(StringFormat("%.*s\"", depth, protection)); // Quotes (and protection, if needed) around static data + ss << '|' << itoa(item->CharmFileID); + ss << '|' << itoa(item->FactionMod1); + ss << '|' << itoa(item->FactionMod2); + ss << '|' << itoa(item->FactionMod3); + ss << '|' << itoa(item->FactionMod4); + + ss << '|' << itoa(item->FactionAmt1); + ss << '|' << itoa(item->FactionAmt2); + ss << '|' << itoa(item->FactionAmt3); + ss << '|' << itoa(item->FactionAmt4); + + ss << '|' << item->CharmFile; + + ss << '|' << itoa(item->AugType); + + ss << '|' << itoa(item->AugSlotType[0]); + ss << '|' << itoa(item->AugSlotVisible[0]); + ss << '|' << itoa(item->AugSlotType[1]); + ss << '|' << itoa(item->AugSlotVisible[1]); + ss << '|' << itoa(item->AugSlotType[2]); + ss << '|' << itoa(item->AugSlotVisible[2]); + ss << '|' << itoa(item->AugSlotType[3]); + ss << '|' << itoa(item->AugSlotVisible[3]); + ss << '|' << itoa(item->AugSlotType[4]); + ss << '|' << itoa(item->AugSlotVisible[4]); + + ss << '|' << itoa(item->LDoNTheme); + ss << '|' << itoa(item->LDoNPrice); + ss << '|' << itoa(item->LDoNSold); + + ss << '|' << itoa(item->BagType); + ss << '|' << itoa(item->BagSlots); + ss << '|' << itoa(item->BagSize); + ss << '|' << itoa(item->BagWR); + + ss << '|' << itoa(item->Book); + ss << '|' << itoa(item->BookType); + + ss << '|' << item->Filename; + + ss << '|' << itoa(item->BaneDmgRaceAmt); + ss << '|' << itoa(item->AugRestrict); + ss << '|' << itoa(item->LoreGroup); + ss << '|' << itoa(item->PendingLoreFlag); + ss << '|' << itoa(item->ArtifactFlag); + ss << '|' << itoa(item->SummonedFlag); + + ss << '|' << itoa(item->Favor); + ss << '|' << itoa(item->FVNoDrop); + ss << '|' << itoa(item->Endur); + ss << '|' << itoa(item->DotShielding); + ss << '|' << itoa(item->Attack); + ss << '|' << itoa(item->Regen); + ss << '|' << itoa(item->ManaRegen); + ss << '|' << itoa(item->EnduranceRegen); + ss << '|' << itoa(item->Haste); + ss << '|' << itoa(item->DamageShield); + ss << '|' << itoa(item->RecastDelay); + ss << '|' << itoa(item->RecastType); + ss << '|' << itoa(item->GuildFavor); + + ss << '|' << itoa(item->AugDistiller); + + ss << '|' << "0"; // unknown + ss << '|' << "0"; // unknown + ss << '|' << itoa(item->Attuneable); + ss << '|' << itoa(item->NoPet); + ss << '|' << "0"; // unknown + ss << '|' << itoa(item->PointType); + + ss << '|' << itoa(item->PotionBelt); + ss << '|' << itoa(item->PotionBeltSlots); + ss << '|' << itoa(item->StackSize); + ss << '|' << itoa(item->NoTransfer); + ss << '|' << itoa(item->Stackable); + + ss << '|' << itoa(item->Click.Effect); + ss << '|' << itoa(item->Click.Type); + ss << '|' << itoa(item->Click.Level2); + ss << '|' << itoa(item->Click.Level); + ss << '|' << "0"; // Click name + + ss << '|' << itoa(item->Proc.Effect); + ss << '|' << itoa(item->Proc.Type); + ss << '|' << itoa(item->Proc.Level2); + ss << '|' << itoa(item->Proc.Level); + ss << '|' << "0"; // Proc name + + ss << '|' << itoa(item->Worn.Effect); + ss << '|' << itoa(item->Worn.Type); + ss << '|' << itoa(item->Worn.Level2); + ss << '|' << itoa(item->Worn.Level); + ss << '|' << "0"; // Worn name + + ss << '|' << itoa(item->Focus.Effect); + ss << '|' << itoa(item->Focus.Type); + ss << '|' << itoa(item->Focus.Level2); + ss << '|' << itoa(item->Focus.Level); + ss << '|' << "0"; // Focus name + + ss << '|' << itoa(item->Scroll.Effect); + ss << '|' << itoa(item->Scroll.Type); + ss << '|' << itoa(item->Scroll.Level2); + ss << '|' << itoa(item->Scroll.Level); + ss << '|' << "0"; // Scroll name + + ss << StringFormat("%.*s\"", depth, protection); // Quotes (and protection, if needed) around static data + + // Sub data for (int index = SUB_INDEX_BEGIN; index < consts::ITEM_CONTAINER_SIZE; ++index) { - ItemInst *sub = inst->GetItem(index); - if (!sub) { - serialization.push_back('|'); // Sub items (empty) - } - else { - std::string sub_item = SerializeItem(sub, 0, (depth + 1)); - serialization.append(StringFormat("|%s", sub_item.c_str())); // Sub items - } + ss << '|'; + + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; + + SerializeItem(ss, sub, 0, (depth + 1)); } - serialization.append(StringFormat("%.*s%s", (depth ? (depth - 1) : 0), protection, (depth ? "\"" : ""))); // For trailing quotes (and protection) if a subitem; + ss << StringFormat("%.*s%s", (depth ? (depth - 1) : 0), protection, (depth ? "\"" : "")); // For trailing quotes (and protection) if a subitem; - return serialization; + if (!depth) + ss.write("\0", 1); } static inline int16 ServerToTitaniumSlot(uint32 serverSlot) diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 28ff1d541..f864172bd 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -22,7 +22,7 @@ namespace UF static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id, uint8 depth); // server to client inventory location converters static inline uint32 ServerToUFSlot(uint32 serverSlot); @@ -473,27 +473,23 @@ namespace UF ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { - + if (!in->size) { in->size = 4; in->pBuffer = new uchar[in->size]; - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); @@ -501,39 +497,28 @@ namespace UF return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + InternalSerializedItem_Struct* eq = (InternalSerializedItem_Struct*)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - for (int r = 0; r < ItemCount; r++, eq++) { + ss.write((const char*)&item_count, sizeof(uint32)); - uint32 Length = 0; - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ss, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ss.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - if (Serialized) { - - uchar *OldBuffer = in->pBuffer; - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ss.tellp(); } - delete[] __emu_buffer; + std::string serialized = ss.str(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); + + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -1259,29 +1244,37 @@ namespace UF ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; + //ItemPacket_Struct* old_item_pkt = (ItemPacket_Struct*)__emu_buffer; + //InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(old_item_pkt->SerializedItem); + InternalSerializedItem_Struct* int_struct = (InternalSerializedItem_Struct*)(&__emu_buffer[4]); - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + std::stringstream ss(std::stringstream::in | std::stringstream::out); + std::stringstream::pos_type last_pos = ss.tellp(); - if (!serialized) { + ss.write((const char*)__emu_buffer, 4); + + SerializeItem(ss, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ss.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + + std::string serialized = ss.str(); + + in->size = serialized.size(); + in->pBuffer = new uchar[in->size]; + //ItemPacket_Struct* new_item_pkt = (ItemPacket_Struct*)in->pBuffer; + //new_item_pkt->PacketType = old_item_pkt->PacketType; + memcpy(in->pBuffer, serialized.c_str(), serialized.size()); delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -3822,43 +3815,36 @@ namespace UF return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + void SerializeItem(std::stringstream& ss, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); + UF::structs::ItemSerializationHeader hdr; - hdr.stacksize = stackable ? charges : 1; + + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; int32 slot_id = ServerToUFSlot(slot_id_in); - hdr.slot = (merchant_slot == 0) ? slot_id : merchant_slot; + hdr.slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; hdr.isEvolving = item->EvolvingItem; + ss.write((const char*)&hdr, sizeof(UF::structs::ItemSerializationHeader)); if (item->EvolvingItem > 0) { UF::structs::EvolvingItem evotop; + evotop.unknown001 = 0; evotop.unknown002 = 0; evotop.unknown003 = 0; @@ -3867,70 +3853,55 @@ namespace UF evotop.progress = 0; evotop.Activated = 1; evotop.evomaxlevel = item->EvolvingMax; + ss.write((const char*)&evotop, sizeof(UF::structs::EvolvingItem)); } + //ORNAMENT IDFILE / ICON - + int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); uint16 ornaIcon = 0; if (inst->GetOrnamentationAug(ornamentationAugtype)) { const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); - ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); ornaIcon = aug_weap->Icon; + + ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); } else if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { - char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); ornaIcon = inst->GetOrnamentationIcon(); + char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + + ss.write(tmp, strlen(tmp)); } - else { - ss.write((const char*)&null_term, sizeof(uint8)); //no idfile - } + ss.write("\0", 1); UF::structs::ItemSerializationHeaderFinish hdrf; + hdrf.ornamentIcon = ornaIcon; hdrf.unknown060 = 0; //This is Always 0.. or it breaks shit.. hdrf.unknown061 = 0; //possibly ornament / special ornament hdrf.isCopied = 0; //Flag for item to be 'Copied' hdrf.ItemClass = item->ItemClass; + ss.write((const char*)&hdrf, sizeof(UF::structs::ItemSerializationHeaderFinish)); if (strlen(item->Name) > 0) - { ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->Lore) > 0) - { ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); if (strlen(item->IDFile) > 0) - { ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); UF::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(UF::structs::ItemBodyStruct)); ibs.id = item->ID; // weight is uint8 in the struct, and some weights exceed that, so capping at 255. - ibs.weight = (item->Weight > 255) ? 255 : item->Weight; + ibs.weight = ((item->Weight > 255) ? 255 : item->Weight); ibs.norent = item->NoRent; ibs.nodrop = item->NoDrop; ibs.attune = item->Attuneable; @@ -4016,14 +3987,8 @@ namespace UF //charm text if (strlen(item->CharmFile) > 0) - { ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); UF::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(UF::structs::ItemSecondaryBodyStruct)); @@ -4031,11 +3996,10 @@ namespace UF isbs.augtype = item->AugType; isbs.augrestrict = item->AugRestrict; - for (int x = 0; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < consts::ITEM_COMMON_SIZE; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -4055,14 +4019,8 @@ namespace UF ss.write((const char*)&isbs, sizeof(UF::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); UF::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(UF::structs::ItemTertiaryBodyStruct)); @@ -4082,7 +4040,7 @@ namespace UF itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; @@ -4106,14 +4064,8 @@ namespace UF ss.write((const char*)&ices, sizeof(UF::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 @@ -4129,14 +4081,8 @@ namespace UF ss.write((const char*)&ipes, sizeof(UF::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 @@ -4151,14 +4097,8 @@ namespace UF ss.write((const char*)&iwes, sizeof(UF::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -4173,14 +4113,8 @@ namespace UF ss.write((const char*)&ifes, sizeof(UF::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -4195,14 +4129,8 @@ namespace UF ss.write((const char*)&ises, sizeof(UF::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 @@ -4225,7 +4153,7 @@ namespace UF ss.write((const char*)&null_term, sizeof(uint8)); } else */ - ss.write((const char*)&null_term, sizeof(uint8)); + ss.write("\0", 1); ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects @@ -4255,67 +4183,44 @@ namespace UF iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - iqbs.clairvoyance = item->Clairvoyance; - - iqbs.subitem_count = 0; - - char *SubSerializations[10]; // - - uint32 SubLengths[10]; - - for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++x) { - - SubSerializations[x] = nullptr; - - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); - - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); - } - } - + iqbs.Clairvoyance = item->Clairvoyance; + ss.write((const char*)&iqbs, sizeof(UF::structs::ItemQuaternaryBodyStruct)); - for (int x = 0; x < 10; ++x) { + std::stringstream::pos_type count_pos = ss.tellp(); + uint32 subitem_count = 0; - if (SubSerializations[x]) { + ss.write((const char*)&subitem_count, sizeof(uint32)); - ss.write((const char*)&x, sizeof(uint32)); + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; - ss.write(SubSerializations[x], SubLengths[x]); + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; - safe_delete_array(SubSerializations[x]); - } + ss.write((const char*)&index, sizeof(uint32)); + + SerializeItem(ss, sub, SubSlotNumber, (depth + 1)); + ++subitem_count; } - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); + if (subitem_count) { + std::stringstream::pos_type cur_pos = ss.tellp(); + ss.seekp(count_pos); - *length = ss.tellp(); - return item_serial; + ss.write((const char*)&subitem_count, sizeof(uint32)); + + ss.seekp(cur_pos); + } } static inline uint32 ServerToUFSlot(uint32 serverSlot) diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index 75e590abd..f6a2c5553 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -4281,14 +4281,13 @@ struct ItemQuaternaryBodyStruct int32 HeroicSVCorrup; int32 HealAmt; int32 SpellDmg; - int32 clairvoyance; + int32 Clairvoyance; uint8 unknown18; //Power Source Capacity or evolve filename? uint32 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; uint32 unknown20; // Bard Stuff? uint32 unknown21; uint32 unknown22; - uint32 subitem_count; }; struct AugmentInfo_Struct