Skip to content

Instantly share code, notes, and snippets.

@MaximumADHD
Last active December 20, 2023 22:39
Show Gist options
  • Save MaximumADHD/538f0ab2541ef98912a2694dd8d274e7 to your computer and use it in GitHub Desktop.
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
@CoolHackerGuy420
Copy link

Found this in FE gun kit. How can I disable this without breaking the gun?

@MaximumADHD
Copy link
Author

Just don't.

@Kan18
Copy link

Kan18 commented Feb 10, 2021

Does this code have any license?

@ReturnedTrue
Copy link

For those using Roblox-ts, I've made a port for it: https://www.npmjs.com/package/@rbxts/thread

@iG-Studios
Copy link

Highly useful bit of code, I use this in all modern projects of mine. I appreciate the resource!

@EpixScripts
Copy link

On line 74, it should say 'errorStack', not 'errorMessage'.

@MaximumADHD
Copy link
Author

MaximumADHD commented Jul 28, 2021

On line 74, it should say 'errorStack', not 'errorMessage'.

whoops, fixed!

@TygoArrived
Copy link

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

@MaximumADHD
Copy link
Author

Hopefully yeah, I'm glad to see a first party solution to the problems that necessitated this module.

@TygoArrived
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment