Idk if I wrote the title properly however what I’m asking is, let’s say I have a table:
local Table = {}
I wanna be able to detect when something like table.insert(Table, 123) is called. (On that table)
Is this possible?
Idk if I wrote the title properly however what I’m asking is, let’s say I have a table:
local Table = {}
I wanna be able to detect when something like table.insert(Table, 123) is called. (On that table)
Is this possible?
can’t you just detect it being indexed the line after you insert something?
For example:
table.insert(Table, 123)
print("Inserted")
For checking when a table is indexed, you can use the __index
metamethod.
For checking when a table index if written to, you can use the __newindex
metamethod.
local tbl = setmetatable({},{
__index = function()print"indexed"end,
__newindex = function()print"newindexed"end
})
local _ = tbl[1] --> indexed
tbl[1] = 1 --> newindexed
Although, if there is a current index in the table, these events wont fire.
local tbl = setmetatable({1},{
__index = function()print"indexed"end,
__newindex = function()print"newindexed"end
})
local _ = tbl[1] -- nothing prints
tbl[1] = 1 -- nothing prints
In regards to table.insert
, it uses raw sets and gets, so you will be unable to detect when it is inserted.
To force all indexes and new indexes to be accessed using the metamethod, it is common to make a new userdata using the Userdata newproxy(Bool hasMetatable)
method. table.insert, rawset, and rawget don’t work on userdatas.
This isn’t how you’d normally go about things like this but you could run a loop and check the differences
local function Watch(t, filter, func)
local prev = {}
local diff = {}
while true do
diff = {} -- Clear old differences
for pos, value in pairs(t) do
if not prev[pos] == value then -- Check for discrepancies
if (value == nil and filter == "Removed") or (prev[pos] == nil and filter == "Inserted") or (not filter) then
diff[pos] = {Previous = prev[pos], New = value}
end
prev[pos] = value -- Update for next time
end
func(diff)
game:GetService("RunService").Heartbeat:Wait()
end
end
local myTable = {}
Watch(myTable, "Inserted", function(diff)
for pos, data in pairs(diff) do
print("Inserted "..data.New.." at "..pos)
end
end)
Not tested but you get the idea
I did this
setmetatable(PlayerInventory.ItemInventory,{
__newindex = function() DataStore.InventoryNotifcation() end
})
The notifcation function is set to print(“New index”)
However when I use table.insert() on the ItemInventory this does not fire.
As this could work I’m looking for a shorter way to do it preferably without loops
local RawTable = {}
local Table = setmetatable({}, {
__index = function(_, Key)
print("Read table with key: " .. tostring(Key))
return RawTable[Key]
end,
__newindex = function(_, Key, Value)
print("Write to table with key: " .. tostring(Key) .. " and value: " .. tostring(Value))
RawTable[Key] = Value
end,
})
Table.Test1 = 1
Table[1] = 123
print(Table.Test1)
print(Table.Test2)
print(Table[1])
The insert method will still work on this table and the metamethod will not able able to detect it. Also something that should be mentioned that hasn’t is that the index metamethod only fires when an index is missing. Thus, userdatas prevent indexes from being added using insert / rawset and always ensure the metamethod fires.
After reading your post, I think what you’re looking for is how to detect a new value being added to the table. But if you want to index tables or something then use the metatable method instead and ignore this.
I have tested it and have come up with a solution , for detecting a new inserted value and it’s type , this does not utilize setmetatable .
It will detect whether an item has been inserted and then even tell you what type of value was inserted through such a simple way too !! (like boolean , string etc.)
Output :
proves to be convenient sometimes, to detect the type as well
tablex = {}
local printed = false--some sort of debounce methodology
local default_amount_of_values = #tablex
print("initial values are " .. default_amount_of_values)
local change_detected=false
function detect_change()
if change_detected==false and printed==false then
local new_amount = table.getn(tablex)--get values passed on heartbeat
if new_amount>default_amount_of_values--difference detected
then change_detected=true--meaning a change was detected
print("a change was detected")
print((type(tablex[#tablex])) .." was added")--print the new value's type
printed=true
change_detected=true
end
end
end
local runService = game:GetService("RunService")
runService.Heartbeat:Connect(detect_change)--connect this to run on heartbeat
that all would detect a change, but we didn’t have anything added yet so let’s test it !
right below this line in my code :
if change_detected==false and printed==false then
add this line below that line in my code :
table.insert(tablex,"string")
so that’s why I implemented a debounce mechanism (printed==false ) etc.
and now it would only fire maximum about 2 times and will detect any change in the table.
Use this script anywhere, preferably in a server script, or run this in the Command bar and look at the Output
tablex = {}
local printed = false
local default_amount_of_values = #tablex
print("initial values are " .. default_amount_of_values)
local change_detected=false
function detect_change()
if change_detected==false and printed==false then
table.insert(tablex,"string") --we insert a value for testing purposes..
local new_amount = table.getn(tablex)
if new_amount>default_amount_of_values
then change_detected=true
print("a change was detected")
print((type(tablex[#tablex])) .." was added")
printed=true
change_detected=true
end
end
end
local runService = game:GetService("RunService")
runService.Heartbeat:Connect(detect_change)
Output :
Exactly what I needed, Thank you.