ESOUI

ESOUI (https://www.esoui.com/forums/index.php)
-   Lua/XML Help (https://www.esoui.com/forums/forumdisplay.php?f=175)
-   -   Help with Complex Array. (https://www.esoui.com/forums/showthread.php?t=1674)

Sharlikran 05/29/14 09:21 PM

Help with Complex Array.
 
Help with Complex Array.

Localization/HarvestMapData-en.lua
Localization/HarvestMapData-de.lua
Localization/HarvestMapData-fr.lua

I have three files in my manifest file listed like this. I have them that way to I can use a diff program like BeyoneCompare to line up the names so they are always in the exact sequence.


Lua Code:
  1. Harvest.langs = { "en", "de", "fr", }
  2. Harvest.DataStore = {
  3.    ["alikr"] = {},      --Alik'r Desert
  4.    ["auridon"] = {},    --Auridon, Khenarthi's Roost
  5.    ["bangkorai"] = {},  --Bangkorai
  6.    ["coldharbor"] = {}, --Coldharbour
  7.    ["cyrodiil"] = {},   --Cyrodiil
  8.    ["deshaan"] = {},    --"Deshaan"
  9.    ["eastmarch"] = {},  --Eastmarch
  10.    ["glenumbra"] = {},  --Glenumbra, Betnikh, Stros M'Kai
  11.    ["grahtwood"] = {},  --Grahtwood
  12.    ["greenshade"] = {}, --Greenshade
  13.    ["malabaltor"] = {}, --Malabal Tor
  14.    ["reapersmarch"] = {},  --Reaper's March
  15.    ["rivenspire"] = {}, --Rivenspire
  16.    ["shadowfen"] = {},  --Shadowfen
  17.    ["stonefalls"] = {}, --Stonefalls, Bal Foyen, Bleakrock Isle
  18.    ["stormhaven"] = {}, --Stormhaven
  19.    ["therift"] = {},    --The Rift
  20.    ["craglorn"] = {},    --Craglorn
  21. }
This is the beginning of my complex array. I am using code with permission from Undiscovered but I want to change it.
Lua Code:
  1. Harvest.DataStore["en"]["alikr"] = {
  2. --Alik'r Desert (Daggerfall, lvl 31-37)
  3.    ["alikr_base"] = {            --Alik'r Desert
  4.       --en
  5.       { "Aldunz", 3 },
  6. }
Then for the next part I want to define it that way. So that I can change the first part in the array to this.
Lua Code:
  1. Harvest.DataStore = {
  2.     ["alikr"] = Harvest.DataStore[Harvest.langs]["alikr"],
  3.     ........
  4. }
How can I structure it better? I want it to be something I could do a For loop on like this

Lua Code:
  1. for zone, zones in pairs(Harvest.DataStore) do
  2.     for lang, langs in pairs(zones) do
  3.         for subzone, subzones in pairs(langs) do
  4.             for map, maps in pairs(subzones) do
  5.                 d("Zone : " .. zone .. " : lang : " .. lang .. " : subzone : " .. subzone .. " : map : " .. map)
would return this

Zone : alikr : lang : en : subzone : alikr_base : map : Aldunz

Lua Code:
  1. Harvest.DataStore["alikr"]["en"]["alikr_base"] = {            --Alik'r Desert
  2.       --en
  3.       { "Aldunz", 3 },
  4. }
How can I accomplish that result, I fear I am doing something terribly wrong.

Lua Code:
  1. Harvest.DataStore["en"]["alikr_base"] = {
  2.     --Alik'r Desert (Daggerfall, lvl 31-37)
  3.     --Alik'r Desert
  4.       --en
  5.       { "Aldunz", 3 },
  6. }
  7.  
  8. Harvest.DataStore = {
  9.    ["alikr"] = {Harvest.DataStore["en"]["alikr_base"],
  10.                 Harvest.DataStore["de"]["alikr_base"],
  11.                 Harvest.DataStore["fr"]["alikr_base"]}  --Alik'r Desert
Something like that maybe?

EDIT: Nope none of my variations are working.

Vuelhering 05/29/14 11:44 PM

I don't have an answer for you, but after glancing through this, my brain is screaming "anonymous closure".

Not sure that will do anything, though :)

Lua is odd, but this code just bothers me at a gut level.
Code:

Harvest.DataStore = {
        ["alikr"] = Harvest.DataStore[Harvest.langs]["alikr"],
        ........
}


Wobin 05/30/14 12:36 AM

Quote:

Originally Posted by Vuelhering (Post 8774)
I don't have an answer for you, but after glancing through this, my brain is screaming "anonymous closure".

Not sure that will do anything, though :)

Lua is odd, but this code just bothers me at a gut level.
Code:

Harvest.DataStore = {
        ["alikr"] = Harvest.DataStore[Harvest.langs]["alikr"],
        ........
}


It's storing a table reference at that point. Not sure if that'll actually work as a SV result (if that's what it is).

Wobin 05/30/14 12:39 AM

The answer to 'how do I store this info' will largely rest on the question "What are you doing with the info?"

Note that you can store the information as sparsely as you need for storage purposes, and recombine them in game for speed of reference and create lookup tables and the like.

Sharlikran 05/30/14 12:43 AM

I am going to try this Lua console from source forge, no idea how to use it yet though. ^_^

Does anyone know a good Lua console that is easy to run like Python and Ruby?

Lua Code:
  1. Harvest.langs = { "en", "de", "fr", }
  2.  
  3. Harvest.woodworking = {
  4.     ["en"] = {
  5.         "Ashtree",
  6.         "Beech",
  7.         "Birch",
  8.         "Hickory",
  9.         "Mahogany",
  10.         "Maple",
  11.         "Nightwood",
  12.         "Oak",
  13.         "Yew",
  14.     },
  15.     ["de"] = {
  16.         "Eschenholz",
  17.         "Buche", -- "Buchenholz"
  18.         "Birkenholz",
  19.         "Hickoryholz",
  20.         "Mahagoniholz",
  21.         "Ahornholz",
  22.         "Nachtholz",
  23.         "Eiche",
  24.         "Eibenholz",
  25.     },
  26.     ["fr"] = {
  27.         "Frêne",
  28.         "Hêtre",
  29.         "Bouleau",
  30.         "Hickory",
  31.         "Acajou",
  32.         "Érable",
  33.         "Bois de nuit",
  34.         "Chêne",
  35.         "If",
  36.     },
  37. }
  38.  
  39. function Harvest.IsValidWoodworkingName(name)
  40.     local nameMatch = false
  41.     for lang, langs in pairs(Harvest.langs) do
  42.         for k, v in pairs(Harvest.woodworking[langs]) do
  43.             if v == name then
  44.                 nameMatch = true
  45.             end
  46.         end
  47.     end
  48.  
  49.     return nameMatch
  50. end

That all works fine, so I have to build off of it and try to apply it to what I want with the map names.

Wobin 05/30/14 01:07 AM

Quote:

Originally Posted by Sharlikran (Post 8777)
I am going to try this Lua console from source forge, no idea how to use it yet though. ^_^

Does anyone know a good Lua console that is easy to run like Python and Ruby?

Lua Code:
  1. function Harvest.IsValidWoodworkingName(name)
  2.     local nameMatch = false
  3.     for lang, langs in pairs(Harvest.langs) do
  4.         for k, v in pairs(Harvest.woodworking[langs]) do
  5.             if v == name then
  6.                 nameMatch = true
  7.             end
  8.         end
  9.     end
  10.  
  11.     return nameMatch
  12. end

That all works fine, so I have to build off of it and try to apply it to what I want with the map names.

Just as a note, you can escape early from that loop by using return true as soon as you have a match and return false outside the loop.

Sharlikran 05/30/14 01:38 AM

Quote:

Originally Posted by Wobin (Post 8779)
Just as a note, you can escape early from that loop by using return true as soon as you have a match and return false outside the loop.

Lua Code:
  1. function Harvest.IsValidWoodworkingName(name)
  2.     for lang, langs in pairs(Harvest.langs) do
  3.         for k, v in pairs(Harvest.woodworking[langs]) do
  4.             if v == name then
  5.                 return true
  6.             end
  7.         end
  8.     end
  9.  
  10.     return false
  11. end
Like that you mean?

Sharlikran 05/30/14 01:40 AM

Warning: Spoiler

If you click the spoiler, as you can see I need to make it modular or I'll end up with a wall of text. Each map file is already over 1200 lines long.

Quote:

Originally Posted by Wobin (Post 8776)
The answer to 'how do I store this info' will largely rest on the question "What are you doing with the info?"

Note that you can store the information as sparsely as you need for storage purposes, and recombine them in game for speed of reference and create lookup tables and the like.

Two things 1) I want to pass the map name, "cahute de Cadwell^fd" as an argument to a function and return the zone, subzone, and an index number. Then use string.format to end up with "coldharbor/coldharbour_base". The index would be that it was the 5th map name in the array. 2) Pass the zone, subzone, and the index and get the map name of any of the three languages thus ending up with a way to translate "cahute de Cadwell^fd" to "Cadwell's Hovel".

Sharlikran 05/30/14 02:00 AM

Lua Code:
  1. Harvest.DataStore_en_auridon_base
  2. Harvest.DataStore.en.auridon.base
Ok I am confused. What is the difference between the two lines. ESO told me I was trying to access a nil value with the line that has the dots in it. Do this dots make Lua think it's a function? The other line works.

Wobin 05/30/14 03:10 AM

Quote:

Originally Posted by Sharlikran (Post 8782)
Lua Code:
  1. Harvest.DataStore_en_auridon_base
  2. Harvest.DataStore.en.auridon.base
Ok I am confused. What is the difference between the two lines. ESO told me I was trying to access a nil value with the line that has the dots in it. Do this dots make Lua think it's a function? The other line works.

The second are table references, the first is a single variable.

Essentially:

Code:

Harvest.DataStore.en.auridon.base
is
Code:

Harvest = {}
Harvest["DataStore"] = {}
Harvest["DataStore"]["en"] = {}
Harvest["DataStore"]["en"]["auridon"] = {}
Harvest["DataStore"]["en"]["auridon"]["base"] = {}

Code:

Harvest.DataStore_en_auridon_base
is
Code:

Harvest = {}
Harvest["DataStore_en_auridon_base"] = {}

You have to create the table before you can add further items to it otherwise you'll get a nil reference.

I suggest you read up on Lua, PiL is a good resource to learn the syntax of Lua

Wobin 05/30/14 03:21 AM

Quote:

Originally Posted by Sharlikran (Post 8780)
Lua Code:
  1. function Harvest.IsValidWoodworkingName(name)
  2.     for lang, langs in pairs(Harvest.langs) do
  3.         for k, v in pairs(Harvest.woodworking[langs]) do
  4.             if v == name then
  5.                 return true
  6.             end
  7.         end
  8.     end
  9.  
  10.     return false
  11. end
Like that you mean?

Yes. That way, if there's a match, it doesn't bother checking the rest of the tables.

As for your requirements, there are two ways you can go about it, depending on how often the information is requested.

If the requests are relatively scarce, you can do as you do above, and just create functions that loop through the tables, til you find a match, then create a chunk of info for your use.

If you need more speed, ie, your requests are very very often, you can create lookup tables in memory so that when you reference MapName["Aldunz"] it'll return { [Zone] : "alikr", [lang] : "en", [subzone] : "alikr_base", [map] : "Aldunz"}. This will frontload the work, by doing it all at load, but will speed up lookup. You just need to know what information you're using, and what format you need the result in.

I advise you read up on how Lua handles tables and references first though, so you understand just what sort of structures you're creating.

Sharlikran 05/30/14 07:21 AM

Quote:

Originally Posted by Wobin (Post 8786)
I advise you read up on how Lua handles tables and references first though, so you understand just what sort of structures you're creating.

That is good advice. Since you probably know more then I, does this page seem to you like it would explain it well enough? Do you think it's missing what you were trying to explain about a "lookup tables"? What do you think? I wont need to remove, insert, or sort the table because it will remain constant.

Halja 05/30/14 07:47 AM

Quote:

Originally Posted by Sharlikran (Post 8795)
That is good advice. Since you probably know more then I, does this page seem to you like it would explain it well enough? Do you think it's missing what you were trying to explain about a "lookup tables"? What do you think? I wont need to remove, insert, or sort the table because it will remain constant.

Unless I'm not completely reading this thread, you can vastly simplify your code by only loading the language file(s) the client has currently running. You do this in your manifest by using the $(language) variable. At run-time the launcher will pick. That way you are also using less memory, your search index can be in your native language, and the code does not need all the if else on language anymore. The value will be the expected text based on the language.

Instead of three line in the manifest like
Code:

Localization/HarvestMapData-en.lua
Localization/HarvestMapData-de.lua
Localization/HarvestMapData-fr.lua

It would be:
Code:

Localization/HarvestMapData-$(language).lua
Based on what the cVar("Language.2") hold, one of your three originally files will be loaded. This is how ZOS is doing the localization for the most part on strings.
Hope this help,
--halja

Garkin 05/30/14 08:19 AM

Metatables
 
I understand that you want to store references from three different tables into the single table. If you use unique keys, it can be done using metatables. If you use just indexes (they are not unique), it will be much more complicated.

I don't know if it is exactly what you want, but I think it's worth of trying.
Lua Code:
  1. Harvest.DataStore["en"]["alikr_base"] = {
  2.    ["Aldunz"] = 3,
  3.     .........
  4. }
  5. Harvest.DataStore["de"]["alikr_base"] = {
  6.    ["Aldunz^N,in"] = 3,
  7.     .........
  8. }
  9. Harvest.DataStore["fr"]["alikr_base"] = {
  10.    ["Aldunz^M"] = 3,
  11.     .........
  12. }
  13.  
  14. Harvest.DataStore["alikr"]["alikr_base"] = {}
  15.  
  16. setmetatable(Harvest.DataStore["de"]["alikr_base"], { __index = Harvest.DataStore["fr"]["alikr_base"] })
  17. setmetatable(Harvest.DataStore["en"]["alikr_base"], { __index = Harvest.DataStore["de"]["alikr_base"] })
  18. setmetatable(Harvest.DataStore["alikr"]["alikr_base"], { __index = Harvest.DataStore["en"]["alikr_base"] })

Metatables:
http://nova-fusion.com/2011/06/30/lu...bles-tutorial/
http://lua-users.org/wiki/MetatableEvents
http://lua-users.org/wiki/MetamethodsTutorial

Sharlikran 05/30/14 08:29 AM

Quote:

Originally Posted by Halja (Post 8796)
Unless I'm not completely reading this thread, you can vastly simplify your code by only loading the language file(s) the client has currently running.

Nope, I actually want all three because I want to translate it. I want to pass a foreign map name like "cahute de Cadwell^fd" or "Cadwells Heim^Ng,in" and return "Cadwell's Hovel". I do check for the client language. So if someone were using a french client I want to take "Cadwell's Hovel" or "Cadwells Heim^Ng,in" and return "cahute de Cadwell^fd".

Sharlikran 05/30/14 08:34 AM

The first link to the Lua Metatables Tutorial looks nice but I'll look at all three. It made my head explode looking at it but I'll do my best to read it and try it with the small example I listed above and try to return the values rather then working with the entire list of over 559 maps. ;)

lyravega 05/30/14 08:38 AM

You don't need for loops to find if something exists in a table if you are not using an array. As long as it is a table, you can use keys like values to check if something exists and work from there. If you are not going to do table-to-table operations, or an operation that HAS to go through all the elements in a table (for example, counting), then you really don't need for loops for them.

http://www.esoui.com/forums/showthre...=8802#post8802

Code:

woodworking = {
    ["en"] = {
        ["Ashtree"] = true,
        ["Beech"] = true,
        ["Birch"] = true,
        ["Hickory"] = true,
        ["Mahogany"] = true,
        ["Maple"] = true,
        ["Nightwood"] = true,
        ["Oak"] = true,
        ["Yew"] = true,
    },
}

Now, all these will return true:

Code:

if woodworking
if woodworking.en
if woodworking.en.Ashtree
local TEST = "Ashtree"; if woodworking.en[TEST]

The last one is a special case; unless you use [] it will look for a key named TEST rather than a key named TEST's value.

Sharlikran 05/30/14 08:45 AM

Warning: Spoiler

So that we aren't talking about different code. I am going to try to attempt to convert that exact code to the metatable that Garkin mentioned and do effectively what Garkin and Wobin are talking about. I'll post again when I think I have figured it out. Also I removed the numbers because that was part of Undiscovered. Again the code is used with permission, in case anyone needs to know. So I don't care about the numbers unless the metatable tutorial specifies that I should use a sequential list of values for each map name.

Garkin 05/30/14 09:08 AM

Quote:

Originally Posted by Sharlikran (Post 8799)
Nope, I actually want all three because I want to translate it. I want to pass a foreign map name like "cahute de Cadwell^fd" or "Cadwells Heim^Ng,in" and return "Cadwell's Hovel". I do check for the client language. So if someone were using a french client I want to take "Cadwell's Hovel" or "Cadwells Heim^Ng,in" and return "cahute de Cadwell^fd".

EDIT: I think the function wasn't working for all languages, so I have to changed it to use index:
Lua Code:
  1. local mapNames = {
  2.    ["en"] = {
  3.       "Alik'r Desert",
  4.       "Auridon",
  5.    }
  6.    ["de"] = {
  7.       "Alik'r-Wüste^N,in",
  8.       "Auridon^N,in",
  9.    ["fr"] = {
  10.       "désert d'Alik'r^md",
  11.       "Auridia^F",
  12.    }
  13. }
  14.  
  15. local language = GetCVar("language.2")
  16. local langlist = { "en", "de", "fr" }
  17.  
  18. function TranslateName(name)
  19.    for _, lang in ipairs(langlist) do
  20.       for i, localizedName in ipairs(mapNames[lang])
  21.          if name == localizedName then
  22.             return mapNames[language][i]
  23.          end
  24.       end
  25.    end
  26.    return name
  27. end

If you want faster translation, you have to use two tables:
lua Code:
  1. Harvest.mapSystem = {
  2.    ["alikr/alikr_base"] = {"Alik'r Desert", "Alik'r-Wüste^N,in", "désert d'Alik'r^md"},
  3.    ["auridon/auridon_base"] = {"Auridon", "Auridon^N,in", "Auridia^F"},
  4.    ["bangkorai/bangkorai_base"] = {"Bangkorai", "Bangkorai^N,in", "Bangkoraï^F"},
  5.    ["coldharbor/coldharbour_base"] = {"Coldharbour", "Kalthafen^N,in", "Havreglace^M"},
  6.    ["cyrodiil/ava_whole"] = {"Cyrodiil", "Cyrodiil^N,in", "Cyrodiil^F"},
  7.    ["deshaan/deshaan_base"] = {"Deshaan", "Deshaan^N,in", "Deshaan^F"},
  8.    ["eastmarch/eastmarch_base"] = {"Eastmarch", "Ostmarsch^N,in", "Estemarche^F"},
  9. }
  10.  
  11. local mapNames = {
  12.    ["en"] = {
  13.       ["Alik'r Desert"] = "alikr/alikr_base",
  14.       ["Auridon"] = "auridon/auridon_base",
  15.       ["Bangkorai"] = "bangkorai/bangkorai_base",
  16.       ["Coldharbour"] = "coldharbor/coldharbour_base",
  17.       ["Cyrodiil"] = "cyrodiil/ava_whole",
  18.       ["Deshaan"] = "deshaan/deshaan_base",
  19.       ["Eastmarch"] = "eastmarch/eastmarch_base",
  20.       --some map names are not unique, so we have to deal with it
  21.       ["Sancre Tor"] = "not unique"
  22.    }
  23.    ["de"] = {
  24.       ["Alik'r-Wüste^N,in"] = "alikr/alikr_base",
  25.       ["Auridon^N,in"] = "auridon/auridon_base",
  26.       ["Bangkorai^N,in"] = "bangkorai/bangkorai_base",
  27.       ["Kalthafen^N,in"] = "coldharbor/coldharbour_base",
  28.       ["Cyrodiil^N,in"] = "cyrodiil/ava_whole",
  29.       ["Deshaan^N,in"] = "deshaan/deshaan_base",
  30.       ["Ostmarsch^N,in"] = "eastmarch/eastmarch_base",
  31.    }
  32.    ["fr"] = {
  33.       ["désert d'Alik'r^md"] = "alikr/alikr_base",
  34.       ["Auridia^F"] = "auridon/auridon_base",
  35.       ["Bangkoraï^F"] = "bangkorai/bangkorai_base",
  36.       ["Havreglace^M"] = "coldharbor/coldharbour_base",
  37.       ["Cyrodiil^F"] = "cyrodiil/ava_whole",
  38.       ["Deshaan^F"] = "deshaan/deshaan_base",
  39.       ["Estemarche^F"] = "eastmarch/eastmarch_base",
  40.    }
  41. }
  42.  
  43. local language = GetCVar("language.2")
  44. local langlist = { ["en"] = 1, ["de"] = 2, ["fr"] = 3 }
  45.  
  46. function TranslateMapName(name)
  47.    for lang in pairs(langlist) do
  48.       local textureName = mapNames[lang]
  49.       if textureName then
  50.          if Harvest.mapSystem[textureName] then
  51.             --if translated name is not defined, return english name
  52.             return Harvest.mapSystem[textureName][langlist[language]] or Harvest.mapSystem[textureName][1]
  53.          else
  54.             --if texture key doesn't exist in Harvest.mapSystem (for example key "not unique"), return original name
  55.             return name
  56.          end
  57.       end
  58.    end
  59.    --translation not found, return original name
  60.    return name
  61. end

Sharlikran 06/02/14 12:40 AM

I love it Garkin thanks. I am still trying to cut and paste all the names from the file and organize it. Once I finally get it all done I'll let you know how it works. If I have any issues I'll see if you have time to help. Thanks again.


All times are GMT -6. The time now is 01:34 AM.

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