WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Problems with Big Tables (https://www.wowinterface.com/forums/showthread.php?t=52608)

Endzeit 08-13-15 07:51 AM

Problems with Big Tables
 
Edit#2:
It works now.. but i got stutter when hover over items.. is there a way with a ~1800 table to improve performance?
-----
EDIT:
i found the problem.. this is working:
Code:

local setName =  {
[1] = {  name = "Mystic's Regalia (Recolor)", items = {14090, 26008, 14094}, },
-- [2......1778]
[1779] = {  name = "Imperial Plate", items = {31436, 30002, 12424, 12425, 12422, 12427, 12429}, },
}
function addline_gametip()
local itemName,itemLink = GameTooltip:GetItem()
        if itemLink ~= nil then         
                local itemString = string.match(itemLink, "item[%-?%d:]+");
                local _, itemId, enchantId, jewelId1, jewelId2, jewelId3, jewelId4, suffixId, uniqueId, linkLevel, reforgeId = strsplit(":", itemString);

 for i = 1, #setName do
j = 1
while j <= 8 do

if (setName[i]['items'][j] ~= nil) and (format("%u",itemId) == format("%u", setName[i]['items'][j])) then
                GameTooltip:AddLine("Transmog Set: " .. setName[i]['name'])
                GameTooltip:Show();
                end
j = j + 1
                end
 end
 end
 end

 

GameTooltip:HookScript("OnTooltipSetItem", addline_gametip);

-------

I'm working on my first wow addon and i'm a big newbie with lua and coding. I think im finished, but it dont work.

problems are the do while i think. here is my code:

Code:

local setName =  {
[1] = {  name = "Mystic's Regalia (Recolor)", items = {14090, 26008, 14094}, },
-- [2......1778]
[1779] = {  name = "Imperial Plate", items = {31436, 30002, 12424, 12425, 12422, 12427, 12429}, },
}

function addline_gametip()
local itemName,itemLink = GameTooltip:GetItem()
        if itemLink ~= nil then         
                local itemString = string.match(itemLink, "item[%-?%d:]+");
                local _, itemId, enchantId, jewelId1, jewelId2, jewelId3, jewelId4, suffixId, uniqueId, linkLevel, reforgeId = strsplit(":", itemString);

 for i = 1, #setName do
j = 1
while j <= 8 do
 if (itemId == setName[i]['items'][j]) then
                GameTooltip:AddLine("Transmog Set: " .. setName[i]['name'])
                GameTooltip:Show();
                end
j = j + 1
                end
 end
 end
 end


GameTooltip:HookScript("OnTooltipSetItem", addline_gametip);

hope someone can help me :)

Mazzop 08-13-15 04:26 PM

cannot help on technical side and i am not sure if i get, what you trying to do :)
but what if you do table other way around and index by itemID with aray of sets name that item is in
adding tooltip then would be trivial

elcius 08-13-15 05:08 PM

lua has no problem with very large tables, just make an itemid to setid lookup table.
Lua Code:
  1. local setName =  {
  2. [1] = {  name = "Mystic's Regalia (Recolor)", items = {14090, 26008, 14094}, },
  3. -- [2......1778]
  4. [1779] = {  name = "Imperial Plate", items = {31436, 30002, 12424, 12425, 12422, 12427, 12429}, },
  5. }
  6.  
  7. -- make lookup table, ideally this would be pre-made
  8. local itemSet = {};
  9. for i,set in pairs(setName) do
  10.     for j, id in pairs(set['items']) do
  11.         itemSet[id] = i;
  12.     end
  13. end
  14.  
  15. function addline_gametip()
  16.     local itemName,itemLink = GameTooltip:GetItem();
  17.     if not itemLink then return end
  18.    
  19.     local itemId = itemLink:match('item:(%d+)');
  20.     local setIndex = itemSet[tonumber(itemId)];
  21.    
  22.     if setIndex and setName[setIndex] then
  23.         GameTooltip:AddLine("Transmog Set: " .. setName[setIndex]['name']);
  24.     end
  25.  end
  26.  
  27.  
  28. GameTooltip:HookScript("OnTooltipSetItem", addline_gametip);

Endzeit 08-14-15 07:19 AM

wow this works great. thanks :)

Next Step i want to add Message, when one of this Items received Loot.

Lua Code:
  1. function AddLootMsg(self, event, message, ...)
  2.     local itemName,itemLink = GetItemInfo(itemID);
  3.     if not itemLink then return end
  4.     local itemId = itemLink:match('item:(%d+)');
  5.     local setIndex = itemSet[tonumber(itemId)];
  6.  
  7.         if setIndex and setName[setIndex] then
  8.         DEFAULT_CHAT_FRAME:AddMessage("Hello, World!");
  9.     end
  10. end
  11.  
  12. ChatFrame_AddMessageEventFilter("CHAT_MSG_LOOT", AddLootMsg);

