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) end) 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 end)
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 end) prop:Set(Vector(5,3,7)) print(prop) -- This will print "50 30 70" cb:Remove() -- Remove the modifier end)
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) prop2:Link(prop) print(prop2) -- This will print "3.0" prop2:AddCallback(function(oldVal,newVal) print("Value of prop2 has changed to " .. newVal) end) 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 prop2:Set(5.0) print(prop2) -- This will print 12 prop:Set(3) 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:Link(prop) posProp:AddModifier(function(v) return v +Vector(10,12,5) end) posProp:SetLocked(true,false) 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.