diff --git a/common/item_container.cpp b/common/item_container.cpp index e84d193e3..92823fc20 100644 --- a/common/item_container.cpp +++ b/common/item_container.cpp @@ -46,6 +46,14 @@ bool EQEmu::ItemContainer::Put(const int slot_id, std::shared_ptr return false; } +uint32 EQEmu::ItemContainer::Size() { + return impl_->items.size(); +} + +uint32 EQEmu::ItemContainer::Size() const { + return impl_->items.size(); +} + bool EQEmu::ItemContainer::Delete(const int slot_id) { auto iter = impl_->items.find(slot_id); if(iter == impl_->items.end()) { diff --git a/common/item_container.h b/common/item_container.h index 549611858..cc650a19b 100644 --- a/common/item_container.h +++ b/common/item_container.h @@ -35,6 +35,8 @@ namespace EQEmu std::shared_ptr Get(const int slot_id); bool Put(const int slot_id, std::shared_ptr inst); bool Delete(const int slot_id); + uint32 Size(); + uint32 Size() const; bool Serialize(MemoryBuffer &buf, int container_number); private: diff --git a/common/item_instance.cpp b/common/item_instance.cpp index 8a26b7b3c..34f9e9cbf 100644 --- a/common/item_instance.cpp +++ b/common/item_instance.cpp @@ -30,8 +30,12 @@ struct EQEmu::ItemInstance::impl { uint32 ornament_idfile_; uint32 ornament_icon_; uint32 ornament_hero_model_; - uint64 tracking_id_; + char tracking_id_[17]; + uint32 serial_id_; uint32 recast_timestamp_; + uint32 merchant_slot_; + uint32 merchant_count_; + uint32 price_; ItemContainer contents_; }; @@ -45,8 +49,12 @@ EQEmu::ItemInstance::ItemInstance() { impl_->ornament_idfile_ = 0; impl_->ornament_icon_ = 0; impl_->ornament_hero_model_ = 0; + impl_->serial_id_ = 0; impl_->recast_timestamp_ = 0; - impl_->tracking_id_ = 0; + impl_->merchant_slot_ = 0; + impl_->merchant_count_ = 0; + impl_->price_ = 0; + memset(impl_->tracking_id_, 0, 17); } EQEmu::ItemInstance::ItemInstance(const ItemData* idata) { @@ -59,8 +67,12 @@ EQEmu::ItemInstance::ItemInstance(const ItemData* idata) { impl_->ornament_idfile_ = 0; impl_->ornament_icon_ = 0; impl_->ornament_hero_model_ = 0; + impl_->serial_id_ = 0; impl_->recast_timestamp_ = 0; - impl_->tracking_id_ = 0; + impl_->merchant_slot_ = 0; + impl_->merchant_count_ = 0; + impl_->price_ = 0; + memset(impl_->tracking_id_, 0, 17); } EQEmu::ItemInstance::ItemInstance(const ItemData* idata, int16 charges) { @@ -74,7 +86,11 @@ EQEmu::ItemInstance::ItemInstance(const ItemData* idata, int16 charges) { impl_->ornament_icon_ = 0; impl_->ornament_hero_model_ = 0; impl_->recast_timestamp_ = 0; - impl_->tracking_id_ = 0; + impl_->serial_id_ = 0; + impl_->merchant_slot_ = 0; + impl_->merchant_count_ = 0; + impl_->price_ = 0; + memset(impl_->tracking_id_, 0, 17); } EQEmu::ItemInstance::~ItemInstance() { @@ -85,6 +101,10 @@ const ItemData *EQEmu::ItemInstance::GetItem() { return impl_->modified_item_ ? impl_->modified_item_ : impl_->base_item_; } +const ItemData *EQEmu::ItemInstance::GetBaseItem() { + return impl_->base_item_; +} + std::shared_ptr EQEmu::ItemInstance::Get(const int index) { if(EQEmu::ValueWithin(index, 0, 255)) { return impl_->contents_.Get(index); @@ -131,6 +151,22 @@ bool EQEmu::ItemInstance::Put(const int index, std::shared_ptr ins return false; } +uint32 EQEmu::ItemInstance::GetSubItemCount() { + return impl_->contents_.Size(); +} + +uint32 EQEmu::ItemInstance::GetSubItemCount() const { + return impl_->contents_.Size(); +} + +int16 EQEmu::ItemInstance::GetCharges() { + return impl_->charges_; +} + +int16 EQEmu::ItemInstance::GetCharges() const { + return impl_->charges_; +} + void EQEmu::ItemInstance::SetCharges(const int16 charges) { impl_->charges_ = charges; } @@ -139,6 +175,14 @@ void EQEmu::ItemInstance::SetColor(const uint32 color) { impl_->color_ = color; } +bool EQEmu::ItemInstance::GetAttuned() { + return impl_->attuned_; +} + +bool EQEmu::ItemInstance::GetAttuned() const { + return impl_->attuned_; +} + void EQEmu::ItemInstance::SetAttuned(const bool attuned) { impl_->attuned_ = attuned; } @@ -160,10 +204,87 @@ void EQEmu::ItemInstance::SetOrnamentHeroModel(const uint32 ornament_hero_model) impl_->ornament_hero_model_ = ornament_hero_model; } -void EQEmu::ItemInstance::SetTrackingID(const uint64 tracking_id) { - impl_->tracking_id_ = tracking_id; +const char* EQEmu::ItemInstance::GetTrackingID() { + return impl_->tracking_id_; +} + +const char* EQEmu::ItemInstance::GetTrackingID() const { + return impl_->tracking_id_; +} + +void EQEmu::ItemInstance::SetTrackingID(const char *tracking_id) { + size_t len = strlen(tracking_id); + if(len > 16) { + return; + } + + strncpy(impl_->tracking_id_, tracking_id, 16); +} + +uint32 EQEmu::ItemInstance::GetRecastTimestamp() { + return impl_->recast_timestamp_; +} + +uint32 EQEmu::ItemInstance::GetRecastTimestamp() const { + return impl_->recast_timestamp_; } void EQEmu::ItemInstance::SetRecastTimestamp(const uint32 recast_timestamp) { impl_->recast_timestamp_ = recast_timestamp; } + +uint32 EQEmu::ItemInstance::GetMerchantSlot() { + return impl_->merchant_slot_; +} + +uint32 EQEmu::ItemInstance::GetMerchantSlot() const { + return impl_->merchant_slot_; +} + +void EQEmu::ItemInstance::SetMerchantSlot(uint32 slot) { + impl_->merchant_slot_ = slot; +} + +uint32 EQEmu::ItemInstance::GetMerchantCount() { + return impl_->merchant_count_; +} + +uint32 EQEmu::ItemInstance::GetMerchantCount() const { + return impl_->merchant_count_; +} + +void EQEmu::ItemInstance::SetMerchantCount(const uint32 cnt) { + impl_->merchant_count_ = cnt; +} + +uint32 EQEmu::ItemInstance::GetPrice() { + return impl_->price_; +} + +uint32 EQEmu::ItemInstance::GetPrice() const { + return impl_->price_; +} + +void EQEmu::ItemInstance::SetPrice(const uint32 p) { + impl_->price_ = p; +} + +uint32 EQEmu::ItemInstance::GetSerialNumber() { + return impl_->serial_id_; +} + +uint32 EQEmu::ItemInstance::GetSerialNumber() const { + return impl_->serial_id_; +} + +void EQEmu::ItemInstance::SetSerialNumber(const uint32 sn) { + impl_->serial_id_ = sn; +} + +bool EQEmu::ItemInstance::IsStackable() { + return impl_->base_item_->Stackable; +} + +bool EQEmu::ItemInstance::IsStackable() const { + return impl_->base_item_->Stackable; +} diff --git a/common/item_instance.h b/common/item_instance.h index 34eeb7384..4fffaf7ee 100644 --- a/common/item_instance.h +++ b/common/item_instance.h @@ -33,18 +33,59 @@ namespace EQEmu ~ItemInstance(); const ItemData *GetItem(); + const ItemData *GetBaseItem(); + + //Container std::shared_ptr Get(const int index); bool Put(const int index, std::shared_ptr inst); + uint32 GetSubItemCount(); + uint32 GetSubItemCount() const; + //Persistent State + int16 GetCharges(); + int16 GetCharges() const; void SetCharges(const int16 charges); + void SetColor(const uint32 color); + + bool GetAttuned(); + bool GetAttuned() const; void SetAttuned(const bool attuned); + void SetCustomData(const std::string &custom_data); void SetOrnamentIDFile(const uint32 ornament_idfile); void SetOrnamentIcon(const uint32 ornament_icon); void SetOrnamentHeroModel(const uint32 ornament_hero_model); - void SetTrackingID(const uint64 tracking_id); + + const char* GetTrackingID(); + const char* GetTrackingID() const; + void SetTrackingID(const char *tracking_id); + + uint32 GetRecastTimestamp(); + uint32 GetRecastTimestamp() const; void SetRecastTimestamp(const uint32 recast_timestamp); + + //Merchant + uint32 GetMerchantSlot(); + uint32 GetMerchantSlot() const; + void SetMerchantSlot(const uint32 slot); + + uint32 GetMerchantCount(); + uint32 GetMerchantCount() const; + void SetMerchantCount(const uint32 cnt); + + uint32 GetPrice(); + uint32 GetPrice() const; + void SetPrice(const uint32 p); + + //Serial Number + uint32 GetSerialNumber(); + uint32 GetSerialNumber() const; + void SetSerialNumber(uint32 sn); + + //Basic Stats + bool IsStackable(); + bool IsStackable() const; private: struct impl; impl *impl_; diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 60f439777..561b40234 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -28,6 +28,7 @@ namespace RoF2 char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth, ItemPacketType packet_type); void SerializeItem(EQEmu::MemoryBuffer &packet_data, EQEmu::ItemInstance *inst, int container_id, int slot_id, int bag_id, int aug_id); + // server to client inventory location converters static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 serverSlot, ItemPacketType PacketType = ItemPacketInvalid); static inline structs::MainInvItemSlotStruct ServerToRoF2MainInvSlot(uint32 serverSlot); @@ -602,7 +603,6 @@ namespace RoF2 EQApplicationPacket *in = *p; *p = nullptr; - in->SetReadPosition(0); size_t entry_size = sizeof(int32) * 2 + sizeof(void*); size_t entries = in->size / entry_size; @@ -613,7 +613,8 @@ namespace RoF2 return; } - SerializedItemInstance_Struct *sis = (SerializedItemInstance_Struct*)in->pBuffer; + unsigned char *__emu_buffer = in->pBuffer; + SerializedItemInstance_Struct *sis = (SerializedItemInstance_Struct*)__emu_buffer; EQEmu::MemoryBuffer packet_data; packet_data.Write(entries); @@ -624,75 +625,16 @@ namespace RoF2 continue; } - //SerializeItem(packet_data, inst, sis[i].container_id, sis[i].slot_id, -1, -1, ItemPacketCharInventory); - // //SerializeItem((const EQEmu::ItemInstance*) - // //char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0, ItemPacketCharInventory); + SerializeItem(packet_data, inst, sis[i].container_id, sis[i].slot_id, -1, -1); } - delete in; + in->pBuffer = new uchar[packet_data.Size()]; + in->size = packet_data.Size(); + memcpy(in->pBuffer, packet_data, in->size); - //if (in->size == 0) { - // - // in->size = 4; - // in->pBuffer = new uchar[in->size]; - // - // *((uint32 *)in->pBuffer) = 0; - // - // 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) { - // - // 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; - // - //in->pBuffer = new uchar[4]; - //*(uint32 *)in->pBuffer = ItemCount; - //in->size = 4; - // - //for (int r = 0; r < ItemCount; r++, eq++) { - // - // uint32 Length = 0; - // - // 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); - // } - //} - // - //delete[] __emu_buffer; - // - ////Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - ////Log.Hex(Logs::Netcode, in->pBuffer, in->size); - // - //dest->FastQueuePacket(&in, ack_req); + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); } ENCODE(OP_ClickObjectAction) @@ -1549,31 +1491,33 @@ namespace RoF2 ENCODE(OP_ItemPacket) { - //consume the packet - EQApplicationPacket *in = *p; - *p = nullptr; + delete *p; - 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); - - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0, old_item_pkt->PacketType); - - if (!serialized) { - 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); - - delete[] __emu_buffer; - safe_delete_array(serialized); - dest->FastQueuePacket(&in, ack_req); + ////consume the packet + //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); + // + //uint32 length; + //char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0, old_item_pkt->PacketType); + // + //if (!serialized) { + // 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); + // + //delete[] __emu_buffer; + //safe_delete_array(serialized); + //dest->FastQueuePacket(&in, ack_req); } ENCODE(OP_ItemVerifyReply) @@ -5258,7 +5202,7 @@ namespace RoF2 //sprintf(hdr.unknown000, "06e0002Y1W00"); - snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID); + snprintf(hdr.tracking_id, sizeof(hdr.tracking_id), "%016d", item->ID); hdr.stacksize = stackable ? charges : 1; hdr.unknown004 = 0; @@ -5794,6 +5738,499 @@ namespace RoF2 return item_serial; } + void SerializeItem(EQEmu::MemoryBuffer &packet_data, EQEmu::ItemInstance *inst, int container_id, int slot_id, int bag_id, int aug_id) { + int ornamentation_augtype = RuleI(Character, OrnamentationAugmentType); + uint8 null_term = 0; + bool stackable = inst->IsStackable(); + uint32 merchant_slot = inst->GetMerchantSlot(); + uint32 charges = inst->GetCharges(); + + const ItemData *item = inst->GetBaseItem(); + RoF2::structs::ItemSerializationHeader hdr; + + snprintf(hdr.tracking_id, sizeof(hdr.tracking_id), "%016d", inst->GetSerialNumber()); + + hdr.stacksize = stackable ? charges : 1; + hdr.unknown004 = 0; + + hdr.slot_type = (merchant_slot == 0) ? container_id : 9; // 9 is merchant 20 is reclaim items? + hdr.main_slot = (merchant_slot == 0) ? slot_id : merchant_slot; + hdr.sub_slot = (merchant_slot == 0) ? bag_id : 0xffff; + hdr.aug_slot = (merchant_slot == 0) ? aug_id : 0xffff; + + hdr.price = inst->GetPrice(); + hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); + //hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; + hdr.scaled_value = 0; + + hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.unknown028 = 0; + hdr.last_cast_time = inst->GetRecastTimestamp(); + hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); + hdr.inst_nodrop = inst->GetAttuned() ? 1 : 0; + hdr.unknown044 = 0; + hdr.unknown048 = 0; + hdr.unknown052 = 0; + hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; + packet_data.Write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader)); + + if(item->EvolvingLevel > 0) { + RoF2::structs::EvolvingItem evotop; + evotop.unknown001 = 0; + evotop.unknown002 = 0; + evotop.unknown003 = 0; + evotop.unknown004 = 0; + evotop.evoLevel = item->EvolvingLevel; + evotop.progress = 95.512; + evotop.Activated = 1; + evotop.evomaxlevel = 7; + packet_data.Write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem)); + } + + uint32 orn_icon = 0; + uint32 hero_model = 0; + + //if(inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) + //{ + // char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + // //Mainhand + // packet_data.Write(tmp, strlen(tmp)); + // packet_data.Write((const char*)&null_term, sizeof(uint8)); + // //Offhand + // ss.write(tmp, strlen(tmp)); + // ss.write((const char*)&null_term, sizeof(uint8)); + // orn_icon = inst->GetOrnamentationIcon(); + // hero_model = inst->GetOrnamentHeroModel(InventoryOld::CalcMaterialFromSlot(slot_id_in)); + //} + //else + //{ + packet_data.Write((const char*)&null_term, sizeof(uint8)); // no main hand Ornamentation + packet_data.Write((const char*)&null_term, sizeof(uint8)); // no off hand Ornamentation + //} + + RoF2::structs::ItemSerializationHeaderFinish hdrf; + hdrf.ornamentIcon = orn_icon; + hdrf.unknowna1 = 0xffffffff; + hdrf.ornamentHeroModel = hero_model; + hdrf.unknown063 = 0; + hdrf.Copied = 0; + hdrf.unknowna4 = 0xffffffff; + hdrf.unknowna5 = 0; + hdrf.ItemClass = item->ItemClass; + + packet_data.Write((const char*)&hdrf, sizeof(RoF2::structs::ItemSerializationHeaderFinish)); + + if(strlen(item->Name) > 0) + { + packet_data.Write(item->Name, strlen(item->Name)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + if(strlen(item->Lore) > 0) + { + packet_data.Write(item->Lore, strlen(item->Lore)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + if(strlen(item->IDFile) > 0) + { + packet_data.Write(item->IDFile, strlen(item->IDFile)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + packet_data.Write((const char*)&null_term, sizeof(uint8)); + + RoF2::structs::ItemBodyStruct ibs; + memset(&ibs, 0, sizeof(RoF2::structs::ItemBodyStruct)); + + ibs.id = item->ID; + ibs.weight = item->Weight; + ibs.norent = item->NoRent; + ibs.nodrop = item->NoDrop; + ibs.attune = item->Attuneable; + ibs.size = item->Size; + ibs.slots = SwapBits21and22(item->Slots); + ibs.price = item->Price; + ibs.icon = item->Icon; + ibs.unknown1 = 1; + ibs.unknown2 = 1; + ibs.BenefitFlag = item->BenefitFlag; + ibs.tradeskills = item->Tradeskills; + ibs.CR = item->CR; + ibs.DR = item->DR; + ibs.PR = item->PR; + ibs.MR = item->MR; + ibs.FR = item->FR; + ibs.SVCorruption = item->SVCorruption; + ibs.AStr = item->AStr; + ibs.ASta = item->ASta; + ibs.AAgi = item->AAgi; + ibs.ADex = item->ADex; + ibs.ACha = item->ACha; + ibs.AInt = item->AInt; + ibs.AWis = item->AWis; + + ibs.HP = item->HP; + ibs.Mana = item->Mana; + ibs.Endur = item->Endur; + ibs.AC = item->AC; + ibs.regen = item->Regen; + ibs.mana_regen = item->ManaRegen; + ibs.end_regen = item->EnduranceRegen; + ibs.Classes = item->Classes; + ibs.Races = item->Races; + ibs.Deity = item->Deity; + ibs.SkillModValue = item->SkillModValue; + ibs.SkillModMax = 0xffffffff; + ibs.SkillModType = (int8)(item->SkillModType); + ibs.SkillModExtra = 0; + ibs.BaneDmgRace = item->BaneDmgRace; + ibs.BaneDmgBody = item->BaneDmgBody; + ibs.BaneDmgRaceAmt = item->BaneDmgRaceAmt; + 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.RecSkill = item->RecSkill; + ibs.BardType = item->BardType; + ibs.BardValue = item->BardValue; + ibs.Light = item->Light; + ibs.Delay = item->Delay; + ibs.ElemDmgType = item->ElemDmgType; + ibs.ElemDmgAmt = item->ElemDmgAmt; + ibs.Range = item->Range; + ibs.Damage = item->Damage; + ibs.Color = item->Color; + ibs.Prestige = 0; + ibs.ItemType = item->ItemType; + ibs.Material = item->Material; + ibs.MaterialUnknown1 = 0; + ibs.EliteMaterial = item->EliteMaterial; + ibs.HerosForgeModel = item->HerosForgeModel; + ibs.MaterialUnknown2 = 0; + ibs.SellRate = item->SellRate; + ibs.CombatEffects = item->CombatEffects; + ibs.Shielding = item->Shielding; + ibs.StunResist = item->StunResist; + ibs.StrikeThrough = item->StrikeThrough; + ibs.ExtraDmgSkill = item->ExtraDmgSkill; + ibs.ExtraDmgAmt = item->ExtraDmgAmt; + ibs.SpellShield = item->SpellShield; + ibs.Avoidance = item->Avoidance; + ibs.Accuracy = item->Accuracy; + ibs.CharmFileID = item->CharmFileID; + ibs.FactionAmt1 = item->FactionAmt1; + ibs.FactionMod1 = item->FactionMod1; + ibs.FactionAmt2 = item->FactionAmt2; + ibs.FactionMod2 = item->FactionMod2; + ibs.FactionAmt3 = item->FactionAmt3; + ibs.FactionMod3 = item->FactionMod3; + ibs.FactionAmt4 = item->FactionAmt4; + ibs.FactionMod4 = item->FactionMod4; + + packet_data.Write((const char*)&ibs, sizeof(RoF2::structs::ItemBodyStruct)); + + //charm text + if(strlen(item->CharmFile) > 0) + { + packet_data.Write((const char*)item->CharmFile, strlen(item->CharmFile)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + //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)); + + isbs.augtype = item->AugType; + isbs.augrestrict2 = -1; + isbs.augrestrict = item->AugRestrict; + + for(int x = AUG_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]; + } + + isbs.ldonpoint_type = item->PointType; + isbs.ldontheme = item->LDoNTheme; + isbs.ldonprice = item->LDoNPrice; + isbs.ldonsellbackrate = item->LDoNSellBackRate; + isbs.ldonsold = item->LDoNSold; + + isbs.bagtype = item->BagType; + isbs.bagslots = item->BagSlots; + isbs.bagsize = item->BagSize; + isbs.wreduction = item->BagWR; + + isbs.book = item->Book; + isbs.booktype = item->BookType; + + packet_data.Write((const char*)&isbs, sizeof(RoF2::structs::ItemSecondaryBodyStruct)); + + if(strlen(item->Filename) > 0) + { + packet_data.Write((const char*)item->Filename, strlen(item->Filename)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + //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)); + + itbs.loregroup = item->LoreGroup; + itbs.artifact = item->ArtifactFlag; + itbs.summonedflag = item->SummonedFlag; + itbs.favor = item->Favor; + itbs.fvnodrop = item->FVNoDrop; + itbs.dotshield = item->DotShielding; + itbs.atk = item->Attack; + itbs.haste = item->Haste; + itbs.damage_shield = item->DamageShield; + itbs.guildfavor = item->GuildFavor; + itbs.augdistil = item->AugDistiller; + itbs.unknown3 = 0xffffffff; + itbs.unknown4 = 0; + itbs.no_pet = item->NoPet; + itbs.unknown5 = 0; + + itbs.potion_belt_enabled = item->PotionBelt; + itbs.potion_belt_slots = item->PotionBeltSlots; + itbs.stacksize = stackable ? item->StackSize : 0; + itbs.no_transfer = item->NoTransfer; + itbs.expendablearrow = item->ExpendableArrow; + + itbs.unknown8 = 0; + itbs.unknown9 = 0; + itbs.unknown10 = 0; + itbs.unknown11 = 0; + itbs.unknown12 = 0; + itbs.unknown13 = 0; + itbs.unknown14 = 0; + + packet_data.Write((const char*)&itbs, sizeof(RoF2::structs::ItemTertiaryBodyStruct)); + + // 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)); + + ices.effect = item->Click.Effect; + ices.level2 = item->Click.Level2; + ices.type = item->Click.Type; + ices.level = item->Click.Level; + ices.max_charges = item->MaxCharges; + ices.cast_time = item->CastTime; + ices.recast = item->RecastDelay; + ices.recast_type = item->RecastType; + + packet_data.Write((const char*)&ices, sizeof(RoF2::structs::ClickEffectStruct)); + + if(strlen(item->ClickName) > 0) + { + packet_data.Write((const char*)item->ClickName, strlen(item->ClickName)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + packet_data.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)); + + ipes.effect = item->Proc.Effect; + ipes.level2 = item->Proc.Level2; + ipes.type = item->Proc.Type; + ipes.level = item->Proc.Level; + ipes.procrate = item->ProcRate; + + packet_data.Write((const char*)&ipes, sizeof(RoF2::structs::ProcEffectStruct)); + + if(strlen(item->ProcName) > 0) + { + packet_data.Write((const char*)item->ProcName, strlen(item->ProcName)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + packet_data.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)); + + iwes.effect = item->Worn.Effect; + iwes.level2 = item->Worn.Level2; + iwes.type = item->Worn.Type; + iwes.level = item->Worn.Level; + + packet_data.Write((const char*)&iwes, sizeof(RoF2::structs::WornEffectStruct)); + + if(strlen(item->WornName) > 0) + { + packet_data.Write((const char*)item->WornName, strlen(item->WornName)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + packet_data.Write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + + RoF2::structs::WornEffectStruct ifes; + memset(&ifes, 0, sizeof(RoF2::structs::WornEffectStruct)); + + ifes.effect = item->Focus.Effect; + ifes.level2 = item->Focus.Level2; + ifes.type = item->Focus.Type; + ifes.level = item->Focus.Level; + + packet_data.Write((const char*)&ifes, sizeof(RoF2::structs::WornEffectStruct)); + + if(strlen(item->FocusName) > 0) + { + packet_data.Write((const char*)item->FocusName, strlen(item->FocusName)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + packet_data.Write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + + RoF2::structs::WornEffectStruct ises; + memset(&ises, 0, sizeof(RoF2::structs::WornEffectStruct)); + + ises.effect = item->Scroll.Effect; + ises.level2 = item->Scroll.Level2; + ises.type = item->Scroll.Type; + ises.level = item->Scroll.Level; + + packet_data.Write((const char*)&ises, sizeof(RoF2::structs::WornEffectStruct)); + + if(strlen(item->ScrollName) > 0) + { + packet_data.Write((const char*)item->ScrollName, strlen(item->ScrollName)); + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + else + { + packet_data.Write((const char*)&null_term, sizeof(uint8)); + } + + packet_data.Write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + + // Bard Effect? + RoF2::structs::WornEffectStruct ibes; + memset(&ibes, 0, sizeof(RoF2::structs::WornEffectStruct)); + + ibes.effect = item->Bard.Effect; + ibes.level2 = item->Bard.Level2; + ibes.type = item->Bard.Type; + ibes.level = item->Bard.Level; + //ibes.unknown6 = 0xffffffff; + + packet_data.Write((const char*)&ibes, sizeof(RoF2::structs::WornEffectStruct)); + + packet_data.Write((const char*)&null_term, sizeof(uint8)); + + packet_data.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)); + + iqbs.scriptfileid = item->ScriptFileID; + iqbs.quest_item = item->QuestItemFlag; + iqbs.Power = 0; + iqbs.Purity = item->Purity; + iqbs.unknown16 = 0; + iqbs.BackstabDmg = item->BackstabDmg; + iqbs.DSMitigation = item->DSMitigation; + iqbs.HeroicStr = item->HeroicStr; + iqbs.HeroicInt = item->HeroicInt; + iqbs.HeroicWis = item->HeroicWis; + iqbs.HeroicAgi = item->HeroicAgi; + iqbs.HeroicDex = item->HeroicDex; + iqbs.HeroicSta = item->HeroicSta; + iqbs.HeroicCha = item->HeroicCha; + iqbs.HeroicMR = item->HeroicMR; + iqbs.HeroicFR = item->HeroicFR; + iqbs.HeroicCR = item->HeroicCR; + iqbs.HeroicDR = item->HeroicDR; + iqbs.HeroicPR = item->HeroicPR; + iqbs.HeroicSVCorrup = item->HeroicSVCorrup; + iqbs.HealAmt = item->HealAmt; + iqbs.SpellDmg = item->SpellDmg; + 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 = inst->GetSubItemCount(); + + packet_data.Write((const char*)&iqbs, sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); + + for(int x = 0; x < 255; ++x) { + auto sub_inst = inst->Get(x); + + if(sub_inst) { + packet_data.Write((const char*)&x, sizeof(uint32)); + SerializeItem(packet_data, sub_inst.get(), container_id, slot_id, x, -1); + } + } + } + static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 serverSlot, ItemPacketType PacketType) { structs::ItemSlotStruct RoF2Slot; diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index dd5b95863..bb53f7d7c 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -4407,7 +4407,7 @@ struct RoF2SlotStruct struct ItemSerializationHeader { -/*000*/ char unknown000[17]; // New for HoT. Looks like a string. +/*000*/ char tracking_id[17]; // New for HoT. Looks like a string. /*017*/ uint32 stacksize; /*021*/ uint32 unknown004; /*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ? diff --git a/common/shareddb.cpp b/common/shareddb.cpp index e86135fbb..f7f18aeb8 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -15,6 +15,14 @@ #include "shareddb.h" #include "string_util.h" +uint32 ItemInstanceSerial = 1; +static inline uint32 GetNextItemInstanceSerial() { + ItemInstanceSerial++; + return ItemInstanceSerial; +} + + + SharedDatabase::SharedDatabase() : Database(), skill_caps_mmf(nullptr), items_mmf(nullptr), items_hash(nullptr), faction_mmf(nullptr), faction_hash(nullptr), loot_table_mmf(nullptr), loot_table_hash(nullptr), loot_drop_mmf(nullptr), loot_drop_hash(nullptr), base_data_mmf(nullptr) @@ -516,7 +524,6 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::Inventory *inv) uint32 ornament_icon = (uint32)std::stoul(row[9]); uint32 ornament_idfile = (uint32)std::stoul(row[10]); uint32 ornament_hero_model = (uint32)std::stoul(row[11]); - uint64 tracking_id = (uint64)std::stoull(row[12]); inst->SetColor(color); inst->SetAttuned(attuned ? true : false); @@ -524,7 +531,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::Inventory *inv) inst->SetOrnamentIcon(ornament_icon); inst->SetOrnamentIDFile(ornament_idfile); inst->SetOrnamentHeroModel(ornament_hero_model); - inst->SetTrackingID(tracking_id); + inst->SetTrackingID(row[12]); auto *item = inst->GetItem(); if(item->RecastDelay) { @@ -1265,7 +1272,9 @@ std::shared_ptr SharedDatabase::CreateItem(uint32 item_id, charges = 1; } - return std::shared_ptr(new EQEmu::ItemInstance(item, charges)); + std::shared_ptr inst = std::shared_ptr(new EQEmu::ItemInstance(item, charges)); + inst->SetSerialNumber(GetNextItemInstanceSerial()); + return inst; } return std::shared_ptr(nullptr);