this is not working..
whats the different between GetItemInfo(itemID); and GameTooltip:GetItem(); ?
Can i use the same lookup table or i need a new one?
Can i use the same locals agains?

suicidalkatt 08-14-15 07:45 AM

Quote:

Originally Posted by elcius (Post 310319)
lua has no problem with very large tables, just make an itemid to setid lookup table.

~ Snip

While your method would be ideal, it doesn't really do what the author intended.

I believe they want to have the tooltip show every set that contains a particular itemID not just the first one that returns true.

Lua Code:
  1. local setName =  {
  2. [1] = {  name = "Mystic's Regalia (Recolor)", items = {14090, 26008, 14094}, },
  3. -- [2......1778]
  4. [1779] = {  name = "Imperial Plate", items = {31436, 30002, 12424, 12425, 12422, 12427, 12429}, },
  5. }
  6.  
  7. -- make lookup table, this will create a list that looks something like this
  8. --[[
  9. local table = {
  10.     [14090] = {201,560,888} -- Item id = Table of setName[index] values
  11. }
  12. ]]
  13. local itemSet = {}
  14. do
  15.     for i,set in pairs(setName) do -- Looks through all the set
  16.         for j, id in pairs(set['items']) do -- looks though just the items table within
  17.             if not itemSet[id] then itemSet[id] = {} end -- creates a table within itemSet for each id (only once)
  18.             tinsert(itemSet[id], i) -- inserts each set index into the table
  19.         end
  20.     end
  21. end
  22.  
  23. function addline_gametip()
  24.     local itemName,itemLink = GameTooltip:GetItem();
  25.     if not itemLink then return end
  26.    
  27.     local itemId = tonumber(itemLink:match('item:(%d+)'));
  28.     if itemSet[itemId] then -- if a set is found
  29.         for i, setIndex in pairs(itemSet[itemId]) do -- for each index the id has
  30.             GameTooltip:AddLine("Transmog Set: " .. setName[setIndex]['name']); -- add a line to the game tooltip
  31.         end
  32.     end
  33.  end
  34.  
  35.  
  36. GameTooltip:HookScript("OnTooltipSetItem", addline_gametip);

Endzeit 08-14-15 07:55 PM

thanks suicidalkatt & elcius.

Quote:

While your method would be ideal, it doesn't really do what the author intended.

I believe they want to have the tooltip show every set that contains a particular itemID not just the first one that returns true.
1 set = 1 itemid. Both variants are correct for me. ItemId 123456 can not be in 2 Sets in my table.


Lua Code:
  1. function AddLootMsg(self, event, message, ...)
  2.      if not string.match(message,'Hbattlepet') then
  3.     local lootid = select(3, string.find(message, "item:(%d+):"))
  4.    
  5.     local itemName,itemLink = GetItemInfo(lootid);
  6.     if not itemLink then return end
  7.    
  8.    
  9.     local itemId = tonumber(itemLink:match('item:(%d+)'));
  10.    
  11.     if itemSet[itemId] then -- if a set is found
  12.         for i, setIndex in pairs(itemSet[itemId]) do -- for each index the id has
  13.         message = message:gsub("\124r.", "\124r (|cff9400D3Transmog Set: " .. setName[setIndex]['name'] .. "|cff00aa00).")
  14.         return false, message, ...
  15.  
  16.     end
  17. end
  18. end
  19. end
  20.  
  21. ChatFrame_AddMessageEventFilter("CHAT_MSG_LOOT", AddLootMsg);

thats my code for chat_msg_loot so far.. in my first tests it works.. have someone also an improvement for this code?

SDPhantom 08-15-15 12:45 AM

Since all the code is doing is matching items to set names, the lookup table doesn't need to be so complicated to use. Here's my example. There can be more optimizations depending on how you want the tooltip to look.

