How to run code if a property is changed?

Suppose I got something like this

local Gun = {}
Gun.__index = Gun

function Gun.new(gunInstance, owner, enabled)
	local metaData = {}
	setmetatable(metaData, Gun)
	
	metaData.Model = gunInstance
	metaData.Owner = owner
	metaData.Enabled = enabled
	
	return metaData
end

return Gun

I need code to run when .Enabled is changed. How would I go about doing that?

You can create a bindable event and a setter to achieve this.

When you set the variable, you can fire the bindable event!

what is a “setter” in this context

Use Instance:GetPropertyChangedSignal(string: property) or Instance.Changed

Edit: just realized what you wanted. Use the __newindex on a metatable. Ex:

Metatable = {}
Metatable.__newindex = function(selfTable,key,value)
    if key == "Enabled" then
        rawset(selfTable,"Enabled",value)
        -- do stuff with the value variable
        print("set to " .. tostring(value))
   end
end

setmetatable({},Metatable).Enabled = false -- "set to false"

You can create one along the lines of Gun:SetEnabled(bool)

That is just a proxy at that point. The whole point is to detect changes to the property

1 Like
local Gun = {}
Gun.__index = function(_,key)
    if key == "Enabled" then
        --thing
    end
    return Gun[key]
end

function Gun.new(gunInstance, owner, enabled)
	local metaData = {}
	setmetatable(metaData, Gun)
	
	metaData.Model = gunInstance
	metaData.Owner = owner
	metaData.Enabled = enabled
	
	return metaData
end

return Gun

Perhaps something like this would work for you?

1 Like

Who is listening to the change? If it’s a client then fire the client, which I’m assuming will be found through the Owner data. If it’s the server, then a BindableEvent would be useful. Just remember that only one subscriber can be listening at a time with the Bindable Event.

I am getting some weird stack overflow errors. This is what I tried to do

local Gun = {}
Gun.__index = Gun
Gun.__newindex = function(metaData,key,value)
	if key == "Enabled" then
		metaData.Enabled = value
		print("test", metaData.Enabled)
		-- do stuff with the value variable
	end
end

function Gun.new(gunInstance, owner, enabled)
	local metaData = setmetatable({}, Gun)
	
	metaData.Model = gunInstance
	metaData.Owner = owner
	metaData.Enabled = enabled
	
	return metaData
end

return Gun

You have to index the class table or itll call __index inside __index infinitely

Fixed it, whoops

Forgot to use rawset

How does the code work and why do you need to use rawset

rawset is needed as if I didn’t use it, it would constantly set the Enabled variable again, making an infinite loop. Though now that I think about it, a side effect of this would be that it wouldn’t work again if you set it again so maybe you should have a separate table for the actual values.

Your code doesnt work, even using rawset

Are you running it directly in the command bar?

No, I am running it on the server

local Gun = {}
Gun.__index = Gun
Gun.__newindex = function(metaData,key,value)
	if key == "Enabled" then
		rawset(metaData,"Enabled",value)
		print("test", metaData.Enabled)
		-- do stuff with the value variable
	end
end

function Gun.new(gunInstance, owner, enabled)
	local metaData = setmetatable({}, Gun)
	
	metaData.Model = gunInstance
	metaData.Owner = owner
	metaData.Enabled = enabled
	
	return metaData
end

return Gun

local Gun = {}
Gun.__index = Gun
Gun.__newindex = function(metaData,key,value)
	if key == "Enabled" then
		rawset(metaData,"Enabled",value)
		print("test", value)
		-- do stuff with the value variable
	end
end

function Gun.new(gunInstance, owner, enabled)
	local metaData = setmetatable({}, Gun)
	
	metaData.Model = gunInstance
	metaData.Owner = owner
	metaData.Enabled = enabled
	
	return metaData
end

return Gun

Try this maybe? Though you should have a separate table for the actual values so that it works a second time due to how newindex works

Why don’t you just put the event inside the constructor function?:

local Gun = {}
Gun.__index = Gun

function Gun.new(gunInstance, owner, enabled)
	local metaData = {}
	setmetatable(metaData, Gun)
	
	metaData.Model = gunInstance
	metaData.Owner = owner
	metaData.Enabled = enabled
	
    gunInstance:GetPropertyChangedSignal("Enabled"):Connect(function()
        -- run code here
    end

	return metaData
end

return Gun

because the enabled shown in the oop function isnt the enabled function in the gunInstance

Anything in “metaData” is the gun instance forever and always because tables are objects