Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Bug Reports

Development::Bug Reports Post detailed bug reports and what you would like to see next in the emu here.

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

Ok, here is an ALPHA patch for bugged corpses. It may still need a little work, but most issues should be ironed out:

[CSD Patch 4]
Code:
Index: inventory.cpp
===================================================================
--- inventory.cpp	(revision 2175)
+++ inventory.cpp	(working copy)
@@ -397,9 +405,11 @@
 		LogFile->write(EQEMuLog::Debug, "DeleteItemInInventory(%i, %i, %s)", slot_id, quantity, (client_update) ? "true":"false");
 	#endif
 
-	if(!m_inv[slot_id]) {
+	// Added 'IsSlotValid(slot_id)' check to both segments of client packet processing.
+	// Cursor queue slots were slipping through and crashing client
+	if(!m_inv[slot_id]) { 
 		// Make sure the client deletes anything in this slot to match the server.
-		if(client_update) {
+		if(client_update && IsValidSlot(slot_id)) {
 			EQApplicationPacket* outapp;
 			outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
 			DeleteItem_Struct* delitem	= (DeleteItem_Struct*)outapp->pBuffer;
@@ -427,7 +437,7 @@
 		    database.SaveInventory(character_id, inst, slot_id);
 	}
 
-	if(client_update) {
+	if(client_update && IsValidSlot(slot_id)) { 
 		EQApplicationPacket* outapp;
 		if(inst) {
 			if(!inst->IsStackable() && !isDeleted) 
@@ -437,13 +447,13 @@
 				// Stackable, arrows, etc ? Delete one from the stack
 				outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(MoveItem_Struct));
 
-			DeleteItem_Struct* delitem	= (DeleteItem_Struct*)outapp->pBuffer;
-			delitem->from_slot			= slot_id;
-			delitem->to_slot			= 0xFFFFFFFF;
-			delitem->number_in_stack	= 0xFFFFFFFF;
-			for(int loop=0;loop<quantity;loop++)
-				QueuePacket(outapp);
-			safe_delete(outapp);
+				DeleteItem_Struct* delitem	= (DeleteItem_Struct*)outapp->pBuffer;
+				delitem->from_slot			= slot_id;
+				delitem->to_slot			= 0xFFFFFFFF;
+				delitem->number_in_stack	= 0xFFFFFFFF;
+				for(int loop=0;loop<quantity;loop++)
+					QueuePacket(outapp);
+				safe_delete(outapp);
 		}
 		else {
 			outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
Index: PlayerCorpse.cpp
===================================================================
--- PlayerCorpse.cpp	(revision 2175)
+++ PlayerCorpse.cpp	(working copy)
@@ -352,13 +352,20 @@
 		pp->silver = 0;
 		pp->gold = 0;
 		pp->platinum = 0;
+
+		// need to tell client that cash has changed..could be RespawnFromHover=true..need to check
+		// issue looks like a money duplication error, but server value is actually correct
 	
 		// get their tints
 		memcpy(item_tint, &client->GetPP().item_tint, sizeof(item_tint));
 	
 		// solar: TODO soulbound items need not be added to corpse, but they need
 		// to go into the regular slots on the player, out of bags
-	
+		
+		// personal and cursor bag slots (251-340) are moved to corpse..should be deleting db entries too.
+		// reworked code to return and merge a list for the query builder instead of adding MoveItemToCorpse
+		// code to each loop.
+
 		// worn + inventory + cursor
         std::list<uint32> removed_list;
         bool cursor = false;
@@ -367,23 +374,27 @@
 			item = client->GetInv().GetItem(i);
 			if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))
 			{
-				MoveItemToCorpse(client, item, i);
-                removed_list.push_back(i);
+				removed_list.merge(MoveItemToCorpse(client, item, i));   
 			}
 		}
 
 		// cursor queue
+		// bumped starting assignment to 8001 because any in-memory 'slot 8000' item was moved above as 'slot 30'
+		// this was mainly for client profile state reflection..should match db player inventory entries now.
 		iter_queue it;
-		for(it=client->GetInv().cursor_begin(),i=8000; it!=client->GetInv().cursor_end(); it++,i++) {
+		for(it=client->GetInv().cursor_begin(),i=8001; it!=client->GetInv().cursor_end(); it++,i++) {
 			item = *it;
 			if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))
 			{
-				MoveItemToCorpse(client, item, i);
+				removed_list.merge(MoveItemToCorpse(client, item, i));
                 cursor = true;
 			}
 		}
 		
-        if(removed_list.size() != 0) {
+		// client->DeleteItemInInventory is memory only..update_db is passed as false..not sure why unless it's a
+		// sync issue... client->Save() alone doesn't appear to handle inventory deletion with &inv[slot_id] being
+		// null. player inventory db entries did not reflect client.inv states after 'client->Save()' alone.
+		if(removed_list.size() != 0) {
             std::stringstream ss("");
             ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
             ss << " AND (";
@@ -401,14 +412,40 @@
             ss << ")";
             database.RunQuery(ss.str().c_str(), ss.str().length());
         }
-        
+
         if(cursor) {
-            std::list<ItemInst*>::const_iterator start = client->GetInv().cursor_begin();
-            std::list<ItemInst*>::const_iterator finish = client->GetInv().cursor_end();
-            database.SaveCursor(client->CharacterID(), 
-                start, finish);
+			// cycle cursor to clear memory queue..will delete server queue, but not client queue with hover enabled...
+			// if can figure out client issue, change argument 3 (client_update) to false if handled elsewhere.
+			// might could solve by forcing zone entry event to reset client inventory or sending client clear and
+			// resending bulkinventory. don't want to send client delete cursor on revive..might cause item loss...
+
+			while(!client->GetInv().CursorEmpty()) {
+				if (RuleB(Character, RespawnFromHover)) {
+					client->Message(0, "Attempting to delete %s from cursor.", client->GetInv().GetItem(SLOT_CURSOR)->GetItem()->Name);
+					client->DeleteItemInInventory(SLOT_CURSOR, 0, true, false);
+				}
+				else {
+					client->DeleteItemInInventory(SLOT_CURSOR, 0, false, false); // no need to update client without hover
+				}
+			}
+
+			if (RuleB(Character, RespawnFromHover)) {
+				client->Message(13, "Warning: Your cursor may contain duplicate items not found on the server!");
+				client->Message(0, "Place these items into an empty inventory slot to resolve this problem.");
+			}
+
+			// this code didn't appear to accomplish anything db-wise. it looks like it just re-saved the cursor
+			// queue data. with this code in-place, the cursor queue was re-saved and prevented lost items..which
+			// were the items on the corpses causing the 'bugged' issue in the first place. this code can be
+			// deleted after testing and verification of code submission.
+
+            //std::list<ItemInst*>::const_iterator start = client->GetInv().cursor_begin();
+            //std::list<ItemInst*>::const_iterator finish = client->GetInv().cursor_end();
+            //database.SaveCursor(client->CharacterID(), 
+            //    start, finish);
         }
 
+		client->CalcBonuses(); // shouldn't matter to a corpse, but hey..at least Magelo will update correctly =)
 		client->Save();
 	} //end "not leaving naked corpses"
 	
@@ -417,28 +454,35 @@
 }
 
 // solar: helper function for client corpse constructor
