Reflect Instance Properties

I’m trying to create a palette system in my game so I can have bodies of terrain water that are different colors as my player moves through zones.

I want to cache the default Terrain settings and then apply a diff to them like so:

game.ReplicatedStorage.Sig.ChangePlayerTerrainSettings.OnClientEvent:Connect(function(settings)
	
	-- First apply defaults
	game.Workspace.Terrain.WaterColor = Color3.fromRGB(23,166,182)
	game.Workspace.Terrain.WaterReflectance = .5
	game.Workspace.Terrain.WaterTransparency = .9
	game.Workspace.Terrain.WaterWaveSize = .15
	game.Workspace.Terrain.WaterWaveSpeed = 10
	-- todo material colors?
	
	
	-- Then modify
	if (settings["WaterColor"] ~= nil) then
		game.Workspace.Terrain.WaterColor = settings["WaterColor"]
	end
	
	if (settings["WaterReflectance"] ~= nil) then
		game.Workspace.Terrain.WaterReflectance = settings["WaterReflectance"]
	end
	
	if (settings["WaterTransparency"] ~= nil) then
		game.Workspace.Terrain.WaterTransparency = settings["WaterTransparency"]
	end
	
	if (settings["WaterWaveSize"] ~= nil) then
		game.Workspace.Terrain.WaterWaveSize = settings["WaterWaveSize"]
	end
	
	if (settings["WaterWaveSpeed"] ~= nil) then
		game.Workspace.Terrain.WaterWaveSpeed = settings["WaterWaveSpeed"]
	end
	
	
end)

But I would love to not have to spell out every single property I want to override. I was surprised that there was no way to simply iterate over all the properties an Instance has.

I searched around here and found other devs doing some crazy stuff to hack around this limitation.

There should be an API like the one that was recently added for Attributes.

21 Likes

So if I’m understanding this correctly

for i,property in pairs(part:GetProperties()) do
      if settings[property.Name] then
            property.Value = settings[property.Name]
      end
end
1 Like

Exactly. Much better than my word wall.

2 Likes
1 Like

I feel like when I use other scripting languages with bad OOP support, like Javascript, I use reflection often.

So I find the incredulity in that thread incredulous.

2 Likes

One thing that will make the code slightly simpler (short of having a full reflection API) is that the . operator is really syntactic sugar for [string] operator:

t = {Transparency= 0.5} for k,v in pairs(t) do workspace.Part[k] = v end

so, as long as all keys in your table are valid property names, you can use a simple for loop to set every property listed in the table on the given object (without needing to copy-paste lines for every possible property).

If you are willing to only give the users a specific subset of properties that you want to allow them to modify, this is sufficient (just make a table where the properties you want to make edit-able are “whitelisted” by being keys in the table). This might be a reasonable limitation anyway for your usecase (e.g. you may not want users to be able to set other properties of Terrain, like CanCollide, Name, etc.)

4 Likes