From Pragma
Jump to: navigation, search

Properties are essentially just variables of specific object types that can be listened to for changes. For example:

	local prop = util.IntProperty(5)
	local cb = prop:AddCallback(function(oldValue,newValue)
		print("Value has changed from " .. oldValue .. " to " .. newValue)
	prop = prop +5 -- This will call the callback specified above
	prop:Set(prop:Get() +3) -- This will also call the callback
	cb:Remove() -- Remove the callback
	prop = prop +3 -- Callback will not be called anymore

You can add as many callbacks to a property as you want. Additionally, you can also specify modifiers, that can be used to change the property's value before it's applied:

	local prop = util.VectorProperty(Vector(0,0,0))
	local cb = prop:AddModifier(function(val)
		return val *10
	print(prop) -- This will print "50 30 70"
	cb:Remove() -- Remove the modifier

If you don't return a value inside the modifier, the value will remain unchanged. Modifiers will be called in the order they were added to the property. Finally, you can link properties together or lock them to prevent them from being edited:

	local prop = util.FloatProperty(3.0)
	local prop2 = util.FloatProperty(7.0)
	print(prop2) -- This will print "3.0"

		print("Value of prop2 has changed to " .. newVal)
	prop:Set(12.0) -- This will also set prop2's value to 12 and invoke the callback above
	prop2:SetLocked(true,false) -- This will prevent the value from being changed, however if the second parameter is false, the value can still be changed through its link
	print(prop2) -- This will print 12
	print(prop2) -- This will print 3

Note that a component can only be linked to one other component, but a component can be linked to as many times as you want. This could be used, for instance, to control multiple entities at once:

	local prop = util.VectorProperty()
	for ent in ents.iterator(bit.bor(ents.ITERATOR_FILTER_DEFAULT,ents.ITERATOR_FILTER_BIT_HAS_TRANSFORM)) do
		local trComponent = ent:GetTransformComponent()
		local posProp = trComponent:GetPosProperty()
		posProp:AddModifier(function(v) return v +Vector(10,12,5) end)
	prop:Set(Vector(12,5,3)) -- Position of all entities will be set to the specified vector + the offset specified above

Only components that are compatible with each other can be linked. You can link a util.FloatProperty and a util.StringProperty, but you cannot link a util.EntityProperty and a util.ColorProperty.

The following property types are available: util.FloatProperty, util.IntProperty, util.BoolProperty, util.ColorProperty, util.VectorProperty, util.Vector3iProperty, util.Vector2Property, util.Vector2iProperty, util.Vector4Property, util.Vector4iProperty, util.QuaternionProperty, util.StringProperty, util.EntityProperty, util.Mat2Property, util.Mat2x3Property, util.Mat3x2Property, util.Mat3Property, util.Mat3x4Property, util.Mat4x3Property and util.Mat4Property

Take care when using operators on properties, as they are not commutative:

	local prop = util.FloatProperty(5)
	local v0 = prop +10
	-- v0 is now a float property with a value of 15
	local v1 = 10 +prop
	-- v1 is now a number(!) with a value of 25
	print(prop) -- This will print 15
	print(v0) -- This will print 15
	print(v1) -- This will print 25

Keep in mind: If the property is on the left side of the operation, you will modify the actual property, but if the property is on the right side, it will be converted to its underlying type and the property itself will not be changed. This is especially problematic with operations that aren't commutative to begin with. To avoid confusion, it's recommended to use the Get() and Set() methods instead:

	local prop = util.FloatProperty(5)
	prop:Set(prop:Get() +10)
	local v0 = prop:Get()
	local v1 = 10 +prop:Get()
	print(prop:Get()) -- This will print 15
	print(v0) -- This will print 15
	print(v1) -- This will print 25

Properties are powerful tools, but they're also much more expensive than regular variables, so use them sparingly.