Browse Source

Fix #269 - Support for Player Inspection /inspection command of Equipment and Appearance Items

Emagi 1 year ago
parent
commit
d01cf3e2cf

+ 1 - 1
EQ2/source/WorldServer/Items/Items.cpp

@@ -2548,7 +2548,7 @@ PacketStruct* Item::PrepareItem(int16 version, bool merchant_item, bool loot_ite
 	PacketStruct* packet = 0;
 	if(loot_item && version > 546)
 		packet = configReader.getStruct("WS_LootItemGeneric", version);
-	else{		
+	else{
 		int8 tmpType = generic_info.item_type;
 		if (version <= 283 && generic_info.item_type > ITEM_TYPE_RECIPE)
 			tmpType = 0;

+ 17 - 8
EQ2/source/WorldServer/client.cpp

@@ -9226,14 +9226,23 @@ void Client::InspectPlayer(Player* player_to_inspect) {
 			for (size_t i = 0; i < biography.length(); i++)
 				packet->setArrayDataByName("biography_char", biography[i], i);
 
-			LogWrite(MISC__TODO, 0, "TODO", "Why is inspect player weapons commented out? in func: %s, line: %i", __FUNCTION__, __LINE__);
-			/*Item* pw = player_to_inspect->GetEquipmentList()->GetItem(0);
-			if (pw)
-				packet->setItemByName("primary", pw, player_to_inspect, 0);
-			Item* sw = player_to_inspect->GetEquipmentList()->GetItem(1);
-			if (sw)
-				packet->setItemByName("secondary", sw, player_to_inspect, 0);*/
-				//DumpPacket(packet->serialize());
+			for(int32 s=0;s<NUM_SLOTS;s++) {
+				int32 slot = s*2;
+				
+				char item_slot_name[64], item_slot_name_appearance[64];
+				_snprintf(item_slot_name,64,"slot_%u",slot);
+				int32 slot_appearance = (s*2)+1;
+				_snprintf(item_slot_name_appearance,64,"slot_%u",slot_appearance);
+				Item* pw = player_to_inspect->GetEquipmentList()->GetItem(s);
+				packet->setItemByName(item_slot_name, pw, this->GetPlayer(), 0, 13);
+				if(s <= EQ2_FEET_SLOT || s == EQ2_RANGE_SLOT || s == EQ2_CLOAK_SLOT) {
+					pw = player_to_inspect->GetAppearanceEquipmentList()->GetItem(s);
+					packet->setItemByName(item_slot_name_appearance, pw, this->GetPlayer(), 0, 13);	
+				}
+				else {
+					packet->setItemByName(item_slot_name_appearance, nullptr, this->GetPlayer(), 0, 13);	
+				}
+			}
 			QueuePacket(packet->serialize());
 			safe_delete(packet);
 		}

+ 18 - 1
EQ2/source/common/PacketStruct.cpp

@@ -2553,6 +2553,17 @@ void PacketStruct::setItem(DataStruct* ds, Item* item, Player* player, int32 ind
 	if (!ds)
 		return;
 	uchar* ptr = (uchar*)GetStructPointer(ds);
+	
+	if(!item) {
+		if(offset > 12) {
+			// for player inspection this will offset the parts of the packet that have no items
+			uchar bogusItemBuffer[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00 /*0x68 was item flags*/,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+			int sizeOfArray = sizeof(bogusItemBuffer) / sizeof(bogusItemBuffer[0]);
+			ds->SetItemSize(sizeOfArray);
+			memcpy(ptr, bogusItemBuffer, sizeOfArray);
+		}
+		return;
+	}
 	PacketStruct* packet = item->PrepareItem(client_version, false, loot_item);
 	if (packet) {
 		int16 item_version = GetItemPacketType(packet->GetVersion());
@@ -2560,6 +2571,11 @@ void PacketStruct::setItem(DataStruct* ds, Item* item, Player* player, int32 ind
 
 		string* generic_string_data = packet->serializeString();
 		int32 size = generic_string_data->length();
+		int32 actual_length = size;
+
+		if(offset > 12) {
+			size += 6; // end padding for the specialized item (used for player inspection)
+		}
 		//DumpPacket((uchar*)generic_string_data->c_str(), size);
 		if (size <= 13)
 		{
@@ -2570,8 +2586,9 @@ void PacketStruct::setItem(DataStruct* ds, Item* item, Player* player, int32 ind
 		if (client_version > 546 && item->IsBag() == false && item->IsBauble() == false && item->IsFood() == false && (offset == 0 || offset == -1 || offset == 2))
 			size = (size * 2) - 5;
 		uchar* out_data = new uchar[size + 1];
+		memset(out_data, 0, size+1);
 		uchar* out_ptr = out_data;
-		memcpy(out_ptr, (uchar*)generic_string_data->c_str() + (9 + offset), generic_string_data->length() - (9 + offset));
+		memcpy(out_ptr, (uchar*)generic_string_data->c_str() + (9 + offset), actual_length - (9 + offset));
 		//DumpPacket((uchar*)generic_string_data->c_str() + (9 + offset), size);
 		//without these it will prompt for your character name
 		if (offset == 0 || offset == -1 || offset == 2) {

+ 51 - 2
server/WorldStructs.xml

@@ -15405,8 +15405,57 @@ to zero and treated like placeholders." />
 <Data ElementName="biography_array" Type="Array" ArraySizeVariable="num_chars">
 	<Data ElementName="biography_char" Type="char" />
 </Data>
-<Data ElementName="unknown14" Type="int8" Size="1" />
-<Data ElementName="unknown_name" Type="EQ2_8Bit_String" />
+<Data ElementName="unknown14" Type="int8" Size="6" />
+<Data ElementName="slot_0" Type="EQ2_Item" />
+<Data ElementName="slot_1" Type="EQ2_Item" />
+<Data ElementName="slot_2" Type="EQ2_Item" />
+<Data ElementName="slot_3" Type="EQ2_Item" />
+<Data ElementName="slot_4" Type="EQ2_Item" />
+<Data ElementName="slot_5" Type="EQ2_Item" />
+<Data ElementName="slot_6" Type="EQ2_Item" />
+<Data ElementName="slot_7" Type="EQ2_Item" />
+<Data ElementName="slot_8" Type="EQ2_Item" />
+<Data ElementName="slot_9" Type="EQ2_Item" />
+<Data ElementName="slot_10" Type="EQ2_Item" />
+<Data ElementName="slot_11" Type="EQ2_Item" />
+<Data ElementName="slot_12" Type="EQ2_Item" />
+<Data ElementName="slot_13" Type="EQ2_Item" />
+<Data ElementName="slot_14" Type="EQ2_Item" />
+<Data ElementName="slot_15" Type="EQ2_Item" />
+<Data ElementName="slot_16" Type="EQ2_Item" />
+<Data ElementName="slot_17" Type="EQ2_Item" />
+<Data ElementName="slot_18" Type="EQ2_Item" />
+<Data ElementName="slot_19" Type="EQ2_Item" />
+<Data ElementName="slot_20" Type="EQ2_Item" />
+<Data ElementName="slot_21" Type="EQ2_Item" />
+<Data ElementName="slot_22" Type="EQ2_Item" />
+<Data ElementName="slot_23" Type="EQ2_Item" />
+<Data ElementName="slot_24" Type="EQ2_Item" />
+<Data ElementName="slot_25" Type="EQ2_Item" />
+<Data ElementName="slot_26" Type="EQ2_Item" />
+<Data ElementName="slot_27" Type="EQ2_Item" />
+<Data ElementName="slot_28" Type="EQ2_Item" />
+<Data ElementName="slot_29" Type="EQ2_Item" />
+<Data ElementName="slot_30" Type="EQ2_Item" />
+<Data ElementName="slot_31" Type="EQ2_Item" />
+<Data ElementName="slot_32" Type="EQ2_Item" />
+<Data ElementName="slot_33" Type="EQ2_Item" />
+<Data ElementName="slot_34" Type="EQ2_Item" />
+<Data ElementName="slot_35" Type="EQ2_Item" />
+<Data ElementName="slot_36" Type="EQ2_Item" />
+<Data ElementName="slot_37" Type="EQ2_Item" />
+<Data ElementName="slot_38" Type="EQ2_Item" />
+<Data ElementName="slot_39" Type="EQ2_Item" />
+<Data ElementName="slot_40" Type="EQ2_Item" />
+<Data ElementName="slot_41" Type="EQ2_Item" />
+<Data ElementName="slot_42" Type="EQ2_Item" />
+<Data ElementName="slot_43" Type="EQ2_Item" />
+<Data ElementName="slot_44" Type="EQ2_Item" />
+<Data ElementName="slot_45" Type="EQ2_Item" />
+<Data ElementName="slot_46" Type="EQ2_Item" />
+<Data ElementName="slot_47" Type="EQ2_Item" />
+<Data ElementName="slot_48" Type="EQ2_Item" />
+<Data ElementName="slot_49" Type="EQ2_Item" /> <!-- Item.h potential max slot number, NUM_SLOTS(24) * 2 + 1 = 49 -->
 <!-- <Data ElementName="equipment_start" Type="int8" Size="5810" />
       <Data ElementName="Achievement_size" Type="int32" Size="1" /> -->
 </Struct>