Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Server Code Submissions

 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
  #8  
Old 11-02-2012, 06:26 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

THIS IS A BETA PATCH. CLIENT TESTING IS STILL NEEDED

The previous post is referenced in the patch to eliminate loading up the code.


For now, this is the best I can do. Players, 'use #resyncinv help' for a quick description of what to expect.


It probably still needs minor timing tweaking, but here it is:

[ResyncInv.patch] (9 files, 627 lines)
Code:
Index: common/Item.cpp
===================================================================
--- common/Item.cpp	(revision 2244)
+++ common/Item.cpp	(working copy)
@@ -668,22 +668,20 @@
 }
 
 // Swap items in inventory
-void Inventory::SwapItem(sint16 slot_a, sint16 slot_b)
-{
-	// Temp holding area for a
+bool Inventory::SwapItem(sint16 slot_a, sint16 slot_b)
+{ // Modified to fail all item swaps into illegal slots..'return false' will trigger resync -U
+
+	// Temp holding areas for a & b
 	ItemInst* inst_a = GetItem(slot_a);
+	ItemInst* inst_b = GetItem(slot_b);
 
-	if(inst_a)
-	{
-		if(!inst_a->IsSlotAllowed(slot_b))
-			return;
-	}
+	if(inst_a) { if(!inst_a->IsSlotAllowed(slot_b)) { return false; } }
+	if(inst_b) { if(!inst_b->IsSlotAllowed(slot_a)) { return false; } }
 
-	// Copy b->a
-	_PutItem(slot_a, GetItem(slot_b));
-	
-	// Copy a->b
-	_PutItem(slot_b, inst_a);
+	_PutItem(slot_a, inst_b); // Copy b->a
+	_PutItem(slot_b, inst_a); // Copy a->b
+
+	return true;
 }
 
 // Checks that user has at least 'quantity' number of items in a given inventory slot
Index: common/Item.h
===================================================================
--- common/Item.h	(revision 2244)
+++ common/Item.h	(working copy)
@@ -144,7 +144,8 @@
 	inline iter_queue cursor_begin()	{ return m_cursor.begin(); }
 	inline iter_queue cursor_end()		{ return m_cursor.end(); }
 	inline bool CursorEmpty()		{ return (m_cursor.size() == 0); }
-	
+	inline int CursorSize()			{ return m_cursor.size(); }
+
 	// Retrieve a read-only item from inventory
 	inline const ItemInst* operator[](sint16 slot_id) const { return GetItem(slot_id); }
 	
@@ -154,8 +155,8 @@
 	// Add item to cursor queue
 	sint16 PushCursor(const ItemInst& inst);
 	
-	// Swap items in inventory
-	void SwapItem(sint16 slot_a, sint16 slot_b);
+	// Swap items in inventory (Changed to bool return function -U)
+	bool SwapItem(sint16 slot_a, sint16 slot_b);
 
 	// Remove item from inventory
 	bool DeleteItem(sint16 slot_id, uint8 quantity=0);
Index: zone/client.cpp
===================================================================
--- zone/client.cpp	(revision 2244)
+++ zone/client.cpp	(working copy)
@@ -324,6 +324,14 @@
 	}
 	MaxXTargets = 5;	
 	XTargetAutoAddHaters = true;
