Thread Tools Display Modes
04-23-15, 11:01 AM   #1
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
GetItemInfo vs WoW's cache

I completely forgot that unless an item has been seen by your client, GetItemInfo(id) returns nil. I would like a table and a string to be populated even if the client hasn't seen the items. After WoW reminder, I thought about looping until the data exists, but I don't know if that is the best solution.
Code:
local retraining_items = {
	[GetItemInfo(118354)] = true,			-- Follower Retraining Certificate
	[GetItemInfo(122273)] = true,			-- Follower Trait Retraining Guide
	[GetItemInfo(122272)] = true,			-- Follower Ability Retraining Manual
	[GetItemInfo(118475)] = true,			-- Hearthstone Strategy Guide
	[GetItemInfo(118474)] = true,			-- Supreme Manual of Dance
	[GetItemInfo(122584)] = true,			-- Winning with Wildlings
	[GetItemInfo(122583)] = true,			-- Grease Monkey Guide
	[GetItemInfo(122582)] = true,			-- Guide to Arakkoa Relations
	[GetItemInfo(122580)] = true,			-- Ogre Buddy Handbook
	[GetItemInfo(122275)] = true,			-- Sun-touched Feather of Rukhmar
	}
local scroll_case = GetItemInfo(123858)		-- Follower Retraining Scroll Case
Is this a solution that will work?
Code:
local retraining_items = {}
local scroll_case
while( (#retraining_items < 11) and (not scroll_case) )
do
    retraining_items = {
	[GetItemInfo(118354)] = true,			-- Follower Retraining Certificate
	[GetItemInfo(122273)] = true,			-- Follower Trait Retraining Guide
	[GetItemInfo(122272)] = true,			-- Follower Ability Retraining Manual
	[GetItemInfo(118475)] = true,			-- Hearthstone Strategy Guide
	[GetItemInfo(118474)] = true,			-- Supreme Manual of Dance
	[GetItemInfo(122584)] = true,			-- Winning with Wildlings
	[GetItemInfo(122583)] = true,			-- Grease Monkey Guide
	[GetItemInfo(122582)] = true,			-- Guide to Arakkoa Relations
	[GetItemInfo(122580)] = true,			-- Ogre Buddy Handbook
	[GetItemInfo(122275)] = true,			-- Sun-touched Feather of Rukhmar
	}
    scroll_case = GetItemInfo(123858)		-- Follower Retraining Scroll Case
end
  Reply With Quote
04-23-15, 04:58 PM   #2
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
That is really hard to follow. At least it works for you, though. I did notice in your function you have a table.insert with an i index, but I don't see a loop for that. Am I missing something?

Also, when I posted my question, I must have been tired, and forgot: I am using Ace3 (not a big difference) and thought to put the cached items into self.db.global, as once the items are found, I don't need to look them up again.
  Reply With Quote
04-23-15, 07:50 PM   #3
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Have a look at my Broker_WoDCurrency addon. It's well-commented and a smaller project so it should hopefully not be too confusing.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
04-23-15, 09:35 PM   #4
Torhal
A Pyroguard Emberseer
 
Torhal's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 1,196
Originally Posted by Banknorris View Post
(it is undocumented but I tested it). Unless of course I am mistaken.
So what you're actually saying is that you might be insane. Got it.
__________________
Whenever someone says "pls" because it's shorter than "please", I say "no" because it's shorter than "yes".

Author of NPCScan and many other AddOns.
  Reply With Quote
04-24-15, 07:17 AM   #5
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
I like Seerah's file as a learning tool. After I get some sleep, I will code something up, which will look similar to Broker_WoDCurrency, test it, and post back with results.

Incidentally, while at work, I was thinking about my idea regarding adding the cached items to saved variables: my conclusion (untested) is that method is not viable, as checking "if player has the item then" won't work passing my English localized item name to the player's GetItemInfo(item) if, say, the player's client is Korean.

Sure, I can do a simple if/then check, but that's why I am using tables for the itemIDs, as looping through a table is significantly easier than a dozen individual look ups. And, of course, comparing two GetItemInfo returns will work, but not if the item is uncached, hence the point of the thread.

Yep, tired and rambling. zzz (posting later)
  Reply With Quote
04-24-15, 07:24 AM   #6
Torhal
A Pyroguard Emberseer
 
Torhal's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 1,196
Memoizing tables FTW.
__________________
Whenever someone says "pls" because it's shorter than "please", I say "no" because it's shorter than "yes".

Author of NPCScan and many other AddOns.
  Reply With Quote
04-24-15, 11:34 AM   #7
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
@Banknorris:

You're right, it is undocumented. And, if it actually does (still) return the itemID, this was added recently with 6.0 and was unannounced.

There are only two places that use the "GET_ITEM_INFO_RECEIVED" event in the UI. The Archaeology UI and the Garrison Mission UI. The latter is the only place where the code looks for a return from the event (the itemID). I'll have to check it out. This change will make a number of addons more efficient.

Oh - and what was stopping you from documenting it?
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
04-24-15, 11:56 AM   #8
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
Originally Posted by Seerah View Post
Oh - and what was stopping you from documenting it?
Actually I was hoping someone more experienced/qualified confirmed this and added the information on WoWpedia. I am justifiably not that confident with things I think I know. Anyway thanks for the incentive.
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill
  Reply With Quote
04-24-15, 04:04 PM   #9
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Should I wait until Seerah looks into this? I am no no rush.
  Reply With Quote
04-24-15, 11:51 PM   #10
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
This is dry-coded and not tested. It is written for Ace3, but easily converted frame/event code. I am assuming BankNorris is correct and that GIIR does return an itemID.
Code:
-- retraining items
local retraining_item_ids = {
	frc = 118354,			-- Follower Retraining Certificate
	ftrg = 122273,			-- Follower Trait Retraining Guide
	farm = 122272,			-- Follower Ability Retraining Manual
	hsg = 118475,			-- Hearthstone Strategy Guide
	smd = 118474,			-- Supreme Manual of Dance
	www = 122584,			-- Winning with Wildlings
	gmg = 122583,			-- Grease Monkey Guide
	gar = 122582,			-- Guide to Arakkoa Relations
	obh = 122580,			-- Ogre Buddy Handbook
	stfr = 122275,			-- Sun-touched Feather of Rukhmar
}
local scroll_case_id = 123858		-- Follower Retraining Scroll Case

function retrainer:OnEnable()
	if #self.db.global[cached_items] < #retraining_item_ids or not self.db.global[cached_case] then
		self:RegisterEvent("GET_ITEM_INFO_RECEIVED")
	end
end

function retrainer:GET_ITEM_INFO_RECEIVED()
	if (#self.db.global[cached_items] > 10) and (self.db.global[scroll_case]) then
		self:UnregisterEvent("GET_ITEM_INFO_RECEIVED")
		return
	end
	
	local item_id = ...
	local item
	for i = 1, #retraining_item_ids do
		if item_id == retraining_item_ids[i] then
			item = GetItemInfo(item_id)
			table.insert(self.db.global[cached_items], item)
		end
	end
	-- sort the items alphabetically per client locale
	table.sort(self.db.global[cached_items], function(a, b)
		return a.name < b.name
	end)
	
	if item_id == scroll_case_id then
		item = GetItemInfo(item_id)
		table.insert(self.db.global[cached_case], item)
	end
end

Last edited by myrroddin : 04-25-15 at 12:21 AM. Reason: Because Torhal is smarter than I
  Reply With Quote
04-25-15, 12:04 AM   #11
Torhal
A Pyroguard Emberseer
 
Torhal's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 1,196
Your table - every key is identical.
__________________
Whenever someone says "pls" because it's shorter than "please", I say "no" because it's shorter than "yes".

Author of NPCScan and many other AddOns.
  Reply With Quote
04-25-15, 12:18 AM   #12
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Originally Posted by Torhal View Post
Your table - every key is identical.
D'oh! I wasn't thinking about that heh heh. Other than that (major) oversight, how does it look? Could it work? I edited the code above.

Last edited by myrroddin : 04-25-15 at 12:22 AM.
  Reply With Quote
04-25-15, 04:41 AM   #13
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
if in retraining_item_ids you used the item ids as keys instead of values you wouldn't need to loop through retraining_item_ids each time the event triggers.

Code:
local retraining_item_ids = {
	[118354] = true,			-- Follower Retraining Certificate
	[122273] = true,			-- Follower Trait Retraining Guide
	[122272] = true,			-- Follower Ability Retraining Manual
	[118475] = true,			-- Hearthstone Strategy Guide
	[118474] = true,			-- Supreme Manual of Dance
	[122584] = true,			-- Winning with Wildlings
	[122583] = true,			-- Grease Monkey Guide
	[122582] = true,			-- Guide to Arakkoa Relations
	[122580] = true,			-- Ogre Buddy Handbook
	[122275] = true,			-- Sun-touched Feather of Rukhmar
}

function retrainer:GET_ITEM_INFO_RECEIVED() --shouldn't be GET_ITEM_INFO_RECEIVED(...)?
	if (#self.db.global[cached_items] > 10) and (self.db.global[scroll_case]) then
		self:UnregisterEvent("GET_ITEM_INFO_RECEIVED")
		return
	end
	
	local item_id = ...
	local item

	if retraining_item_ids[item_id] then
		item = GetItemInfo(item_id)
		table.insert(self.db.global[cached_items], item)
	end
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill
  Reply With Quote
04-25-15, 12:37 PM   #14
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
BankNorris, thank you for the suggestion. I do have a table length nil value error, and while I can guess which table (the global saved vars), I am unsure why. What follows is the error and my full code. Line 64 is the first line in OnEnable.

You will notice I have a debug function, and the GIIS exit check is less prone to endless loops.

Error:
Code:
1x FollowerRetrainer\Retrainer.lua:64: attempt to get length of field '?' (a nil value)
FollowerRetrainer\Retrainer.lua:64: in function <FollowerRetrainer\Retrainer.lua:63>
(tail call): ?
[C]: ?
[string "safecall Dispatcher[1]"]:9: in function <[string "safecall Dispatcher[1]"]:5>
(tail call): ?
Ace3\AceAddon-3.0\AceAddon-3.0-12.lua:558: in function `EnableAddon'
Ace3\AceAddon-3.0\AceAddon-3.0-12.lua:651: in function <Ace3\AceAddon-3.0\AceAddon-3.0.lua:636>
[C]: ?
[C]: in function `LoadAddOn'
FrameXML\UIParent.lua:336: in function `UIParentLoadAddOn'
FrameXML\UIParent.lua:359: in function `CombatLog_LoadUI'
FrameXML\UIParent.lua:906: in function <FrameXML\UIParent.lua:814>

Locals:
nil
Full code:
Code:
local retrainer = LibStub("AceAddon-3.0"):NewAddon("FollowerRetrainer", "AceConsole-3.0", "AceEvent-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("FollowerRetrainer", true)

-- extra libs
local LBU = LibStub("LibBagUtils-1.0")
local LDB = LibStub("LibDataBroker-1.1")

-- retraining items
local retraining_item_ids = {
	[118354] = true,			-- Follower Retraining Certificate
	[122273] = true,			-- Follower Trait Retraining Guide
	[122272] = true,			-- Follower Ability Retraining Manual
	[118475] = true,			-- Hearthstone Strategy Guide
	[118474] = true,			-- Supreme Manual of Dance
	[122584] = true,			-- Winning with Wildlings
	[122583] = true,			-- Grease Monkey Guide
	[122582] = true,			-- Guide to Arakkoa Relations
	[122580] = true,			-- Ogre Buddy Handbook
	[122275] = true,			-- Sun-touched Feather of Rukhmar
}
local scroll_case_id = 123858		-- Follower Retraining Scroll Case

-- db for altering profiles
local db

-- default saved variables
local defaults = {
	profile = {
		enabled = true,
		selfDebug = false,
		--@debug@
		selfDebug = true,
		--@end-debug@
	},
	char = {
		safeRetraining = true,
	}
}

function retrainer:Debug(str, ...)
	if not self.db.profile.debugMode then return end
	if not str or strlen(str) == 0 then return end
	if select("#", ...) > 0 then
		if strfind(str, "%%[dfqsx%d]") or strfind(str, "%%%.%d") then
			str = format(str, ...)
		else
			str = strjoin(" ", str, tostringall(...))
		end
	end
	DEFAULT_CHAT_FRAME:AddMessage(format("|cffff9933%s:|r %s", self.name, str))
end

function retrainer:OnInitialize()
	-- register saved variables with AceDB
	db = LibStub("AceDB-3.0"):New("FollowerRetrainerDB", defaults, true)
	db.RegisterCallback(self, "OnProfileChanged", "RefreshConfig")
	db.RegisterCallback(self, "OnProfileCopied", "RefreshConfig")
	db.RegisterCallback(self, "OnProfileReset", "RefreshConfig")
	self.db = db
	self:SetEnabledState(self.db.profile.enabled)
end

function retrainer:OnEnable()
	if #self.db.global[cached_items] < #retraining_item_ids or not self.db.global[cached_case] then
		self:RegisterEvent("GET_ITEM_INFO_RECEIVED")
	end
	
	-- global saved variables complete,
	-- sort the items alphabetically per client locale
	table.sort(self.db.global[cached_items], function(a, b)
		return a.name < b.name
	end)
	
	if self.db.profile.selfDebug then
		for i = 1, #self.db.global[cached_items] do
			self:Debug("Debugging the global variables: ", tostring(self.db.global[i]))
		end
		self:Debug("And the scroll case: ", tostring(self.db.global[scroll_case]))
	end
end

function retrainer:OnDisable()
end

function retrainer:RefreshConfig()
	db = self.db
end

function retrainer:GET_ITEM_INFO_RECEIVED(...)
	if (#self.db.global[cached_items] >= #retraining_item_ids) and (self.db.global[scroll_case]) then
		self:UnregisterEvent("GET_ITEM_INFO_RECEIVED")
		return
	end
	
	local item_id = ...
	local item = GetItemInfo(item_id)
	
	if retraining_item_ids[item_id] then
		table.insert(self.db.global[cached_items], item)
	elseif item_id == scroll_case_id then
		table.insert(self.db.global[cached_case], item)
	end
end
  Reply With Quote
04-25-15, 01:47 PM   #15
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
The # operator only works for arrays, not hash tables but to cache items you don't need to know the length. I would remove from retraining_item_ids all item ids whose date is or become available (that is possible here because retraining_item_ids has the only purpose to help caching items). When retraining_item_id becomes empty (and you know that by checking if next(retraining_item_ids)==nil), it means all items are cached.
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill
  Reply With Quote
04-25-15, 04:13 PM   #16
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
I can't remove things from retrainer_item_ids, because if the user ever resets the profiles, or otherwise deletes or clears their saved variables within the game, I need something from which to rebuild.

No more errors.

In any case, my debug prints are returning nil values. I may have to use Eventful, as I'm beginning to think GIIR does not work they way you think it does.
  Reply With Quote
04-25-15, 04:32 PM   #17
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Now, this is interesting: GIIR has three arguments: userdata, event, itemID. I think the syntax will be
Code:
GET_ITEM_INFO_RECEIVED(userdata, event, itemID)
userdata -- the player unit's GUID? It is in hex, so that would be my guess
event -- GET_ITEM_INFO_RECEIVED
itemID -- the item ID that has been found
  Reply With Quote
04-26-15, 05:08 AM   #18
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Originally Posted by myrroddin View Post
Code:
function retrainer:OnEnable()
	if #self.db.global[cached_items] < #retraining_item_ids or not self.db.global[cached_case] then
		self:RegisterEvent("GET_ITEM_INFO_RECEIVED")
	end
	
	-- global saved variables complete,
	-- sort the items alphabetically per client locale
	table.sort(self.db.global[cached_items], function(a, b)
		return a.name < b.name
	end)
	
	if self.db.profile.selfDebug then
		for i = 1, #self.db.global[cached_items] do
			self:Debug("Debugging the global variables: ", tostring(self.db.global[i]))
		end
		self:Debug("And the scroll case: ", tostring(self.db.global[scroll_case]))
	end
end
I don't know where line 64 is, but there's no reference to cached_items anywhere, so I don't know to what self.db.global[cached_items] is supposed to refer.
Originally Posted by myrroddin View Post
Now, this is interesting: GIIR has three arguments: userdata, event, itemID. I think the syntax will be
Code:
GET_ITEM_INFO_RECEIVED(userdata, event, itemID)
userdata -- the player unit's GUID? It is in hex, so that would be my guess
event -- GET_ITEM_INFO_RECEIVED
itemID -- the item ID that has been found
No, that's just the standard arguments that you receive in your event handler from the UI engine, eg frame and event. That being said, as far as I know AceEvent passes the event itself to your event handlers in addition to the event arguments, but you're disregarding the event argument.
__________________
Grab your sword and fight the Horde!
  Reply With Quote
04-26-15, 08:11 PM   #19
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
http://wowprogramming.com/docs/scripts/OnEvent
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » GetItemInfo vs WoW's cache

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