Lua Code:
  1. local TransmogSets={
  2.     {
  3.         name="Mystic's Regalia (Recolor)",
  4.         items={14090, 26008, 14094},
  5.     },
  6.     {
  7.         name="Imperial Plate",
  8.         items={31436, 30002, 12424, 12425, 12422, 12427, 12429},
  9.     },
  10. --  And so on ...
  11. };
  12.  
  13. --  Lookup Table
  14. local ItemSetNames={}; do
  15.     for _,set in ipairs(TransmogSets) do--  Scan through all sets
  16.         for _,itemid in ipairs(set.items) do--  Scan through items
  17. --          Add set name to list in lookup table
  18.             if not ItemSetNames[itemid] then ItemSetNames[itemid]={}; end
  19.             table.insert(ItemSetNames[itemid],set.name);
  20.         end
  21.     end
  22.  
  23. --  Sorts set names
  24.     for _,list in pairs(ItemSetNames) do table.sort(list); end
  25. end
  26.  
  27. --  Tooltip Hook
  28. GameTooltip:HookScript("OnTooltipSetItem",function(self)
  29.     local _,link=self:GetItem();
  30.     if not link then return; end--  Exit if we have no item
  31.  
  32.     local id=tonumber(link:match("|Hitem:(%d+)")) or 0;--   Force nil to zero if we have an invalid link (no items exist at index zero)
  33.     if ItemSetNames[id] then
  34.         for i,name in ipairs(ItemSetNames[id]) do
  35. --          Only show our label on the first line
  36.             self:AddDoubleLine(i<=1 and "Transmog Set:" or " ",name);
  37.         end
  38.     end
  39. end);
  40.  
  41. --  Chat Hook
  42. ChatFrame_AddMessageEventFilter("CHAT_MSG_LOOT",function(self,event,msg,...)
  43.     local id=tonumber(msg:match("|Hitem:(%d+)")) or 0;--    Force nil to zero if we have an invalid link (no items exist at index zero)
  44.     if ItemSetNames[id] then return false,msg.." (|cff9400d3Transmog Sets: "..table.concat(ItemSetNames[id],", ").."|r).",...; end
  45. end);

Edit: Replaced string.join() section with more efficient table.concat() call.

Endzeit 08-15-15 01:06 PM

Lua Code:
  1. --  Chat Hook
  2. ChatFrame_AddMessageEventFilter("CHAT_MSG_LOOT",function(self,event,msg,...)
  3.     local id=tonumber(msg:match("|Hitem:(%d+)")) or 0;--    Force nil to zero if we have an invalid link (no items exist at index zero)
  4.     if ItemSetNames[id] then return false,msg.." (|cff9400d3Transmog Sets: "..string.join(", ",unpack(ItemSetNames[id])).."|r).",...; end
  5. end);

works.. but it also show loot from other player.. this should not happen. i tried this:
Lua Code:
  1. --  Chat Hook
  2. ChatFrame_AddMessageEventFilter("CHAT_MSG_LOOT",function(self,event,msg,...)
  3.     local id=tonumber(msg:match("|Hitem:(%d+)")) or 0;--    Force nil to zero if we have an invalid link (no items exist at index zero)
  4.     if ItemSetNames[id] and LOOT_ITEM_PUSHED_SELF or LOOT_ITEM_SELF ~= nil then return false,msg.." (|cff9400d3Transmog Sets: "..string.join(", ",unpack(ItemSetNames[id])).."|r).",...; end
  5. end);
this works for myself.. but get lua errors if other player loot items.

Mazzop 08-15-15 02:50 PM

try

Lua Code:
  1. ChatFrame_AddMessageEventFilter("CHAT_MSG_LOOT",function(self,event,msg,who...)
  2.   if who==UnitName("player")
  3.     local id=tonumber(msg:match("|Hitem:(%d+)")) or 0;--    Force nil to zero if we have an invalid link (no items exist at index zero)
  4.     if ItemSetNames[id]  then return false,msg,who.." (|cff9400d3Transmog Sets: "..string.join(", ",unpack(ItemSetNames[id])).."|r).",...; end
  5.   end
  6. end);

Endzeit 08-15-15 03:13 PM

Quote:

Originally Posted by Mazzop (Post 310361)
try

Lua Code:
  1. ChatFrame_AddMessageEventFilter("CHAT_MSG_LOOT",function(self,event,msg,who...)
  2.   if who==UnitName("player")
  3.     local id=tonumber(msg:match("|Hitem:(%d+)")) or 0;--    Force nil to zero if we have an invalid link (no items exist at index zero)
  4.     if ItemSetNames[id]  then return false,msg,who.." (|cff9400d3Transmog Sets: "..string.join(", ",unpack(ItemSetNames[id])).."|r).",...; end
  5.   end
  6. end);

this is not working.. lua errors.
also trying change from 'function(self,event,msg,who...)' to 'function(self,event,msg,who,...)'
and
' if who==UnitName("player")' to ' if who==UnitName("player") then'
no lua errors now, but is not working anymore

print(who); returns nothing like print();

Mazzop 08-15-15 03:23 PM

obviously i cannot drycode :)
its 5th argument, from fast /etrace