+
+	// ResyncInventory() Initialization Stuff
+	ri_CallBackTimer = new Timer(0);
+	ri_Count = 0;
+	ri_Step = 0;
+	ri_CursorCount = 0;
+	ri_CallBackDelay = 0;
+
 }
 
 Client::~Client() {
@@ -406,6 +414,7 @@
 	safe_delete(taskstate);
 	safe_delete(KarmaUpdateTimer);
 	safe_delete(GlobalChatLimiterTimer);
+	safe_delete(ri_CallBackTimer); // ResyncInventory() Stuff
 	safe_delete(qGlobals);
 	safe_delete(adventure_request_timer);
 	safe_delete(adventure_create_timer);
Index: zone/client.h
===================================================================
--- zone/client.h	(revision 2244)
+++ zone/client.h	(working copy)
@@ -761,6 +761,7 @@
 	bool	PushItemOnCursor(const ItemInst& inst, bool client_update = false);
 	void	DeleteItemInInventory(sint16 slot_id, sint8 quantity = 0, bool client_update = false, bool update_db = true);
 	bool	SwapItem(MoveItem_Struct* move_in);
+	void	ResyncInventory(bool server_call = true, bool timer_callback = false);
 	void	PutLootInInventory(sint16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data = 0);
 	bool	AutoPutLootInInventory(ItemInst& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0);
 	void	SummonItem(uint32 item_id, sint16 charges = 0, uint32 aug1=0, uint32 aug2=0, uint32 aug3=0, uint32 aug4=0, uint32 aug5=0, bool attuned=false, uint16 to_slot=SLOT_CURSOR);
@@ -1397,6 +1398,25 @@
 
 	struct XTarget_Struct XTargets[XTARGET_HARDCAP];
 
+	// ResyncInventory() Private Stuff
+	Timer *ri_CallBackTimer;
+	void ResyncInvCallBack();
+	void ResyncInvProcSlots(sint16 slot_begin, sint16 slot_end, int8 sync_method = 128);
+	void ResyncInvClDelItem(sint16 slot_id, bool alt_delete = false);
+	int8 ri_Count;
+	int8 ri_Step;
+	int8 ri_CursorCount;
+	int32 ri_CallBackDelay;
+	// float ri_CallBackDelayModifier = ??
+#define RI_COUNT_LIMIT	3
+#define RI_STEP_COUNT	20
+#define RI_CURSOR_LIMIT	37
+#define RI_BIT_AU		1		// Alternate Update
+#define RI_BIT_UN		2		// Update Null
+#define RI_BIT_AD		4		// Alternate Delete
+#define RI_BIT_CP		8		// Check Parent
+#define RI_BIT_BROKEN	128
+
 };
 
 #include "parser.h"
Index: zone/client_packet.cpp
===================================================================
--- zone/client_packet.cpp	(revision 2244)
+++ zone/client_packet.cpp	(working copy)
@@ -3306,62 +3306,51 @@
 				casting_spell_id);
 			database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName());
 			safe_delete_array(detect);
+			// This Kick() could be deleted unless an automatic ban is in use. (Unremark the code below) -U
 			Kick();   // Kick client to prevent client and server from getting out-of-sync inventory slots
+			//Message(13, "Warning: You have attempted an item move while casting a spell - this action is not allowed!");
+			//ResyncInventory();
 			return;
 		}
 	}
 
