Thread Tools Display Modes
12/26/14, 11:26 PM   #1
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
GetItemType() ?

Maybe not a bug, just an unwanted (by me) default action...

I'm trying to track down an error causing a crash. This is not the cause, but its something I noticed when trying to tack down the problem. In my code I have been checking to see if an item exists in a bag/slot by checking the itemType before attempting to do anything with the item. If it came back ITEMTYPE_NONE I assumed the item was moved, destroyed, sold, or I assumed it was just an invalid bag/slot passed in.

But I just found out that
  1. If the slotIndex is nil, like: GetItemType(1, nil) it seems to use slot 0 for that bag.
  2. If the bag is nil: GetItemType(nil, 33) it seems to default to bag 0
  3. If the bag is an erroneous number: GetItemType(12343224, nil) it is defaulting to bag 1.

Is there any other way to verify if the values for bag/slot are valid & correspond to an actual item that still exists in that bag/slot? (besides tediously checking the bag# & slot# against the available bags & slots)

Last edited by circonian : 12/26/14 at 11:41 PM.
  Reply With Quote
12/27/14, 06:52 AM   #2
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 832
I think that the easiest solution is checking if arguments are valid before you use them.

Lua Code:
  1. --for our purposes are valid bags:
  2. -- BAG_WORN (0)
  3. -- BAG_BACKPACK (1)
  4. -- BAG_BANK (2)
  5. -- BAG_GUILDBANK(3)
  6. --Other bags are invalid:
  7. -- BAG_BUYBACK (4),
  8. -- BAG_TRANSFER (5)
  9. -- BAG_DELETE(255)
  10.  
  11. local function IsSlotOccupied(bagId, slotIndex)
  12.     if (type(bagId) == "number" and bagId >= 0 and bagId <= 3) then
  13.         if (type(slotIndex) == "number" and slotIndex >= 0 and slotIndex <= GetBagSize(bagId) - 1) then
  14.             local _, stackCount = GetItemInfo(bagId, slotIndex)
  15.             return stackCount > 0
  16.         end
  17.     end
  18. end
  19. --function returns:
  20. --true: bag slot is occupied
  21. --false: bag slot is empty
  22. --nil: invalid bagId or slotIndex arguments


This is how it does inventory manager:

Lua Code:
  1. function ZO_InventoryManager:IsSlotOccupied(bagId, slotIndex)
  2.     local inventoryType = self.bagToInventoryType[bagId]
  3.     local slot = self.inventories[inventoryType].slots[slotIndex]
  4.  
  5.     return ((slot ~= nil) and (slot.stackCount > 0))
  6. end

Global reference to that function is PLAYER_INVENTORY:IsSlotOccupied(bagId, slotIndex)

Last edited by Garkin : 12/28/14 at 06:27 AM. Reason: Typo, variable i should be slotIndex.
  Reply With Quote
12/27/14, 07:28 PM   #3
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Originally Posted by Garkin View Post
I think that the easiest solution is checking if arguments are valid before you use them.

Lua Code:
  1. --for our purposes are valid bags:
  2. -- BAG_WORN (0)
  3. -- BAG_BACKPACK (1)
  4. -- BAG_BANK (2)
  5. -- BAG_GUILDBANK(3)
  6. --Other bags are invalid:
  7. -- BAG_BUYBACK (4),
  8. -- BAG_TRANSFER (5)
  9. -- BAG_DELETE(255)
  10.  
  11. local function IsSlotOccupied(bagId, slotIndex)
  12.     if (type(bagId) == "number" and bagId >= 0 and bagId <= 3) then
  13.         if (type(slotIndex) == "number" and slotIndex >= 0 and slotIndex <= GetBagSize(bagId) - 1) then
  14.             local _, stackCount = GetItemInfo(bagId, i)
  15.             return stackCount > 0
  16.         end
  17.     end
  18. end
  19. --function returns:
  20. --true: bag slot is occupied
  21. --false: bag slot is empty
  22. --nil: invalid bagId or slotIndex arguments


This is how it does inventory manager:

Lua Code:
  1. function ZO_InventoryManager:IsSlotOccupied(bagId, slotIndex)
  2.     local inventoryType = self.bagToInventoryType[bagId]
  3.     local slot = self.inventories[inventoryType].slots[slotIndex]
  4.  
  5.     return ((slot ~= nil) and (slot.stackCount > 0))
  6. end

Global reference to that function is PLAYER_INVENTORY:IsSlotOccupied(bagId, slotIndex)
Ok, I didn't know if there was some function built in to do it for me or not.
Thanks for the help Garkin.
  Reply With Quote
12/28/14, 10:08 PM   #4
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
One more question about this, mainly its out of curiousity as to why this is happening.

I took your suggestion & started using:
Lua Code:
  1. local function IsBagSlotOccupied(_iBagId, _iSlotIndex)
  2.     if (type(_iBagId) == "number" and _iBagId >= 0 and _iBagId <= 3) then
  3.         if (type(_iSlotIndex) == "number" and _iSlotIndex >= 0 and _iSlotIndex <= GetBagSize(_iBagId) - 1) then
  4.             local _, stackCount = GetItemInfo(_iBagId, _iSlotIndex)
  5.             return stackCount > 0
  6.         end
  7.     end
  8. end
To check and see if there is a valid item in the bag/slot.

But after I call that to check I'm trying to grab the slot data like this, but I'm getting an error sometimes:
Lua Code:
  1. local function IsSlotProtected(_iBagId, _iSlotId)
  2.    if not IsBagSlotOccupied(_iBagId, _iSlotId) then return false end
  3.  
  4.       local slotData = SHARED_INVENTORY:GenerateSingleSlotData(_iBagId, _iSlotId)
  5.  
  6.       -- But I'm getting an error (sometimes) on this: attempting to index a nil value
  7.       if slotData.FilterIt_CurrentFilter then
  8.           return true
  9.       end
  10.    return false
  11. end

So if the IsBagSlotOccupied(..) returns true, then there is an item in that bag slot.
and this
Lua Code:
  1. SHARED_INVENTORY:GenerateSingleSlotData(_iBagId, _iSlotId)
is not throwing any errors now, but then why does slotData come back nil (sometimes) if the slot is occupied?
I "think" its only occuring when I move items...but still if the slot is occupied I was assuming the bag/slot did not belong to an empty slot the item was moved out of, so there should still be data there?

The only thing I can think of now is to add another check to make sure the slotData is valid also.
Lua Code:
  1. local function IsBagSlotOccupied(_iBagId, _iSlotIndex)
  2.     if (type(_iBagId) == "number" and _iBagId >= 0 and _iBagId <= 3) then
  3.         if (type(_iSlotIndex) == "number" and _iSlotIndex >= 0 and _iSlotIndex <= GetBagSize(_iBagId) - 1) then
  4.             local _, stackCount = GetItemInfo(_iBagId, _iSlotIndex)
  5.             return stackCount > 0
  6.         end
  7.     end
  8. end
  9.  
  10. local function IsSlotOccupied(_tSlot)
  11.     return ((_tSlot ~= nil) and (_tSlot.stackCount > 0))
  12. end
  13.  
  14. local function IsSlotProtected(_iBagId, _iSlotId)
  15.    if not IsBagSlotOccupied(_iBagId, _iSlotId) then return false end
  16.       local slotData = SHARED_INVENTORY:GenerateSingleSlotData(_iBagId, _iSlotId)
  17.       if IsSlotOccupied(slotData) and slotData.FilterIt_CurrentFilter then
  18.          return true
  19.       end
  20.    return false
  21. end

Any ideas why this happens?
  Reply With Quote
12/29/14, 10:19 AM   #5
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Why not check only slotData. The whole IsBagSlotOccupied check seems redundant (and also overly tolerant to invalid input if you ask me )
  Reply With Quote
12/29/14, 06:56 PM   #6
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Originally Posted by merlight View Post
Why not check only slotData. The whole IsBagSlotOccupied check seems redundant (and also overly tolerant to invalid input if you ask me )
This is called in a function that is open to other addons for a library & I don't trust them to pass in a valid bag/slot....and at times GenerateSingleSlotData(..) was generating errors because the bagid & slotId were not valid.

I don't remember now, I think the problem was that they were nil. So I could have "just" checked to ensure they are not nil, but I wasn't sure if any other invalid values would also throw an error so I thought the best method would be to just check to make sure the bag/slot are ones that I know are valid, which worked.

But the slotData could still come out nil so had to check it too.

Redundant, I agree!! I dunno maybe your right it, is overly tolerant. Its their own fault if they pass in bad values to start with.
  Reply With Quote
12/29/14, 11:45 PM   #7
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 832
As merlight said, if you are going to use function SHARED_INVENTORY:GenerateSingleSlotData(bagId, slotIndex), much easier (and faster) is just checking data you get from this function.

Lua Code:
  1. local function IsSlotProtected(_iBagId, _iSlotId)
  2.     local slotData = SHARED_INVENTORY:GenerateSingleSlotData(_iBagId, _iSlotId)
  3.     if slotData and slotData.FilterIt_CurrentFilter then
  4.         return true
  5.     end
  6.     return false
  7. end

At first I wanted to add condition "slotData.stackCount > 0" to the function above, but it is not necessary. SHARED_INVENTORY checks it before storing slot data into the bag cache, so stackCount must be always more then zero.

Q: When slotData could be nil even if slot is not empty?
A: If you are using SHARED_INVENTORY:GenerateSingleSlotData(bagId, slotIndex) directly from the EVENT_INVENTORY_SINGLE_SLOT_UPDATE handler, it is possible that your function is called before bag cache is updated. If you want to be sure that cache is updated, use SHARED_INVENTORY's callbacks instead.

Example:
Lua Code:
  1. local function OnFullInventoryUpdated(bagId)
  2.     --some code here
  3. end
  4.  
  5. local function OnInventorySlotUpdated(bagId, slotIndex)
  6.     --some code here
  7. end
  8.  
  9. SHARED_INVENTORY:RegisterCallback("FullInventoryUpdate", OnFullInventoryUpdated)
  10. SHARED_INVENTORY:RegisterCallback("SingleSlotInventoryUpdate", OnInventorySlotUpdated)
  Reply With Quote
12/30/14, 12:42 AM   #8
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Originally Posted by Garkin View Post
Q: When slotData could be nil even if slot is not empty?
A: If you are using SHARED_INVENTORY:GenerateSingleSlotData(bagId, slotIndex) directly from the EVENT_INVENTORY_SINGLE_SLOT_UPDATE handler, it is possible that your function is called before bag cache is updated. If you want to be sure that cache is updated, use SHARED_INVENTORY's callbacks instead.

Example:
Lua Code:
  1. local function OnFullInventoryUpdated(bagId)
  2.     --some code here
  3. end
  4.  
  5. local function OnInventorySlotUpdated(bagId, slotIndex)
  6.     --some code here
  7. end
  8.  
  9. SHARED_INVENTORY:RegisterCallback("FullInventoryUpdate", OnFullInventoryUpdated)
  10. SHARED_INVENTORY:RegisterCallback("SingleSlotInventoryUpdate", OnInventorySlotUpdated)
I didn't think of that. Yeah I guess it was just two different problems and I didn't realize it.

At first I had was worried if another addon called it with invalid bag/slot and then, yes, in my addon it was getting called from EVENT_INVENTORY_SINGLE_SLOT_UPDATE which is when I ran into the second problem with GenerateSingleSlotData(..) coming back nil.

I didn't realize I could register for a "SingleSlotInventoryUpdate" for the SHARED_INVENTORY.

Thanks for the info.
  Reply With Quote

ESOUI » Developer Discussions » General Authoring Discussion » GetItemType() Bug?

Thread Tools
Display Modes

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

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