PDA

View Full Version : Item stacksize


blackdragonsdg
01-22-2012, 01:44 AM
I am encountering weird issues with item stack sizes over 244. I have several items on my server set between 500-1000 and it will work flawlessly one minute then the next it is reverting the stack size back to 244 or even 232. Some times I can log out and back in and the previously reverted stack will display correctly again. This behavior seems to be fairly random. At first I thought I had corrupted something in my database or even the emulator but after a complete wipe of my database and a new emulator compile the stacksize issue continues to happen at random. I only recently started using stack sizes over 100 which is why I never saw this until now. I am using emulator rev2097 and peqdb rev2092 with the SoD client.

Has anyone else seen anything like this before? If so how do I fix it?

lerxst2112
01-22-2012, 02:01 AM
Stack size was fairly recently updated to allow for stacks of more than 255. It's possible something was missed, so if you had a stack over that size and whatever wasn't updated happens you'd end up with the old stack size mod 256. So, if you had 500 you'd end up with 244, and if you had 1000 you'd end up with 232.

If you limited yourself to stacks of 255 or less you wouldn't have any issues. If you're looking to track it down you'd need to find everywhere that the stacksize is assigned to a variable or passed into a function and make sure none of those places is using an unsigned char instead of a uint16.

blackdragonsdg
01-22-2012, 04:42 AM
Since the stacksize change was made in rev2004 I used the file list from that as a reference on where to look for any unsigned char being used with stacksize and I am sorry to say I did not see any.

Guess I will have to lower my stack sizes down below 255 till I can track down the culprit in the code or where ever it is or until someone beats me to it.

lerxst2112
01-22-2012, 05:45 AM
If I had to guess I'd say it might be one of these:


Inventory
bool DeleteItem(sint16 slot_id, uint8 quantity=0);
sint16 HasItem(uint32 item_id, uint8 quantity=0, uint8 where=0xFF);
sint16 HasItemByUse(uint8 use, uint8 quantity=0, uint8 where=0xFF);
sint16 _HasItem(map<sint16, ItemInst*>& bucket, uint32 item_id, uint8 quantity);
sint16 _HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity);
sint16 _HasItemByUse(map<sint16, ItemInst*>& bucket, uint8 use, uint8 quantity);
sint16 _HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity);


But I'd say the most likely candidate is this:


void Client::DeleteItemInInventory(sint16 slot_id, sint8 quantity, bool client_update, bool update_db)

blackdragonsdg
01-22-2012, 10:54 PM
So I took your idea on the potentital problem and ran with. After more than a few changes and function overload errors and fixes I am at a loss again.

The following did not fix the problem nor did the changes cause any other issues that I am aware of atm.

-------------------------------------------------------------------
zone/inventory.cpp
-------------------------------------------------------------------

void Client::DeleteItemInInventory(sint16 slot_id, sint8 quantity, bool client_update, bool update_db)

changed to

void Client::DeleteItemInInventory(sint16 slot_id, sint16 quantity, bool client_update, bool update_db)


uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {

changed to

uint32 Client::NukeItem(uint32 itemnum, uint16 where_to_check) {

-------------------------------------------------------------------
zone/client.h
-------------------------------------------------------------------

void DeleteItemInInventory(sint16 slot_id, sint8 quantity = 0, bool client_update = false, bool update_db = true);

changed to

void DeleteItemInInventory(sint16 slot_id, sint16 quantity = 0, bool client_update = false, bool update_db = true);


uint32 NukeItem(uint32 itemnum, uint8 where_to_check =

changed to

uint32 NukeItem(uint32 itemnum, uint16 where_to_check =

-------------------------------------------------------------------
common/item.cpp
-------------------------------------------------------------------

// Remove item from inventory (with memory delete)
bool Inventory::DeleteItem(sint16 slot_id, uint8 quantity)

changed to

// Remove item from inventory (with memory delete)
bool Inventory::DeleteItem(sint16 slot_id, uint16 quantity)


sint16 Inventory::HasItem(uint32 item_id, uint8 quantity, uint8 where)

changed to

sint16 Inventory::HasItem(uint32 item_id, uint16 quantity, uint16 where)


sint16 Inventory::HasItemByUse(uint8 use, uint8 quantity, uint8 where)

changed to

sint16 Inventory::HasItemByUse(uint8 use, uint16 quantity, uint16 where)


sint16 Inventory::_HasItem(map<sint16, ItemInst*>& bucket, uint32 item_id, uint8 quantity)

changed to

sint16 Inventory::_HasItem(map<sint16, ItemInst*>& bucket, uint32 item_id, uint16 quantity)


sint16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity)

changed to

sint16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint16 quantity)


sint16 Inventory::_HasItemByUse(map<sint16, ItemInst*>& bucket, uint8 use, uint8 quantity)

changed to

sint16 Inventory::_HasItemByUse(map<sint16, ItemInst*>& bucket, uint8 use, uint16 quantity)


sint16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity)

changed to

sint16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint16 quantity)









-------------------------------------------------------------------
common/item.h
-------------------------------------------------------------------

// Remove item from inventory
bool DeleteItem(sint16 slot_id, uint8 quantity=0);

changed to

// Remove item from inventory
bool DeleteItem(sint16 slot_id, uint16 quantity=0);


// Check whether item exists in inventory
// where argument specifies OR'd list of invWhere constants to look
sint16 HasItem(uint32 item_id, uint8 quantity=0, uint8 where=0xFF);

changed to

// Check whether item exists in inventory
// where argument specifies OR'd list of invWhere constants to look
sint16 HasItem(uint32 item_id, uint16 quantity=0, uint16 where=0xFFFF);