-	// Added checks for illegal bagslot swaps..should help with certain cheats (currently checks personal and cursor bag slots.)
-	// - If a player has used an illegal inventory cheat, they can become bugged at some point (especially concerning lore items.)
-	//* Start
+	// Illegal bagslot useage checks. Currently, user only receives a message if this check is triggered. -U
 	bool mi_hack = false;
 
 	if (mi->from_slot >= 251 && mi->from_slot <= 340) {
-		if (mi->from_slot > 330)
-			mi_hack = true; // why are we moving from a cursor bagslot when you can't open it?
+		if (mi->from_slot > 330) { mi_hack = true; } // move << cursor bagslot
 		else {			
-			sint16 from_invslot = Inventory::CalcSlotId(mi->from_slot);
-			const ItemInst *from_invslotitem = GetInv().GetItem(from_invslot); 
+			sint16 from_parent = m_inv.CalcSlotId(mi->from_slot);
 
-			if (!from_invslotitem) // trying to move from bag slots when parent inventory slot is empty
-				mi_hack = true;
-			else if (from_invslotitem->GetItem()->ItemClass == 1) { // checking the parent inventory slot for container
-				if ((Inventory::CalcBagIdx(mi->from_slot) + 1) > from_invslotitem->GetItem()->BagSlots)
-					mi_hack = true; // trying to move from slots beyond parent container size
-			}
-			else // trying to move from bag slots when inventory slot item is not a container
-				mi_hack = true;
+			if (!m_inv[from_parent]) { mi_hack = true; } // move << empty parent
+			else if (m_inv[from_parent]->GetItem()->ItemClass != 1) { mi_hack = true; } // move << non-container parent
+			else if((m_inv.CalcBagIdx(mi->from_slot) + 1) > m_inv[from_parent]->GetItem()->BagSlots) { mi_hack = true; }// move << beyond container size
 		}
 	}
 
 	if (mi->to_slot >= 251 && mi->to_slot <= 340) {
-		if (mi->to_slot > 330)
-			mi_hack = true; // why are we moving to a cursor bagslot when you can't open it?
-		else {
-			sint16 to_invslot = Inventory::CalcSlotId(mi->to_slot);
-			const ItemInst *to_invslotitem = GetInv().GetItem(to_invslot);
+		if (mi->to_slot > 330) { mi_hack = true; } // move >> cursor bagslot
+		else {			
+			sint16 to_parent = m_inv.CalcSlotId(mi->to_slot);
 
-			if (!to_invslotitem) // trying to move into bag slots when parent inventory slot is empty
-				mi_hack = true;
-			else if (to_invslotitem->GetItem()->ItemClass == 1) { // checking the parent inventory slot for container
-				if ((Inventory::CalcBagIdx(mi->to_slot) + 1) > to_invslotitem->GetItem()->BagSlots)
-					mi_hack = true; // trying to move into slots beyond parent container size
-			}
-			else // trying to move into bag slots when inventory slot item is not a container
-				mi_hack = true;
+			if (!m_inv[to_parent]) { mi_hack = true; } // move >> empty parent 
+			else if (m_inv[to_parent]->GetItem()->ItemClass != 1) { mi_hack = true; } // move >> non-container parent
+			else if((m_inv.CalcBagIdx(mi->to_slot) + 1) > m_inv[to_parent]->GetItem()->BagSlots) { mi_hack = true; }// move >> beyond container size
 		}
 	}
 
-	if (mi_hack) { // a CSD can also cause this condition, but more likely the use of a cheat
-		Message(13, "Hack detected: Illegal use of inventory bag slots!");
-		// TODO: Decide whether to log player as hacker - currently has no teeth...
-		// Kick();
-		// return;
-	} // End */
+	if (mi_hack) { Message(15, "Caution: Illegal use of inaccessable bag slots!"); }
 
-	// if this swapitem call fails, then the server and client could be de-sync'd
-	if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot))
-		Message(0, "Client SwapItem request failure - verify inventory integrity.");
+	if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
+		Message(13, "Client OP_MoveItem request error!");
+		ResyncInventory();
+	
+		if(mi_hack) {
+			Message(15, "Caution: If you use 3rd-party software to manipulate slots,");
+			Message(15, "this action may or may not correct problems in these areas.");
+			Message(15, "To ensure inventory syncronization, you must zone or relog.");
+		}
+	}
 
 	return;
 }
Index: zone/client_process.cpp
===================================================================
--- zone/client_process.cpp	(revision 2244)
+++ zone/client_process.cpp	(working copy)
@@ -746,6 +746,9 @@
 		Message(0,"Your enemies have forgotten you!");
 	}
 	
+	// ResyncInventory() callback timer check
+	if(ri_CallBackTimer && ri_CallBackTimer->Enabled() && ri_CallBackTimer->Check(false)) { ResyncInvCallBack(); }
+
 	return ret;
 }
 
Index: zone/command.cpp
===================================================================
--- zone/command.cpp	(revision 2244)
+++ zone/command.cpp	(working copy)
@@ -459,7 +459,8 @@
 		command_add("xtargets", "Show your targets Extended Targets and optionally set how many xtargets they can have.", 250, command_xtargets) ||
 		command_add("printquestitems","Returns available quest items for multiquesting currently on the target npc.",200,command_printquestitems) ||
 		command_add("clearquestitems","Clears quest items for multiquesting currently on the target npc.",200,command_clearquestitems) ||
