local module = {} local FF_COMPUTED_CONSTRUCTION_CALLBACK = false local FF_COMPUTED_REFS = {} local refValuesById = {} function module.ref(value: any) table.insert(refValuesById, { Value = value, OnSet = {} }) local id = #refValuesById local ref = setmetatable({ Id = id, get = function(self) if FF_COMPUTED_CONSTRUCTION_CALLBACK then table.insert(FF_COMPUTED_REFS, self.Id) end; return refValuesById[self.Id].Value; end, set = function(self, value: any) self.Value = value task.spawn(function() local callbacks = refValuesById[self.Id].OnSet for _, callback in callbacks do callback(value) end end) end, }, {}) return ref end local computedsById = {} function module.computed(computationCallback: () -> (any)) FF_COMPUTED_CONSTRUCTION_CALLBACK = true table.insert(computedsById, { Value = computationCallback(), Callack = computationCallback, Refs = FF_COMPUTED_REFS, OnChange = {} }) local notifyChange = function(refId, compId) return function() local computedData: { Value: any, Callack: () -> any, OnChange: { } } = computedsById[refId] local newComputedValue = computedData.Callack() computedsById[compId].Value = newComputedValue for _, callback in computedData.OnChange do callback(newComputedValue) end end end local refs = FF_COMPUTED_REFS if refs[1] then for _, ref in refs do table.insert(refValuesById[ref].OnSet, notifyChange(ref, #computedsById)) end end FF_COMPUTED_CONSTRUCTION_CALLBACK = false FF_COMPUTED_REFS = {} return setmetatable({ Value = computationCallback(), }, { Id = #computedsById, __index = function(self, key) if key:upper() == "VALUE" then return computedsById[#computedsById].Value else return rawget(self, key) end end}) end function module.listenEvent(computed: typeof(setmetatable({ Id = 1}, {})), callback: (newValue: any) -> ()) table.insert(computedsById[computed.Id].OnChange, callback) end local Computed = module.computed local Ref = module.ref local ListenTo = module.listenEvent local a = Ref(1) local b = Ref(2) local aAndB = Computed(function() return a:get() * b:get() end) print(aAndB.Value) -- 2 ListenTo(aAndB, print) a:set(2) -- aAndB = 4 b:set(3) -- aAndB = 6 return module