So I am trying to edit my config list where it has to edit robbed to true when entity is equal to entity in the list (entities get generated when my script is starting)
Config file
Config.location = {
[1] = {
x = 24.39,
y = -1345.776,
z = 29.49,
h = 267.58,
robbed = false,
entity = nil
},
[2] = {
x = -47.7546,
y = -1759.276,
z = 29.421,
h = 48.035,
robbed = false,
entity = nil
},
}
So this list gets loaded - When [1] has been robbed it should change robbed in [1] if the entity matches.
I would imagine i should do a for loop but i'm still clueless.
As Config.list is a sequence with positive integer keys starting from 1 you can conveniently use the iparis iterator in combination with a generic for loop to check every entry in your list.
for i,v in ipairs(Config.location) do
v.robbed = v.entity == someOtherEntity and true or false
end
Of course your entity entries shouldn't be nil as this wouldn't make sense.
Related
How do I get the full path to the required value in the table? I want to track changes in another table through a proxy table.
I understand that I need to use metatables and __index in it. But I haven't been able to come up with a tracker yet.
Sample table structure:
Objects = {
Panel = { layer = 1, x = 600, y = 328, w = 331, h = 491;
objects = {
label = { layer = 1, x = 0, y = 0, text = 'header' };
Window = { layer = 2, x = 400, y = 100, w = 100, h = 100;
objects = {
label = { layer = 1, x = 0, y = 0, text = 'lorem ipsum dorem' };
};
};
};
};
};
Path: Objects.Panel.objects.Window.objects.label.text
I tried to create a metatable for each of the tables and collect the result of each call to __index into a table in order to roughly understand which key and value were retrieved or changed in order to synchronize these values with other tables.
This will prove itself to be horrendously slow and memory inefficient. Anyway, you were right on the track: proxy and handle __index and __newindex metamethods to your liking. This being said you also need to track the state of the proxy somehow.
You can try to hide it with some closures and upvalues but the easy way is to store the information directly in the proxy tables:
function make_tracker (o, name)
local mt = {}
mt.__index = function (proxy, key)
local path = {unpack(rawget(proxy, "__path"))} -- Stupid shallow copy
local object = rawget(proxy, "__to")
table.insert(path, key)
if type(object[key]) == "table" then
return setmetatable({__to = object[key], __path = path}, mt)
else
return table.concat(path, ".") .. " = " .. tostring(object[key])
end
end
return setmetatable({__to = o, __path = {name}}, mt)
end
__to fields indicates what proxy should point to and __path is there to cover fields we have trespassed so far. It does a shallow copy, so that one can use subproxies with local variables. name parameter is there to initialize the name of the first table, as you just simply can't know that. You use it like this:
local tObjects = make_tracker(Objects, "Objects")
local subproxy = tObjects.Panel.objects.Window
print(subproxy.objects.label.text)
print(tObjects.Panel.objects.label.text)
print(subproxy.x)
-- prints:
-- Objects.Panel.objects.Window.objects.label.text = lorem ipsum dorem
-- Objects.Panel.objects.label.text = header
-- Objects.Panel.objects.Window.x = 400
Of course, I doubt that appending the path to the original value is what you want. Modify insides of else block:
return table.concat(path, ".") .. " = " .. tostring(object[key])
according to your needs, e.g:
register_tracked_path(table.concat(path, "."))
return object[key]
If you want to handle modification of values you need to extend the metatable with similar __newindex.
I'm working on a game where a bunch of characters will be generated on the fly, based on some constraints defined either in the project or externally via mod files. I am using MoonSharp Lua (5.2) interpreter for interfacing with my C# code, and Lua tables to store the constraint presets. As an example:
require "Defaults"
AgePresets = {}
-- Single value
AgePresets.Newborn = 0
-- Simple ranges
AgePresets.Default = defaultAgeRange --referring to the Defaults require
AgePresets.Child = {1, 12}
AgePresets.Teenager = {13, 19}
AgePresets.YoungAdult = {20, 29}
AgePresets.Adult = {30, 40}
AgePresets.MiddleAge = {40, 60}
AgePresets.Senior = {61, 80}
AgePresets.Elder = {81, 99}
AgePresets.Methuselah = {100, 150}
AgePresets.Methuselah2 = {150, 200}
-- Weighted ranges // again referring to previously defined elements to keep things concise
AgePresets.Tween = {
{weight = 1, minmax = AgePresets.Teenager },
{weight = 1, minmax = AgePresets.YoungAdult }
}
This works fine, but from an end-user point of view, there's a lot of unnecessary typing involved. We are clearly working on AgePresets here but it is still mentioned as a prefix before every member name.
I could of course define AgePresets as an array, like AgePresets = { Child = {}, Teenager = {} } but the problem with that is then I cannot refer to previously defined elements in the array.
This doesn't work:
AgePresets = {
Child = {1,12},
RefToChild = Child, //attempt to index a nil value exception
Teen = {13,19}
}
What I ideally want to achieve is a clean, concise way for users to enter this data in, like in the first example but without having to put AgePresets. prefix before everything. How do I go about declaring a scope in a file such that all succeeding members defined in the file will be within that scope, while maintaining the ability to refer to other members defined previously in the scope?
AgePresets = setmetatable({}, {__index = _G})
do
local _ENV = AgePresets
Newborn = 0
Child = {1,12}
RefToChild = Child -- this ref is Ok
Teen = {13,19}
YoungAdult = {20,29}
Tween = {
{weight = 1, minmax = Teen },
{weight = 1, minmax = YoungAdult }
}
rnd = math.random(10) -- global functions are available here
end
setmetatable(AgePresets, nil)
You can mix the two styles: table constructor for fields that don't need to reference variables that aren't in scope yet, followed by assignment statements for the rest.
I would do that unless the order of the fields in the code significantly enhanced comprehension.
I'm going to simplify the situation as much as I can. I have the following code:
windows = { "window1", "window2" }
window1 = {
x = 100
y = 100
properties = { active = false, width = 200, height = 200 }
}
window2 = {
x = 0
y = 0
properties = { active = false, width = 200, height = 200 }
}
If I do the following, I get the correct output:
print (window1.x)
OUTPUT: 0
print (window1.properties.active)
OUTPUT: false
HOWEVER, if I iterate through the list, I get "nil" values for "l.x" and "l.properties.active":
for _,l in ipairs(windows) do
print (l)
print (l.x)
print (l.properties.active)
end
Is there a different way I need to iterate through the variables in the lists, so I can get the values?
That is not a nested table, but just a table containing strings. And, as you just saw, a string doesn't contain a value for the key "x".
You have to put the tables in a sequence:
local window1 = {...} -- first table
local window2 = {...} -- second table
local windows = {window1, window2}
for _,l in ipairs(windows) do
-- do stuff with l
end
Or, if you want to keep the list of strings and iterate over the strings, put the windows in a second table using these strings as a key.
local windowNames = { "window1", "window2" }
local windows = {}
windows.window1 = {...} -- first table
windows.window2 = {...} -- second table
for _,l in ipairs(windowNames) do
local ourWindow = windows[l]
-- do stuff with ourWindow
end
I got a table which is not meant to be sorted in a way I need it to be sorted at a specific point.
Thus, I cannot sort the table while creation but have to sort it when needed.
Problem is, there are plenty gabs in the indeces and the Values I want to sort here are nested.
Simplified model:
table = {
[1] = { a = 1 , b = 31231, c = { c1 = "foo" , true } },
[8] = { a = 2 , b = 5231 , c = { c1 = "bar" , true } },
[92] = { a = 8 , b = 2 , c = { c1 ="asdgköbana" , false } },
}
Now I want to sort this table by length of c[1].
How can I do that in the fastest way? Length of table in first dimension will stay under 100 entries.
Indices don't need to be kept. So by a table with 3 entries, it's okay when last index is [3] after the portage. Basicly in this case, I only use the index to identifies neighbors, they have no prior use.
Using table as a variable kills the table library, which you need to get the sort function.
Try the code below. Note that it makes a new table to hold the sorted list but reuses the internal tables.
local t = {
[1] = { a = 1 , b = 31231, c = { c1 = "foo" , true } },
[8] = { a = 2 , b = 5231 , c = { c1 = "bar" , true } },
[92] = { a = 8 , b = 2 , c = { c1 ="asdgköbana" , false } },
}
local s = {}
for k,v in pairs(t) do
s[#s+1]=v
end
table.sort(s,function (a,b)
return #a.c.c1 < #b.c.c1
end)
for k,v in ipairs(s) do
print(k,v.a,v.c.c1)
end
I'm writing a program with lua. I have data that organized in the following way:
t= {
i1 = {
p1 = { value = "i1p1" },
p2 = { value = "i1p2" },
-- etc
pm = { value = "i1pm" }
},
i2 = {
p1 = { value = "i2p1" },
p2 = { value = "i2p2" },
-- etc
pm = { value = "i2pm" }
},
im = {
p1 = { value = "imp1" },
p2 = { value = "imp2" },
-- etc
pm = { value = "impm" }
}
} --(inner tables)
In another way each group of data is indexed by two variables i&p,I am sure that the data is kept correctly but I want a way to print the data from their tables because I won't know the values of i and p to iterate over them or even the numbers n & m any body know how to do this with lua?
If you know the depth of your nested (inner) tables, you can iterate explicitly to that depth:
for k1,v1 in pairs(t) do
for k2,v2 in pairs(v1) do
for k3, v3 in pairs(v2) do
print(k3, ":", v3)
end
end
end
Alternatively, you can recursively iterate into your nested structure:
function print_tbl(tbl)
if type(tbl) == "table" then
for _,v in pairs(tbl) do
print_tbl(v)
end
else
print(tbl)
end
end
print_tbl(t)
This is just an example. If your tables contain functions, contains userdata, or your nesting has cycles, you'll need a different approach. Take a look at table serialization on the Lua user wiki. Serialization requires sensible handling of tables with nesting, functions, cycles, etc. You may be able to use lessons learned on your data.