Lua Code:
  1. ChatFrame_AddMessageEventFilter("CHAT_MSG_LOOT",function(self,event,msg,who,language,channelString,target,  ...)
  2.       if target==UnitName("player") then
  3.         local id=tonumber(msg:match("|Hitem:(%d+)")) or 0;--    Force nil to zero if we have an invalid link (no items exist at index zero)
  4.         if ItemSetNames[id] then return false,msg,who,language,channelString,target,." (|cff9400d3Transmog Sets: "..string.join(", ",unpack(ItemSetNames[id])).."|r).",...; end
  5.       end
  6.     end);

Endzeit 08-15-15 03:43 PM

this cannot be working like this
for example playername: "Killer"
target returns "Killer"
UnitName("player") returns "Killer nil"


Lua Code:
  1. ChatFrame_AddMessageEventFilter("CHAT_MSG_LOOT",function(self,event,msg,_,_,_,target,  ...)
  2.       local name, realm = UnitName("player")
  3.       if target==name then
  4.         local id=tonumber(msg:match("|Hitem:(%d+)")) or 0;--    Force nil to zero if we have an invalid link (no items exist at index zero)
  5.         if ItemSetNames[id] then return false,msg.." (|cff9400d3Transmog Sets: "..string.join(", ",unpack(ItemSetNames[id])).."|r).",...; end
  6.       end
  7.     end);

this works for UnitName("player"), cant check now if it works for other players

Mazzop 08-15-15 03:48 PM

instead of UnitName("player") use select(1, UnitName("player"))
or make a variable local playername=UnitName("player")

Seerah 08-15-15 07:27 PM

Quote:

Originally Posted by Mazzop (Post 310366)
instead of UnitName("player") use select(1, UnitName("player"))
or make a variable local playername=UnitName("player")

The second option here ^^ is WAY better than the first. 1) it eliminates a needless function call. 2) select(1, ...) will still return everything after that 1st return.

Torhal 08-15-15 08:45 PM

There's also the option of

Code:

(UnitName("player"))
That will only evaluate the first return value, but it's a bit non-obvious if you're looking at the code months later.

Phanx 08-16-15 01:55 AM

Quote:

Originally Posted by Mazzop (Post 310366)
select(1, UnitName("player"))

There is no reason to ever use select with 1 as the first argument. There's almost no reason to ever use select at all -- it's way slower than assigning variables, eg. local _, class = UnitClass("player") -- but there's really no reason to ever use it like this. >_<

Mazzop 08-16-15 02:38 AM

ok ok, select is big nono, i get it :)
dont wanna hijack topic, but not even here

instead of sexy and nice
Lua Code:
  1. for j = 1, numbonuses do
  2.   bonus[j] = select(14 + j, strsplit(":", itemstring))
  3. end

would be better hideous abomination with numerous if depends of numbonuses and 14+ _ ?

Lombra 08-16-15 04:25 AM

Quote:

Originally Posted by Mazzop (Post 310376)
ok ok, select is big nono, i get it :)
dont wanna hijack topic, but not even here

instead of sexy and nice
Lua Code:
  1. for j = 1, numbonuses do
  2.   bonus[j] = select(14 + j, strsplit(":", itemstring))
  3. end

would be better hideous abomination with numerous if depends of numbonuses and 14+ _ ?

A few calls here and there is not gonna make a difference. It's fine, and I'd say this is a perfectly reasonable situation in which to use it. That logic might be improved slightly in other ways, though!

Rilgamon 08-16-15 06:04 AM

Quote:

Originally Posted by Lombra (Post 310379)
A few calls here and there is not gonna make a difference.

Turn your logic around a little. The request was to improve the performance. And removing select will always be an improvement.

Lombra 08-16-15 10:36 AM

Quote:

Originally Posted by Rilgamon (Post 310381)
Turn your logic around a little. The request was to improve the performance. And removing select will always be an improvement.

Sure, but I didn't read the word "performance" anywhere, only "better". If the performance gain is negligible I would definitely go for readability.

Edit: Without wanting to make a point of it, just did some quick benchmarks so people can get an idea of the difference.
This takes 43 ms to run:
Code:

for i = 1, 1e6 do
        local a, b, c = 1, 2, 3, 4, 5, 6, 7, 8, 9
end

This takes 94 ms to run, with the first select argument not affecting the result. No local reference.
Code:

for i = 1, 1e6 do
        local a, b, c = select(1, 1, 2, 3, 4, 5, 6, 7, 8, 9)
end

That's one million iterations, with each value adding a few ms in both tests.


All times are GMT -6. The time now is 04:37 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI