Introducting… properties module! Detect changes to values without using Value objects!
Big thanks to @Scriptos for helping me out with this. He originally modified Aero Game Framework to do this very thing, but in a style that fits aero. So now, I am creating this module so everyone else can use it.
Every once and a while, I’ll see people asking how to detect changes to a value. It’s not easy to do, and I’ve seen some people even recommending while loops to do this. You could use an Object value, or you could use PropertyModule!
Example usage:
local rs = game:GetService("ReplicatedStorage");
local PropertiesModule = require(rs:WaitForChild("PropertyModule"));
local Values = PropertiesModule.new();
Values.Enabled = false; -- Will not fire, as it is set before the event is created.
Values:GetPropertyChangedEvent("Enabled"):Connect(function(New, Old)
print(Values.Enabled, Old);
end)
Values.Enabled = true; -- Will fire the event!
Values:Set("Enabled", false) -- Set Values.Enabled to false without firing the event.
Values:End(); -- No need for events.
Timer Example
local rs = game:GetService("ReplicatedStorage");
local PropertiesModule = require(rs:WaitForChild("PropertyModule"));
local Values = PropertiesModule.new();
Values.Timer = 0;
Values:GetPropertyChangedEvent("Timer"):Connect(function(New, Old)
if Values.Timer > 0 then
wait(1);
Values.Timer = Values.Timer - 1;
print(Values.Timer);
elseif Values.Timer == 0 then
print("All done!");
end
end)
Values.Timer = 5; -- All you need to do to start the timer!
(no, Enabled has nothing to do with the Module itself. Enabled is just a property, it can be called anything)
You are able to call GetPropertyChangedEvent before the variable is even defined! So the very first time you set the variable, it will fire the event.
This does not use Value objects. It is done with metatables.
Documentation
Summary
ModuleScript
PropertiesModule.new()
- returns a PropertiesModule class
Class
Method Set(PropertyName, NewValue)
- Set a property without firing the associated event.
Method End()
- All events are disconnected. You can still access and set properties.
Method GetPropertyChangedEvent(PropertyName)
- Returns an event that passes the new, and old value.
Get it here!
https://www.roblox.com/library/5024176989/PropertyModule
Module compatible with Aero Game Framework
(once you have these modules setup, everything you need is already a member of self! self:RegisterProperty, self:GetPropertyChangedEvent, and you set registered variables though self too! self.SomeVariable = SomeValue. Pretty nifty, I’d say…)
Property Shared Module
-- Properties
-- WorldPosition
-- May 13, 2020
--[[
RegisterProperty(Name)
GetPropertyChangedEvent(Name):Connect(function(New, Old))
--]]
local Properties = {}
function Properties:Init()
local Event = self.Shared.Event;
local Aero = getmetatable(self).__index;
function Aero:RegisterProperty(PropertyName)
if not self.Properties then
self.Properties = {};
self.PropertyEvents = {};
end
self.Properties[PropertyName] = false;
self.PropertyEvents[PropertyName] = Event.new();
return self.PropertyEvents[PropertyName];
end
function Aero:GetPropertyChangedEvent(PropertyName)
local evnt = nil;
if not self.Properties or self.PropertyEvents[PropertyName] == nil then
evnt = self:RegisterProperty(PropertyName);
end
if evnt == nil then
evnt = self.PropertyEvents[PropertyName];
end
return evnt;
end
getmetatable(self).__index = function(self, index)
if rawget(self, "Properties") and rawget(self.Properties, index) ~= nil then
return rawget(self.Properties, index);
else
if rawget(Aero, index) ~= nil then
return Aero[index];
end
end
end
getmetatable(self).__newindex = function(self, key, value)
if rawget(self, "Properties") and rawget(self.Properties, key) ~= nil then
local old = self.Properties[key];
rawset(self.Properties, key, value)
self.PropertyEvents[key]:Fire(value, old);
else
rawset(self, key, value);
end
end
end
return Properties
PropertyController
-- Property Controller
-- WorldPosition
-- May 14, 2020
--[[
--]]
local Properties;
local PropertyController = {}
PropertyController.__aeroOrder = 1;
function PropertyController:Init()
Properties = self.Shared.Properties;
end
return PropertyController
PropertyService
-- Property Service
-- WorldPosition
-- May 14, 2020
--[[
--]]
local Properties;
local PropertyService = {Client = {}}
PropertyService.__aeroOrder = 1;
function PropertyService:Init()
Properties = self.Shared.Properties;
end
return PropertyService