-void Corpse::MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot)
+std::list<uint32> Corpse::MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot)
 {
 	int bagindex;
 	sint16 interior_slot;
 	ItemInst *interior_item;
+	std::list<uint32> returnlist;
 
 	AddItem(item->GetItem()->ID, item->GetCharges(), equipslot, item->GetAugmentItemID(0), item->GetAugmentItemID(1), item->GetAugmentItemID(2), item->GetAugmentItemID(3), item->GetAugmentItemID(4));
-	if(item->IsType(ItemClassContainer))
+	returnlist.push_back(equipslot);
+
+	// Qualified bag slot iterations. processing bag slots that don't exist is not a good idea.
+	if(item->IsType(ItemClassContainer) && ((equipslot >= 22 && equipslot <=30))) // Limit the bag check to inventory and cursor slots.
 	{
 		for(bagindex = 0; bagindex <= 10; bagindex++)
 		{
+			// For empty bags in cursor queue, slot was being resolved as SLOT_INVALID (-1)
 			interior_slot = Inventory::CalcSlotId(equipslot, bagindex);
 			interior_item = client->GetInv().GetItem(interior_slot);
 
 			if(interior_item)
 			{
 				AddItem(interior_item->GetItem()->ID, interior_item->GetCharges(), interior_slot, interior_item->GetAugmentItemID(0), interior_item->GetAugmentItemID(1), interior_item->GetAugmentItemID(2), interior_item->GetAugmentItemID(3), interior_item->GetAugmentItemID(4));
+				returnlist.push_back(Inventory::CalcSlotId(equipslot, bagindex));
 				client->DeleteItemInInventory(interior_slot, 0, true, false);
 			}
 		}
-	}
+	} // */
 	client->DeleteItemInInventory(equipslot, 0, true, false);
