-
-
Save MaximumADHD/538f0ab2541ef98912a2694dd8d274e7 to your computer and use it in GitHub Desktop.
-------------------------------------------------------------------------- | |
-- @ CloneTrooper1019, 2020-2021 | |
-- Thread.lua | |
-------------------------------------------------------------------------- | |
local Thread = {} | |
-------------------------------------------------------------------------- | |
-- Task Scheduler | |
-------------------------------------------------------------------------- | |
local RunService = game:GetService("RunService") | |
local front | |
-- use array indices for speed | |
-- and avoiding lua hash tables | |
local THREAD = 1 | |
local RESUME = 2 | |
local NEXT = 3 | |
local function pushThread(thread: thread, resume: number) | |
local node = | |
{ | |
[THREAD] = thread; | |
[RESUME] = resume; | |
} | |
if front then | |
if front[RESUME] >= resume then | |
node[NEXT] = front | |
front = node | |
else | |
local prev = front | |
while prev[NEXT] and prev[NEXT][RESUME] < resume do | |
prev = prev[NEXT] | |
end | |
node[NEXT] = prev[NEXT] | |
prev[NEXT] = node | |
end | |
else | |
front = node | |
end | |
end | |
local function popThreads() | |
local now = os.clock() | |
while front do | |
-- Resume if we're reasonably close enough. | |
if front[RESUME] - now < (1 / 120) then | |
local thread = front[THREAD] | |
front = front[NEXT] | |
coroutine.resume(thread, now) | |
else | |
break | |
end | |
end | |
end | |
RunService.Heartbeat:Connect(popThreads) | |
-------------------------------------------------------------------------- | |
-- Thread | |
-------------------------------------------------------------------------- | |
local errorStack = "ERROR: %s\nStack Begin\n%sStack End" | |
local function HandleError(err) | |
local trace = debug.traceback() | |
warn(errorStack:format(err, trace)) | |
end | |
function Thread:Wait(t: number?) | |
local t = tonumber(t) | |
if t then | |
local start = os.clock() | |
pushThread(coroutine.running(), start + t) | |
return coroutine.yield() - start | |
else | |
return RunService.Heartbeat:Wait() | |
end | |
end | |
function Thread:Spawn(func: any, ...) | |
local args = { ... } | |
local numArgs = select('#', ...) | |
local bindable = Instance.new("BindableEvent") | |
bindable.Event:Connect(function (stack) | |
xpcall(func, HandleError, stack()) | |
end) | |
bindable:Fire(function () | |
return unpack(args, 1, numArgs) | |
end) | |
end | |
function Thread:Delay(t: number, callback: any) | |
self:Spawn(function () | |
local delayTime, elapsed = self:Wait(t) | |
xpcall(callback, HandleError, delayTime, elapsed) | |
end) | |
end | |
-------------------------------------------------------------------------- | |
return Thread |
For those using Roblox-ts, I've made a port for it: https://www.npmjs.com/package/@rbxts/thread
Highly useful bit of code, I use this in all modern projects of mine. I appreciate the resource!
On line 74, it should say 'errorStack', not 'errorMessage'.
On line 74, it should say 'errorStack', not 'errorMessage'.
whoops, fixed!
task.wait() and some other stuff is released now, task.wait is very accurate and its 1/60, so this module probaly isnt needed for most people anymore
Hopefully yeah, I'm glad to see a first party solution to the problems that necessitated this module.
Hopefully yeah, I'm glad to see a first party solution to the problems that necessitated this module.
on 1 test i did with task.wait, it was 3ms off, wait() is also optimized a bit now, its nice to see this
Does this code have any license?