Loading...   

  • Created By Uleat On: 11:46 AM September 08, 2014
  • Link

 common/item.h          | 33 ++++++++++++++++++++++++++++++++-
 common/patches/rof.cpp | 38 ++++++++++++++++++++++++++++++--------
 zone/client_packet.cpp |  9 +++++++++
 zone/command.cpp       |  6 ++++++
 zone/forage.cpp        |  8 ++++++++
 zone/inventory.cpp     | 30 ++++++++++++++++++++++++++----
 zone/spell_effects.cpp |  9 +++++++++
 7 files changed, 120 insertions(+), 13 deletions(-)

diff --git a/common/item.h b/common/item.h
index c24c708..7acad73 100644
--- a/common/item.h
+++ b/common/item.h
@@ -87,6 +87,7 @@ enum {
 class ItemInstQueue
 {
 public:
+	ItemInstQueue() { current_ptr = 0; }
 	~ItemInstQueue();
 	/////////////////////////
 	// Public Methods
@@ -101,13 +102,38 @@ public:
 	ItemInst* peek_front() const;
 	inline int size()		{ return static_cast<int>(m_list.size()); }
 
+	// buffer-related
+	/*
+		NOTES:
+
+		These are not desync safe..but, you'd be an idiot if you pushed 37 or more items to your cursor :P
+		..Desync applies applies to all clients..not just RoF+ that use this pointer
+
+		This process only tested with #summonitem (does not require the cursor to be pre-loaded like v0.1)
+
+		This process contains a bug when comparing to client behavior...
+
+		'ItemPacketSummonItem' changes outside of Client::SummonItem() need to be tested..especially the two const_cast<t>(v) cases
+
+		Bug:
+		- #summonitem pushes correctly and Client::SwapItem() properly reports Limbo main slot (+ 10000)
+		- bug occurs at transistion from back to front
+		- queue order and buffer pushed as -> {33, 34, 35, 0, 1, 2}
+		- client reports a move item as -> {0, 1, 2, 33, 34, 35} - a definite desync
+		- changes needed to fix this bug 'should' be localized to the 3 methods below...
+	*/
+
+	bool buffer_full()	{ return (m_list.size() >= 37); } // buffer is 36..1 is added since we store MainCursor as 'push_front'
+	int16 buffer_ptr()	{ return current_ptr; }
+	void advance_ptr()	{ ++current_ptr; current_ptr %= 36; }
+
 protected:
 	/////////////////////////
 	// Protected Members
 	/////////////////////////
 
+	int16 current_ptr;
 	std::list<ItemInst*> m_list;
-
 };
 
 // ########################################
@@ -134,6 +160,11 @@ public:
 	inline iter_queue cursor_end()		{ return m_cursor.end(); }
 	inline bool CursorEmpty()		{ return (m_cursor.size() == 0); }
 
+	// cursor buffer pointer accessors
+	bool IsBufferFull()			{ return m_cursor.buffer_full(); }
+	int16 GetBufferPointer()	{ return m_cursor.buffer_ptr(); }
+	void AdvanceBufferPointer()	{ m_cursor.advance_ptr(); }
+
 	// Retrieve a read-only item from inventory
 	inline const ItemInst* operator[](int16 slot_id) const { return GetItem(slot_id); }
 
diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp
index d5303cc..f30b254 100644
--- a/common/patches/rof.cpp
+++ b/common/patches/rof.cpp
@@ -2244,8 +2244,10 @@ ENCODE(OP_ItemPacket) {
 	ItemPacket_Struct *old_item_pkt=(ItemPacket_Struct *)__emu_buffer;
 	InternalSerializedItem_Struct *int_struct=(InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem);
 
+	bool is_buffer_item = old_item_pkt->PacketType == ItemPacketSummonItem;
+
 	uint32 length;
-	char *serialized=SerializeItem((ItemInst *)int_struct->inst,int_struct->slot_id,&length,0);
+	char *serialized = SerializeItem((ItemInst *)int_struct->inst, (is_buffer_item ? 10000 : int_struct->slot_id), &length, 0);
 
 	if (!serialized) {
 		_log(NET__STRUCTS, "Serialization failed on item slot %d.",int_struct->slot_id);
@@ -4307,8 +4309,19 @@ DECODE(OP_MoveItem)
 
 	//_log(NET__ERROR, "Moved item from %u to %u", eq->from_slot.MainSlot, eq->to_slot.MainSlot);
 	_log(NET__ERROR, "MoveItem SlotType from %i to %i, MainSlot from %i to %i, SubSlot from %i to %i, AugSlot from %i to %i, Unknown01 from %i to %i, Number %u", eq->from_slot.SlotType, eq->to_slot.SlotType, eq->from_slot.MainSlot, eq->to_slot.MainSlot, eq->from_slot.SubSlot, eq->to_slot.SubSlot, eq->from_slot.AugSlot, eq->to_slot.AugSlot, eq->from_slot.Unknown01, eq->to_slot.Unknown01, eq->number_in_stack);
-	emu->from_slot = RoFToServerSlot(eq->from_slot);
-	emu->to_slot = RoFToServerSlot(eq->to_slot);
+	
+	if (eq->from_slot.SlotType != maps::MapLimbo) {
+		emu->from_slot = RoFToServerSlot(eq->from_slot);
+		emu->to_slot = RoFToServerSlot(eq->to_slot);
+	}
+	else { // not needed in live code
+		// these have to be the same value to trigger the SwapItem::Message()
+		// from should be {5, eq->from_slot.MainSlot, -1, -1} - can verify in the log message above
+		// to should be {0, 33, -1, -1}
+		emu->from_slot = 10000 + eq->from_slot.MainSlot;
+		emu->to_slot = 10000 + eq->from_slot.MainSlot;
+	}
+	
 	IN(number_in_stack);
 
 	_hex(NET__ERROR, eq, sizeof(structs::MoveItem_Struct));
@@ -4895,12 +4908,21 @@ char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint
 	hdr.stacksize = stackable ? charges : 1;
 	hdr.unknown004 = 0;
 
-	structs::ItemSlotStruct slot_id = ServerToRoFSlot(slot_id_in);
+	if (slot_id_in != 10000) {
+		structs::ItemSlotStruct slot_id = ServerToRoFSlot(slot_id_in);
+
+		hdr.slot_type = (merchant_slot == 0) ? slot_id.SlotType : 9; // 9 is merchant 20 is reclaim items?
+		hdr.main_slot = (merchant_slot == 0) ? slot_id.MainSlot : merchant_slot;
+		hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubSlot : 0xffff;
+		hdr.unknown013 = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff;
+	}
+	else {
+		hdr.slot_type = maps::MapLimbo;
+		hdr.main_slot = inst->GetCurrentSlot();
+		hdr.sub_slot = ~0;
+		hdr.unknown013 = ~0;
+	}
 
-	hdr.slot_type = (merchant_slot == 0) ? slot_id.SlotType : 9; // 9 is merchant 20 is reclaim items?
-	hdr.main_slot = (merchant_slot == 0) ? slot_id.MainSlot : merchant_slot;
-	hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubSlot : 0xffff;
-	hdr.unknown013 = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff;
 	//hdr.unknown013 = 0xffff;
 	hdr.price = inst->GetPrice();
 	hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount();
diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp
index 9d7c9e0..0d44baf 100644
--- a/zone/client_packet.cpp
+++ b/zone/client_packet.cpp
@@ -9443,6 +9443,11 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
 			// First item cursor is sent in bulk inventory packet
 			if (it==m_inv.cursor_begin())
 				continue;
+
+			ItemInst* fixit = *it;
+			fixit->SetCurrentSlot(m_inv.GetBufferPointer()); // borrowing the db blob corpse slot identifier
+			m_inv.AdvanceBufferPointer();
+
 			const ItemInst *inst=*it;
 			SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
 		}
@@ -12109,6 +12114,10 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
 			{
 				PushItemOnCursor(*inst);
 
+				// it doesn't matter if the Cloned() instance doesn't reflect this..the pointer is only used for client update 
+				inst->SetCurrentSlot(m_inv.GetBufferPointer()); // borrowing the db blob corpse slot identifier
+				m_inv.AdvanceBufferPointer();
+
 				SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
 
 				GuildBanks->DeleteItem(GuildID(), gbwis->Area, gbwis->SlotID, gbwis->Quantity);
diff --git a/zone/command.cpp b/zone/command.cpp
index aa7e137..daff40c 100644
--- a/zone/command.cpp
+++ b/zone/command.cpp
@@ -11417,6 +11417,12 @@ void command_zopp(Client *c, const Seperator *sep)
 		}
 
 		ItemInst* FakeItemInst = database.CreateItem(FakeItem, charges);
+		
+		if (slotid == MainCursor && packettype == ItemPacketSummonItem) {
+			FakeItemInst->SetCurrentSlot(c->GetInv().GetBufferPointer()); // borrowing the db blob corpse slot identifier
+			c->GetInv().AdvanceBufferPointer();
+		}
+
 		c->SendItemPacket(slotid, FakeItemInst, packettype);
 		c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u) with %i %s to slot %i.", packettype==ItemPacketTrade?"Trade":"Summon", FakeItem->Name, itemid, charges, abs(charges==1)?"charge":"charges", slotid);
 		safe_delete(FakeItemInst);
diff --git a/zone/forage.cpp b/zone/forage.cpp
index 4a39d50..b0c53c4 100644
--- a/zone/forage.cpp
+++ b/zone/forage.cpp
@@ -348,6 +348,10 @@ void Client::GoFish()
 			else
 			{
 				PushItemOnCursor(*inst);
+
+				inst->SetCurrentSlot(m_inv.GetBufferPointer()); // borrowing the db blob corpse slot identifier
+				m_inv.AdvanceBufferPointer();
+
 				SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
 				if(RuleB(TaskSystem, EnableTaskSystem))
 					UpdateTasksForItem(ActivityFish, food_id);
@@ -462,6 +466,10 @@ void Client::ForageItem(bool guarantee) {
 			}
 			else {
 				PushItemOnCursor(*inst);
+
+				inst->SetCurrentSlot(m_inv.GetBufferPointer()); // borrowing the db blob corpse slot identifier
+				m_inv.AdvanceBufferPointer();
+
 				SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
 				if(RuleB(TaskSystem, EnableTaskSystem))
 					UpdateTasksForItem(ActivityForage, foragedfood);
diff --git a/zone/inventory.cpp b/zone/inventory.cpp
index a4625bf..bb02371 100644
--- a/zone/inventory.cpp
+++ b/zone/inventory.cpp
@@ -581,6 +581,10 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
 	// put item into inventory
 	if (to_slot == MainCursor) {
 		PushItemOnCursor(*inst);
+
+		inst->SetCurrentSlot(m_inv.GetBufferPointer()); // borrowing the db blob corpse slot identifier
+		m_inv.AdvanceBufferPointer();
+
 		SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
 	}
 	else {
@@ -815,6 +819,12 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
 	m_inv.PushCursor(inst);
 
 	if (client_update) {
+		// the calling functions that pass client_update as 'false' already do this..this is for the 'true' cases
+		ItemInst fixit = const_cast<ItemInst&>(inst);
+
+		fixit.SetCurrentSlot(m_inv.GetBufferPointer()); // borrowing the db blob corpse slot identifier
+		m_inv.AdvanceBufferPointer();
+
 		SendItemPacket(MainCursor, &inst, ItemPacketSummonItem);
 	}
 
@@ -830,8 +840,19 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client
 	else
 		m_inv.PutItem(slot_id, inst);
 
-	if (client_update)
-		SendItemPacket(slot_id, &inst, ((slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade));
+	if (client_update) {
+		if (slot_id == MainCursor) {
+			ItemInst fixit = const_cast<ItemInst&>(inst);
+
+			fixit.SetCurrentSlot(m_inv.GetBufferPointer()); // borrowing the db blob corpse slot identifier
+			m_inv.AdvanceBufferPointer();
+
+			SendItemPacket(slot_id, &inst, ItemPacketSummonItem);
+		}
+		else {
+			SendItemPacket(slot_id, &inst, ItemPacketTrade);
+		}
+	}
 
 	if (slot_id == MainCursor) {
 		std::list<ItemInst*>::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end();
@@ -1270,7 +1291,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
 	uint32 dst_slot_check = move_in->to_slot;
 	uint32 stack_count_check = move_in->number_in_stack;
 
-	if(!IsValidSlot(src_slot_check)){
+	if(!IsValidSlot(src_slot_check) && (src_slot_check < 10000 || src_slot_check > 10035)) { // {10000..10035} not needed in live code 
 		// SoF+ sends a Unix timestamp (should be int32) for src and dst slots every 10 minutes for some reason.
 		if(src_slot_check < 2147483647)
 			Message(13, "Warning: Invalid slot move from slot %u to slot %u with %u charges!", src_slot_check, dst_slot_check, stack_count_check);
@@ -1278,7 +1299,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
 		return false;
 	}
 
-	if(!IsValidSlot(dst_slot_check)) {
+	if (!IsValidSlot(dst_slot_check) && (dst_slot_check < 10000 || dst_slot_check > 10035)) { // {10000..10035} not needed in live code
 		// SoF+ sends a Unix timestamp (should be int32) for src and dst slots every 10 minutes for some reason.
 		if(src_slot_check < 2147483647)
 			Message(13, "Warning: Invalid slot move from slot %u to slot %u with %u charges!", src_slot_check, dst_slot_check, stack_count_check);
@@ -1289,6 +1310,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
 	// This could be expounded upon at some point to let the server know that
 	// the client has moved a buffered cursor item onto the active cursor -U
 	if (move_in->from_slot == move_in->to_slot) { // Item summon, no further proccessing needed
+		this->Message(15, "Client::SwapItem() - Client move item request [from: %i, to: %i]", move_in->from_slot, move_in->to_slot);
 		if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
 		return true;
 	}
diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp
index b10c436..204f86d 100644
--- a/zone/spell_effects.cpp
+++ b/zone/spell_effects.cpp
@@ -1164,7 +1164,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
 							charges = 1;
 
 						if (SummonedItem) {
+
 							c->PushItemOnCursor(*SummonedItem);
+
+							SummonedItem->SetCurrentSlot(c->GetInv().GetBufferPointer()); // borrowing the db blob corpse slot identifier
+							c->GetInv().AdvanceBufferPointer();
+
 							c->SendItemPacket(MainCursor, SummonedItem, ItemPacketSummonItem);
 							safe_delete(SummonedItem);
 						}
@@ -2990,6 +2995,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
 	if (SummonedItem) {
 		Client *c=CastToClient();
 		c->PushItemOnCursor(*SummonedItem);
+
+		SummonedItem->SetCurrentSlot(c->GetInv().GetBufferPointer()); // borrowing the db blob corpse slot identifier
+		c->GetInv().AdvanceBufferPointer();
+
 		c->SendItemPacket(MainCursor, SummonedItem, ItemPacketSummonItem);
 		safe_delete(SummonedItem);
 	}

Raw Paste Data