// Check whether item exists in inventory
// where argument specifies OR'd list of invWhere constants to look
sint16 HasItemByUse(uint8 use, uint16 quantity=0, uint8 where=0xFF);

changed to

// Check whether item exists in inventory
// where argument specifies OR'd list of invWhere constants to look
sint16 HasItemByUse(uint8 use, uint16 quantity=0, uint16 where=0xFFFF);

// Checks an inventory bucket for a particular item
sint16 _HasItem(map<sint16, ItemInst*>& bucket, uint32 item_id, uint8 quantity);
sint16 _HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity);
sint16 _HasItemByUse(map<sint16, ItemInst*>& bucket, uint8 use, uint8 quantity);
sint16 _HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity);

changed to

// Checks an inventory bucket for a particular item
sint16 _HasItem(map<sint16, ItemInst*>& bucket, uint32 item_id, uint16 quantity);
sint16 _HasItem(ItemInstQueue& iqueue, uint32 item_id, uint16 quantity);
sint16 _HasItemByUse(map<sint16, ItemInst*>& bucket, uint8 use, uint16 quantity);
sint16 _HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint16 quantity);

lerxst2112
01-23-2012, 12:10 AM
Some of the things you changed wouldn't have anything to do with this issue, specifically the "where to look" params. Presumably it won't hurt anything to have changed them.

Changing the quantities on those functions is a start, but you need to look at where they are called as well. As an example,
bool Client::DecreaseByID(int32 type, int8 amt)
has the potential to cause issues, although it is only called from Perl, and I didn't dig through any quest scripts to see if it is even used.

If you are able to narrow down specifically what you do to cause the problem it would probably help to narrow it down where in the code it might be occurring.

blackdragonsdg
01-23-2012, 01:37 AM
I am not exactly an expert with C++ so some of the changes I made were purely a guess. Obviously I may have guessed wrong on somethings but it didn't hurt to try.
Today I focused on this error instead of trying to actually play EQ which was the case at the time I made my initial post on this issue. It didn't take long to find a trigger which allowed me to cause the error at will. The trigger is very simple...put an arrow on a merchant...set its stacksize to 1000 then purchase 1000 of them. When the purchased item is placed into the characters inventory automatically the stacksize is reduced to 232.

lerxst2112
01-23-2012, 02:08 AM
Try changing this:


struct Merchant_Sell_Struct {
/*000*/ int32 npcid; // Merchant NPC's entity id
/*004*/ int32 playerid; // Player's entity id
/*008*/ int32 itemslot;
int32 unknown12;
/*016*/ int8 quantity; // Already sold
/*017*/ int8 Unknown016[3];
/*020*/ int32 price;
};


To this:


struct Merchant_Sell_Struct {
/*000*/ int32 npcid; // Merchant NPC's entity id
/*004*/ int32 playerid; // Player's entity id
/*008*/ int32 itemslot;
int32 unknown12;
/*016*/ int32 quantity; // Already sold
/*020*/ int32 price;
};


That might actually break something, but cross your fingers and prepare to change it back. :)

lerxst2112
01-23-2012, 02:14 AM
Looks like you'll also need to change the Merchant_Sell_Struct for each patch. Same basic idea though, remove the int8 x[3] placeholder and change the quantity to an int32.

blackdragonsdg
01-23-2012, 02:34 AM
Try changing this:


struct Merchant_Sell_Struct {
/*000*/ int32 npcid; // Merchant NPC's entity id
/*004*/ int32 playerid; // Player's entity id
/*008*/ int32 itemslot;
int32 unknown12;
/*016*/ int8 quantity; // Already sold
/*017*/ int8 Unknown016[3];
/*020*/ int32 price;
};


To this:


struct Merchant_Sell_Struct {
/*000*/ int32 npcid; // Merchant NPC's entity id
/*004*/ int32 playerid; // Player's entity id
/*008*/ int32 itemslot;
int32 unknown12;
/*016*/ int32 quantity; // Already sold
/*020*/ int32 price;
};


That might actually break something, but cross your fingers and prepare to change it back. :)

This did not fix the problem but at the same time it didn't appear to break anything either.
Maybe this will help narrow it down further and I just tried this.....I can summon stacks of 1000 random arrows and they can be placed into my inventory with no problem. I can manipulate those stacks without any reverting issues. I tried this with three different item id's of the same arrow name and type.

blackdragonsdg
01-23-2012, 03:04 AM
Looks like you'll also need to change the Merchant_Sell_Struct for each patch. Same basic idea though, remove the int8 x[3] placeholder and change the quantity to an int32.

Now doing this broke something somewhere. I purchased the 1000 arrows from the same merchant like I had been doing this whole time and then the problem occured. I could not access my inventory or use the merchant again. I tried clicking the blightfire stone just to zone and nothing happened so I used the zone command just to zone. After I zoned I was able to use my inventory again and well the arrows that I had purchased were not there. I checked my log files hoping for hint but found nothing useful.

lerxst2112
01-23-2012, 03:23 AM
Yeah, when you start messing around with the packet structs in the patches it gets a little problematic. If you break one of those then you're most likely stuck until you zone.

The most important thing with those is to never change the size, so if you change the int8 to an int32 you need to remove the array of unknown right after it so it stays the same size. It's also possible that whichever client you are using doesn't read those bits, or has a problem if they are changed.

Unless someone has a packet capture of buying 1000 of something on live when that particular client was being used to match up with it's all just guessing.

blackdragonsdg
01-23-2012, 05:36 AM
After my initial failure with the changing of the structs I decided to give it one more shot. So I dumped all the changes I had made up to this point and started over. This time I only used the struct changes and it worked so either something was interferring or I made a typo in one of those last changes. Gonna use this version of the compile for a while to see if the good fortune holds up.

Thanks for all the help lerxst2112.