-		command_add("zopp", "Troubleshooting command - Sends a fake item packet to you. No server reference is created.", 250, command_zopp) 
+		command_add("zopp", "Troubleshooting command - Sends a fake item packet to you. No server reference is created.", 250, command_zopp) ||
+		command_add("resyncinv", "Client inventory resyncronation command. Use when you suspect an issue with your inventory.", 0, command_resyncinv)
 		)
 	{
 		command_deinit();
@@ -11701,7 +11702,24 @@
 
 		ItemInst* FakeItemInst = database.CreateItem(FakeItem, charges);
 		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);
+		c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u), quantity: %i, to slot %i.", packettype==ItemPacketTrade?"Trade":"Summon", FakeItem->Name, itemid, charges, slotid);
 		safe_delete(FakeItemInst);
 	}
 }
+
+void command_resyncinv(Client *c, const Seperator *sep) {
+	// This command can be set to GM status once all of the desync issues are found and corrected -U
+
+	if(!c) { return; }
+	else if(sep->argnum==1 && strcasecmp(sep->arg[1], "help") == 0) {
+		c->Message(0, "This command will attempt to resyncronize your inventory with the server.");
+		c->Message(0, "(Any empty bank slots will return 'lore deletion' messages for each slot)");
+		c->Message(0, "(A 'Worthless Coin' will be left in any empty shared bank slots until you");
+		c->Message(0, "zone or re-log. Clicking this coin will result in another resyncinv call)");
+	}
+	else if(sep->argnum > 0) { c->Message(15, "Usage: #resyncinv [help]"); }
+	else {
+		c->Message(15, "Player initiated inventory resyncronization:");
+		c->ResyncInventory(false);
+	}
+}
Index: zone/command.h
===================================================================
--- zone/command.h	(revision 2244)
+++ zone/command.h	(working copy)
@@ -323,6 +323,7 @@
 void command_printquestitems(Client *c, const Seperator *sep);
 void command_clearquestitems(Client *c, const Seperator *sep);
 void command_zopp(Client *c, const Seperator *sep);
+void command_resyncinv(Client *c, const Seperator *sep);
 
 #ifdef EMBPERL
 void command_embperl_plugin(Client *c, const Seperator *sep);
Index: zone/inventory.cpp
===================================================================
--- zone/inventory.cpp	(revision 2244)
+++ zone/inventory.cpp	(working copy)
@@ -965,6 +965,7 @@
 				banker ? banker->GetName() : "UNKNOWN NPC", distance);
 			database.SetMQDetectionFlag(AccountName(), GetName(), hacked_string, zone->GetShortName());
 			safe_delete_array(hacked_string);
+			// This Kick() could be deleted unless an automatic ban is in use. A resyncinv is triggered on the 'return false;' -U
 			Kick();	// Kicking player to avoid item loss do to client and server inventories not being sync'd
 			return false;
 		}
@@ -1020,12 +1021,16 @@
 			move_in->from_slot = dst_slot_check;
 			move_in->to_slot = src_slot_check;
 			move_in->number_in_stack = dst_inst->GetCharges();
-			if (!SwapItem(move_in)) // shouldn't fail because call wouldn't exist otherwise, but just in case...
-				this->Message(13, "Error: Internal SwapItem call returned a failure!");
+			if (!SwapItem(move_in)) {
+#if (EQDEBUG>= 5)
+				LogFile->write(EQEMuLog::Debug, "Client::SwapItem() %s's recursive swapitem call resulted in an unknown failure.", GetName());
+#endif
+			}
 		}