+	return returnlist;
 }
 
 // To be called from LoadFromDBData
@@ -981,19 +1025,43 @@
 		ItemList::iterator cur,end;
 		cur = itemlist.begin();
 		end = itemlist.end();
+
+		// Observed some odd behavior concerning the last corpse slot as coded (SoF client in this case.)
+		// Clicking index 29 (zero-based) with an item in index 28 results in retrieving index 28 item.
+		// Clicking index 29 with no item in index 28 results in the closing of the corpse loot window.
+
+		int corpselootlimit = 30; // 30 is the original value
+		/* need actual corpse limit values per client (or client range)..if always 30, then these con checks are unneeded
+		// enumeration shouldn't be needed unless someone finds a use for this info elsewhere
+		if (client->GetClientVersion()>=EQClientVoA)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientHoT)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientUnderfoot)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientSoD)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientSoF) // SoF has 32 visible slots..change untested
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientTitanium)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClient62)
+			corpselootlimit=30;
+		else
+			corpselootlimit=30; // */
+
 		for(; cur != end; cur++) {
 			ServerLootItem_Struct* item_data = *cur;
 			item_data->lootslot = 0xFFFF;
+			
+			// Dont display the item if it's in a bag
 
-			// Dont display the item if it's in a bag
-			if(!IsPlayerCorpse() || item_data->equipSlot <= 30 || tCanLoot>=3)
+			// added cursor queue slots to corpse item visibility list. Nothing else should be making it to corpse.
+			if(!IsPlayerCorpse() || item_data->equipSlot <= 30 || tCanLoot>=3 ||
+				(item_data->equipSlot >= 8000 && item_data->equipSlot <= 8999))
 			{
-				if (i >= 30)
+				if (i < corpselootlimit) // < 30 (0 - 29) 
 				{
-						Message(13, "Warning: Too many items to display. Loot some then re-loot the corpse to see the rest");
-				}
-				else
-				{
 					item = database.GetItem(item_data->item_id);
 					if (client && item)
 					{
@@ -1006,9 +1074,24 @@
 						item_data->lootslot = i;
 					}
 				}
+				else if (i == corpselootlimit) // = 30
+				{
+					client->Message(13, "Warning: This corpse contains more items than can be displayed!");
+					client->Message(0, "Remove items and re-loot corpse to access remaining inventory.");
+				}
 				i++;
 			}
 		}
+		if (i > corpselootlimit) // > 30 (remember 'i' is increased again after the last iteration, so no '=')
+			client->Message(0, "(%s contains %i additional %s.)", GetName(), (i-corpselootlimit), (i-corpselootlimit)==1?"item":"items");
+
+		if (IsPlayerCorpse() && i == 0 && itemlist.size() > 0) { // somehow, corpse contains items, but client doesn't see them...
+			client->Message(13, "Warning: This corpse contains items that you do not permission to access!");
+			client->Message(13, "Contact a GM for assistance to determine if item replacement is necessary.");
+			client->Message(0, "BUGGED CORPSE [DBID: %i, Name: %s, Item Count: %i]", GetDBID(), GetName(), itemlist.size());
+			// if needed/wanted - create log dump->iterate corpse list..need pointer to log file
+			// could add code to check for owning client and give list of bugged items on corpse
+		}
 	}
 	
 	// Disgrace: Client seems to require that we send the packet back...
Index: PlayerCorpse.h
===================================================================
--- PlayerCorpse.h	(revision 2175)
+++ PlayerCorpse.h	(working copy)
@@ -111,7 +111,7 @@
 	inline int GetRezzExp() { return rezzexp; }
 
 protected:
-	void MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot);
+	std::list<uint32> MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot);
 
 private:
 	bool		p_PlayerCorpse;

Remember, this patch is NOT commit ready.
__________________
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:22 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