Hi, I'm currently creating a very general open source inventory system for everyone to use, but i've come across a problem. I've created a modulescript called ItemDB where I keep track of all items and their properties. It looks like this right now:
itemDB = { ["TestBrick"] = { Image = "", Properties = {"pickupable"}, Path = game.ReplicatedStorage.TestBrick, hasProperty = function(self, property) for i, p in pairs(itemDB["TestBrick"].Properties) do if p == property then return true end end return false end }; } return itemDB
So currently I can do
itemDB["TestBrick"]:hasProperty("pickupable")
which will return true, which is great! However this is only single function, which is several lines long, and every item will need access to several functions. ItemDB is gonna be very long with a minimal amount of items. I'd love to put the hasProperty function in the itemDB table itself, instead of putting it in every item's table. If I put the function in the ItemDB table and then call it on ["TestBrick"], i get the following error:
ReplicatedFirst.PickUpItems:9: attempt to call method 'hasProperty' (a nil value)
Which makes sense, since hasProperty is indeed not present in ["TestBrick"]. Is there any way to get this to work the way I want it? Like, a way to make ["TestBrick"] inherit all functions of ItemDB?
One way to do this would be to use metatables and have each table in itemsDB
have the same __index
table in the metastable.
The __index
metamethod is called is called/indexed every time that indexing the table fails
local t = {} local f = {} f.Value = 3 print(t.Value) -- this will print "nil" setmetatable(t, {__index = f}) print (t.Value) -- this will print "3" -- 'Value' is not in 't' so it looks in the index of 't' -- So, t.Value is f.Value, which is 3
Implementing this idea, you could do something like:
local itemindex = { -- Contain all properties and methods that members of itemDB should have } setmetatable(itemDB, { -- Now to add it to new tables. __newindex = function (tab, index, value) -- Runs every time items are added to the itemDB table with the assignment operator setmetatable(value, {__index = itemindex}) -- Set the index to itemindex rawset(tab, index, value) -- Rawset ignores __newindex, without this it would cause an infinite loop. end }) -- However this will only work with the assignment operator -- meaning that __newindex is not called when table.insert is used.
For tables that are manually put in itemDB
like
itemDB = { Item1 = {}, Item2 = {}, }
you would need to manually specify the index like
itemDB = { Item1 = setmetatable({}, {__index = itemindex}), Item2 = setmetatable({}, {__index = itemindex}), }
Or you could do (if using the __newindex metamethod)
itemDB = {} itemDB.Item1 = {} itemDB.Item2 = {}