local threading = { _canSafelyClose = true, _endThread = false, _isRunning = false, _blocks = {}, _scheduledBlock = nil, _hasScheduledBlockRun = true, } local logger = require(script.Parent.Logger) local RunService = game:GetService("RunService") local function getScheduledBlock() local now = tick() if not threading._hasScheduledBlockRun and threading._scheduledBlock ~= nil and threading._scheduledBlock.deadline <= now then threading._hasScheduledBlockRun = true return threading._scheduledBlock else return nil end end local function run() task.spawn(function() logger:d("Starting GA thread") while not threading._endThread do threading._canSafelyClose = false if #threading._blocks ~= 0 then for _, b in pairs(threading._blocks) do local s, e = pcall(b.block) if not s then logger:e(e) end end threading._blocks = {} end local timedBlock = getScheduledBlock() if timedBlock ~= nil then local s, e = pcall(timedBlock.block) if not s then logger:e(e) end end threading._canSafelyClose = true task.wait(1) end logger:d("GA thread stopped") end) --Safely Close game:BindToClose(function() -- waiting bug fix to work inside studio if RunService:IsStudio() then return end --Give game.Players.PlayerRemoving time to to its thang task.wait(1) --Delay if not threading._canSafelyClose then repeat task.wait() until threading._canSafelyClose end task.wait(3) end) end function threading:scheduleTimer(interval, callback) if self._endThread then return end if not self._isRunning then self._isRunning = true run() end local timedBlock = { block = callback, deadline = tick() + interval, } if self._hasScheduledBlockRun then self._scheduledBlock = timedBlock self._hasScheduledBlockRun = false end end function threading:performTaskOnGAThread(callback) if self._endThread then return end if not self._isRunning then self._isRunning = true run() end local timedBlock = { block = callback, } self._blocks[#self._blocks + 1] = timedBlock end function threading:stopThread() self._endThread = true end return threading