-		Message(13, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
-		LogFile->write(EQEMuLog::Debug, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
-		this->DeleteItemInInventory(dst_slot_id,0,true);
+		// This code is no longer needed :) -U
+		//Message(13, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
+		//LogFile->write(EQEMuLog::Debug, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
+		//this->DeleteItemInInventory(dst_slot_id,0,true);
 		return false;
 	}
 	//verify shared bank transactions in the database
@@ -1210,9 +1215,9 @@
 		else {
 			// Nothing in destination slot: split stack into two
 			if ((sint16)move_in->number_in_stack >= src_inst->GetCharges()) {
+				// Move entire stack
+				if(!m_inv.SwapItem(src_slot_id, dst_slot_id)) { return false; }
 				mlog(INVENTORY__SLOTS, "Move entire stack from %d to %d with stack size %d. Dest empty.", src_slot_id, dst_slot_id, move_in->number_in_stack);
-				// Move entire stack
-				m_inv.SwapItem(src_slot_id, dst_slot_id);
 			}
 			else {
 				// Split into two
@@ -1232,8 +1237,8 @@
 			}
 			SetMaterial(dst_slot_id,src_inst->GetItem()->ID);
 		}
+		if(!m_inv.SwapItem(src_slot_id, dst_slot_id)) { return false; }
 		mlog(INVENTORY__SLOTS, "Moving entire item from slot %d to slot %d", src_slot_id, dst_slot_id);
-		m_inv.SwapItem(src_slot_id, dst_slot_id);
 	}
 	
 	int matslot = SlotConvert2(dst_slot_id);
@@ -1258,6 +1263,282 @@
 	return true;
 }
 
