New API Instance:GetPropertyChangedSignal()

This new method returns a version of the Instance.Changed signal that is will be fired for just one property.

The idea behind this is that it’s sometimes needlessly expensive to listen to the Changed signal for all properties when you only care about a few properties or just one property. Using this API a filtered version of the signal can be used to listen to only those properties.

An example of this is the CurrentCamera.Changed listener in the PopperCamera script.

local function OnCameraChanged(property)
	if property == 'CameraSubject' then
		-- Do CameraSubject specific stuff here
	end
end

The issue with code like this is that it makes other Camera properties a lot more expensive to update, especially busy properties like CFrame. The CFrame property for the Camera can be updated twice per frame (once for the camera update and then once for the occlusion update) and for each of these updates there are around six Changed signal listeners in the CameraScripts and PlayerScripts that need to be fired. This is made worse by the fact that the update also needs to fire the Changed signal with the legacy CoordinateFrame property.

With the new GetPropertyChangedSignal API expensive listeners like the above code can be replaced with the following:

workspace.CurrentCamera:GetPropertyChangedSignal("CameraSubject"):connect(function()
	-- Code that deals with CameraSubject update here
end)
77 Likes

Would it be possible for some behaviour regarding GetPropertyChangedSignal to be changed (heh)?

Currently, .Changed doesn’t fire for certain busy properties such as Position of parts (unless manually set, of course). This is undesirable in cases where I do in fact want to listen to Position changes of the part. If I explicitly fetch the signal for the Position property changing, I want to be able to listen to that rather than needing to poll with a while loop. GetPropertyChangedSignal on Position doesn’t fire when Position is changed (it functions like regular .Changed where it only fires if manually set).

This is the code I used to test it out:

script.Parent.Changed:connect(function(property)
	if property == "Position" then
		print("generic changed")
	end
end)

script.Parent:GetPropertyChangedSignal("Position"):connect(function()
	print("GetPropertyChangedSignal changed")
end)

script.Parent.Position = Vector3.new(0, 50, 0)

EDIT:

Not suggesting .Changed should fire every frame the physics engine/position updates, asking that :GetPropertyChangedSignal would explicitly fire every frame the physics engine/position updates. If I explicitly call for the signal of a property, then I want to know explicitly when it changes.

This would go for any similar property that doesn’t seem to fire with .Changed as it changes via physics engine or whatever.

I assume this was initially done as an optimization, though it might be feasible to pull back if the developer can now pinpoint the property they want to listen to.

13 Likes

Thanks @TheGamer101

Tesco ™: Every Little Helps :stuck_out_tongue:

3 Likes

Might as well just poll using Heartbeat loop. I would listen for Position change, then hook up Heartbeat loop until position change is at some minimum change, then kill the Heartbeat connection.


Anyway, this is cool. Quick question: If you call GetPropertyChangedSignal("Name") three times, will it return 3 separate signal instances, or the same one?

2 Likes

This would be nice because you are explicitly asking for the property changes with GetPropertyChangedSignal but I don’t think it’s practical to implement unfortunately. I think there would be an overhead associated with checking if the developer has explicitly asked for changes for these properties that would make it too expensive to do for all moving parts every physics step.

The internal signal used will be the same but the object returned to Lua will be different (this is also what happens when you index an Instance to get a RBXScriptSignal). Comparison will work as expected because the comparison checks the contents of the RBXScriptSignal rather than if the actual object is the same.

Example:

print(game.Workspace.Baseplate:GetPropertyChangedSignal("Name") == game.Workspace.Baseplate:GetPropertyChangedSignal("Name"))
--> True
5 Likes

A event that fires when a part falls asleep or wakes up would be more practical. Polling solves the rest.

11 Likes

Yeah, that was the primary reason why I opted for the signal method to fire when these busy properties change.

It does seem in hindsight now more reasonable to have an event fire on sleeping, this would allow a simulation of the changed event for these sorts of busy properties (ie connecting/disconnecting on wake/sleep; I believe Position, Rotation, and CFrame are all busy properties that do wake-up the part/keep it awake regardless).

:thumbsup:

2 Likes

Hmmmmm me likey!

2 Likes

Interesting, thanks for the response!

1 Like

Could you allow us to connect to locked properties as some locked properties have functions to get their value ( PGS, loadstring via pcall, etc ). .Changed allows this so I’m not sure why this shouldn’t.

2 Likes

I think this can be changed, do you have a specific use case in mind where this would be needed?

2 Likes

In play solo, things like loadstringenabled can be changed which I’d like to track for my admin that allows a loadstring command when it’s enabled. Another use I can think of is needing to change how certain things operate depending on whether or not PGS is enabled, and as it can be set in play solo would be useful to be able to track when it changes as its value can be gotten.

1 Like

You can’t change PGS while the game is running, so there’s no point for that.

1 Like

It was just examples off the top of my head. I don’t use the PGS one personally, although I assumed it could be changed in playsolo?

EDIT: Seems it can be changed but doesn’t affect anything.

1 Like

Likely talking about plugins, perhaps.

1 Like

I wasn’t, but that’s a valid point too. Plugins may want to do certain things based on PGS / LoadstringEnabled.

1 Like

Are there any circumstances when you should prefer the instance.Changed signal over using instance:GetPropertyChangedSignal method?

Is there a plan to deprecate Changed entirely in favor of this method?

Would you consider passing the old and new value as parameters to the event handler?

1 Like

http://devforum.roblox.com/t/what-is-this-new-api/35519/5

4 Likes

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.