+/*
+	This method is used to syncronize client and server inventories when a swapitem request fails.
+	I believe it works as well as it's going to, given the restrictions imposed upon us by the client -U
+
+	See this post for more information:
+	http://www.eqemulator.org/forums/showpost.php?p=213911&postcount=7
+*/
+void Client::ResyncInventory(bool server_call, bool timer_callback) {
+	
+	float delay_modifier = 1.00; // adjust (1/4-point increments) to eliminate timing errors (consider making a rule)
+
+	if(!timer_callback) { /* DO INITIAL CALL WORK */
+		if(!ri_Count) {
+			Message(15, "Attempting to resyncronize %s's inventory - Please stand-by...", GetName());
+			Message(15, "(Do not use your inventory until resyncronization is complete.)");
+
+#if (EQDEBUG>=5)
+			if(server_call) { LogFile->write(EQEMuLog::Debug, "Client::ResyncInventory() server failure of swapitem called for resync of %s's inventory", GetName()); }
+#endif
+		}
+		// Close all containers - if possible
+
+		ri_CallBackTimer->Disable();
+		ri_Count += 1;
+
+		if(ri_Count > RI_COUNT_LIMIT) {
+			ri_Count = 0;
+			ri_Step = 0;
+			ri_CursorCount = 0;
+			ri_CallBackDelay = 0;
+
+			Kick();
+			return;
+		}
+		else if(ri_Count > 1) {
+			Message(13, "Warning: Do not perform any actions until resyncronization completes!");
+			ri_CursorCount = RI_CURSOR_LIMIT;
+		}
+		else {
+			if(m_inv.CursorSize() < RI_CURSOR_LIMIT) { ri_CursorCount = m_inv.CursorSize() + 1; }
+			else { ri_CursorCount = RI_CURSOR_LIMIT; }
+		}
+
+		ri_Step = RI_STEP_COUNT;
+		ri_CallBackDelay = static_cast<int32>(250 * delay_modifier); // Step 1 callback delay (timing critical for proper operation)
+		
+		ri_CallBackTimer->Start(ri_CallBackDelay);
+
+		return;
+	}
+	
+	switch(ri_Step) { /* PARSE WORK TO STEPS FOR EACH CALLBACK */
+		case RI_STEP_COUNT: { // Delete Client CURSOR (Step 1)
+			ResyncInvClDelItem(SLOT_CURSOR);
+
+			return;
+		}
+		case 19: { // Sync WORN & PERSONAL (Step 2)
+			ResyncInvProcSlots(0, 21, RI_BIT_UN);
+			if(GetClientVersion() >= EQClientSoF) { ResyncInvProcSlots(9999, 9999, RI_BIT_UN); }
+			ResyncInvProcSlots(22, 29, RI_BIT_UN);
+
+			ri_CallBackDelay = static_cast<int32>(500 * delay_modifier); // Step 3 callback delay
+			return;
+		}
+		case 18: { // Sync PERSONAL BAGS (Step 3) [First 40 slots]
+			ResyncInvProcSlots(251, 291, (RI_BIT_AU | RI_BIT_UN | RI_BIT_CP));
+
+			ri_CallBackDelay = static_cast<int32>(500 * delay_modifier); // Step 4 callback delay
+			return;
+		}
+		case 17: { // Sync PERSONAL BAGS (Step 4) [Second 40 slots]
+			ResyncInvProcSlots(291, 330, (RI_BIT_AU | RI_BIT_UN | RI_BIT_CP));
+
+			ri_CallBackDelay = static_cast<int32>(500 * delay_modifier); // Step 5 callback delay
+			return;
+		}
+		case 16: { // Sync TRIBUTE (Step 5) /* BROKEN */
+			ResyncInvProcSlots(400, 404, RI_BIT_BROKEN /* (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP) */);
+
+			ri_CallBackDelay = static_cast<int32>(1 /* 1000 working */ * delay_modifier); // Step 6 callback delay
+			return;
+		}
+		case 15: { // Sync BANK (Step 6)
+			if(GetClientVersion() >= EQClientSoF) { ResyncInvProcSlots(2000, 2023, (RI_BIT_UN | RI_BIT_AD)); }
+			else { ResyncInvProcSlots(2000, 2015, (RI_BIT_UN | RI_BIT_AD)); }
+
+			ri_CallBackDelay = static_cast<int32>(1000 * delay_modifier); // Step 7 callback delay
+			return;
+		}
+		case 14: { // Sync BANK BAGS (Step 7) [SoF+ & Ti First 40 slots]
+			if(GetClientVersion() >= EQClientSoF) { ResyncInvProcSlots(2031, 2110, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+			else { ResyncInvProcSlots(2031, 2070, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+
+			ri_CallBackDelay = static_cast<int32>(500 * delay_modifier); // Step 8 callback delay
+			return;
+		}
+		case 13: { // Sync BANK BAGS (Step 8) [SoF+ & Ti Second 40 slots]
+			if(GetClientVersion() >= EQClientSoF) { ResyncInvProcSlots(2031, 2110, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+			else { ResyncInvProcSlots(2071, 2110, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+
+			ri_CallBackDelay = static_cast<int32>(500 * delay_modifier); // Step 9 callback delay
+			return;
+		}
+		case 12: { // Sync BANK BAGS (Step 9) [SoF+ & Ti Third 40 slots]
+			if(GetClientVersion() >= EQClientSoF) { ResyncInvProcSlots(2111, 2190, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+			else { ResyncInvProcSlots(2111, 2150, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+
+			ri_CallBackDelay = static_cast<int32>(500 * delay_modifier); // Step 10 callback delay
+			return;
+		}
+		case 11: { // Sync BANK BAGS (Step 10) [SoF+ & Ti Fourth 40 slots]
+			if(GetClientVersion() >= EQClientSoF) { ResyncInvProcSlots(2111, 2190, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+			else { ResyncInvProcSlots(2151, 2190, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+
+			ri_CallBackDelay = static_cast<int32>(500 * delay_modifier); // Step 11 callback delay
+			return;
+		}
+		case 10: { // Sync BANK BAGS (Step 11) [SoF+ Fifth 40 slots]
+			if(GetClientVersion() >= EQClientSoF) { ResyncInvProcSlots(2191, 2230, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+
+			ri_CallBackDelay = static_cast<int32>(500 * delay_modifier); // Step 12 callback delay
+			return;
+		}
+		case 9: { // Sync BANK BAGS (Step 12) [SoF+ Sixth 40 slots]
+			if(GetClientVersion() >= EQClientSoF) { ResyncInvProcSlots(2231, 2270, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP)); }
+
+			ri_CallBackDelay = static_cast<int32>(500 * delay_modifier); // Step 13 callback delay
+			return;
+		}
+		case 8: { // Sync SHARED BANK & SHARED BANK BAGS (Step 13)
+			ResyncInvProcSlots(2500, 2501, (RI_BIT_UN | RI_BIT_AD));
+			ResyncInvProcSlots(2531, 2550, (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP));
+			
+			ri_CallBackDelay = static_cast<int32>(1000 * delay_modifier); // Step 14 callback delay
+			return;
+		}
+		case 7: { // Sync TRADER (Step 14) /* BROKEN */
+			ResyncInvProcSlots(3000, 3007, RI_BIT_BROKEN /* (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP) */);
+			
+			ri_CallBackDelay = static_cast<int32>(1 /* 1000 working */ * delay_modifier); // Step 15 callback delay
+			return;
+		}
+		case 6: { // Sync TRADER BAGS (Step 15) [First 40 Slots] /* BROKEN */
+			ResyncInvProcSlots(3100, 3139, RI_BIT_BROKEN /* (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP) */);
+
+			ri_CallBackDelay = static_cast<int32>(1 /* 500 working */ * delay_modifier); // Step 16 callback delay
+			return;
+		}
+		case 5: { // Sync TRADER BAGS (Step 16) [Second 40 slots] /* BROKEN */
+			ResyncInvProcSlots(3140, 3179, RI_BIT_BROKEN /* (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP) */);
+
+			ri_CallBackDelay = static_cast<int32>(1 /* 500 working */ * delay_modifier); // Step 17 callback delay
+			return;
+		}
+		case 4: { // Sync WORLD CONTAINER (Step 17) /* BROKEN */
+			ResyncInvProcSlots(4000, 4009, RI_BIT_BROKEN /* (RI_BIT_AU | RI_BIT_UN | RI_BIT_AD | RI_BIT_CP) */);
+			
+			ri_CallBackDelay = static_cast<int32>(1 /* 1000 working */ * delay_modifier); // Step 18 callback delay
+			return;
+		}
+		case 3: { // Delete Client CURSOR (Step 18)
+			ResyncInvClDelItem(SLOT_CURSOR, true); // hack for Bank Slots
+
+			ri_CallBackDelay = static_cast<int32>(1500 * delay_modifier); // Step 19 callback delay
+			return;
+		}
+		case 2: { // Sync Client CURSOR (Step 19)
+			ResyncInvClDelItem(SLOT_CURSOR); // hack for Bank Slots
+
+			ri_CursorCount = 1;
+			for(std::list<ItemInst*>::const_iterator cursor_iter = m_inv.cursor_begin(); cursor_iter != m_inv.cursor_end() && ri_CursorCount <= RI_CURSOR_LIMIT;
+				cursor_iter++, ri_CursorCount++) { SendItemPacket(SLOT_CURSOR, *cursor_iter, ItemPacketSummonItem); }
+
+			if(ri_Count > 1) { ri_CallBackDelay = static_cast<int32>(4000 * delay_modifier); } // Step 20 callback delay (full) }
+			else { ri_CallBackDelay = static_cast<int32>(2000 * delay_modifier); } // Step 20 callback delay (normal)
+			return;
+		}
+		case 1: { // Sync Cursor Bags (Step 20)
+			ResyncInvProcSlots(331, 340, (RI_BIT_AU | RI_BIT_UN | RI_BIT_CP));
+			
+			ri_CallBackDelay = static_cast<int32>(100 * delay_modifier); // Finalization callback delay
+			return;
+		}
+		case 0: { // Finalization
+			if (ri_CursorCount > RI_CURSOR_LIMIT) {
+				Message(15, "Caution: The server's cursor count exceeds client capacity.");
+				Message(15, "Remove all cursor items and resycinv again to correct this.");
+			}
+
+			ri_Count = 0;
+			ri_Step = 0;
+			ri_CursorCount = 0;
+			ri_CallBackDelay = 0;
+
+			Message(14, "%s's inventory resyncronization complete.", GetName());
+			Message(0, "(Close any container/trade windows that were open before using inventory) ");
+			return;
+		}
+		default: { // (somehow, 'ResyncInvStep' was set above the number of coded steps...)
+#if (EQDEBUG>=5)
+			LogFile->write(EQEMuLog::Debug, "Client::ResyncInventory() resyncinv for %s's inventory tried to process non-existent step %i", GetName(), ri_Step);
+#endif
+
+			ri_Count = 0;
+			ri_Step = 0;
+			ri_CursorCount = 0;
+			ri_CallBackDelay = 0;
+
+			Kick();
+			return;
+		}
+	}
+}
+
+void Client::ResyncInvCallBack() {
+
+	int8 step_percent = ((static_cast<float>(RI_STEP_COUNT - ri_Step) / RI_STEP_COUNT) * 100);
+	if(step_percent) { Message(1, "Resycronization %i percent complete...", step_percent); }
+
+	ri_CallBackTimer->Disable();
+	ResyncInventory(false, true);
+	
+	if(ri_CursorCount && ri_Step == RI_STEP_COUNT) { ri_CursorCount -= 1; }
+	else if(ri_Step) { ri_Step -= 1; }
+
+	if(ri_CallBackDelay) { ri_CallBackTimer->Start(ri_CallBackDelay); }
+}
+
+void Client::ResyncInvProcSlots(sint16 slot_begin, sint16 slot_end, int8 sync_method) {
+
+	if(sync_method & RI_BIT_BROKEN) { return; }
+
+	for(sint16 slot_id = slot_begin; slot_id <= slot_end; slot_id++) {
+		const ItemInst* slot_inst = m_inv[slot_id];
+
+		if(sync_method & RI_BIT_CP) {
+			sint16 parent_slot = m_inv.CalcSlotId(slot_id);
+
+			if(parent_slot != SLOT_INVALID && m_inv[parent_slot] && m_inv[parent_slot]->GetItem()->ItemClass == 1) {
+				if(slot_inst) { SendItemPacket(slot_id, slot_inst, ItemPacketTrade); }
+				else { if(!(sync_method & RI_BIT_AU) && (sync_method & RI_BIT_UN)) { ResyncInvClDelItem(slot_id, (sync_method & RI_BIT_AD)); } }
+			}
+		}
+		else {
+			if(slot_inst) { SendItemPacket(slot_id, slot_inst, ItemPacketTrade); }
+			else { if(!(sync_method & RI_BIT_AU) && (sync_method & RI_BIT_UN)) { ResyncInvClDelItem(slot_id, (sync_method & RI_BIT_AD)); } }
+		}
+	}
+}
+
+void Client::ResyncInvClDelItem(sint16 slot_id, bool alt_delete) {
+
+	if(alt_delete) {
+		const Item_Struct* ri_TokenStruct = database.GetItem(1041); // 'Worthless Coin'
+		ItemInst* ri_TokenInst = database.CreateItem(ri_TokenStruct, 1);
+		
+		SendItemPacket(slot_id, ri_TokenInst, ItemPacketTrade);
+	}
+	else {
+		const Item_Struct* ri_TokenStruct = database.GetItem(22292); // 'Copper Coin'
+		ItemInst* ri_TokenInst = database.CreateItem(ri_TokenStruct, 1);
+
+		SendItemPacket(slot_id, ri_TokenInst, ItemPacketTrade);
+
+		EQApplicationPacket* outapp		= new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
+		DeleteItem_Struct* delete_slot	= (DeleteItem_Struct*)outapp->pBuffer;
+		delete_slot->from_slot			= slot_id;
+		delete_slot->to_slot			= 0xFFFFFFFF;
+		delete_slot->number_in_stack	= 0xFFFFFFFF;
+		
+		QueuePacket(outapp);
+		safe_delete(outapp);
+	}	
+}
+
 void Client::DyeArmor(DyeStruct* dye){
 	sint16 slot=0;
 	for(int i=0;i<7;i++){
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
 


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 11:41 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3