Advertisement
LoganDark

Minisched

Apr 17th, 2020 (edited)
435
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.67 KB | None | 0 0
  1. local class = require(script.Parent:WaitForChild('Class'))
  2.  
  3. local Minisched = class('Minisched') do
  4.     function Minisched:__Construct(bind)
  5.         self.schedule = {}
  6.        
  7.         if bind ~= false then
  8.             self:BindTo(game:GetService('RunService').Stepped)
  9.         end
  10.     end
  11.    
  12.     function Minisched:SortSchedule()
  13.         table.sort(self.schedule, function(a, b)
  14.             return a.at <= b.at
  15.         end)
  16.     end
  17.    
  18.     function Minisched:Schedule(coro, at, ...)
  19.         local task = {coro = coro, at = at, args = table.pack(...)}
  20.        
  21.         table.insert(self.schedule, task)
  22.         self:SortSchedule()
  23.        
  24.         return task
  25.     end
  26.    
  27.     function Minisched:Unschedule(task)
  28.         local i = table.find(self.schedule, task)
  29.         if i then table.remove(self.schedule, i) end
  30.        
  31.         return i ~= nil
  32.     end
  33.    
  34.     function Minisched:Resume(task, remove)
  35.         if remove then self:Unschedule(task) end
  36.        
  37.         local status = coroutine.status(task.coro)
  38.         if status ~= 'suspended' then
  39.             warn('Encountered a scheduled coroutine with status ' .. status)
  40.             return
  41.         end
  42.        
  43.         local parent = Minisched.Current
  44.         Minisched.Current = self
  45.         local results = table.pack(coroutine.resume(task.coro, table.unpack(task.args, 1, task.args.n)))
  46.         Minisched.Current = parent
  47.        
  48.         if not results[1] then
  49.             warn(results[2])
  50.             warn(debug.traceback(task.coro))
  51.         end
  52.        
  53.         return table.unpack(results, 1, results.n)
  54.     end
  55.    
  56.     function Minisched:GetOverdueTasks(t, remove)
  57.         local t = t or tick()
  58.         local overdue = {}
  59.        
  60.         for _, task in ipairs(self.schedule) do
  61.             if task.at > t then break end
  62.             table.insert(overdue, task)
  63.         end
  64.        
  65.         if remove then
  66.             for i = 1, #overdue do
  67.                 table.remove(self.schedule, 1)
  68.             end
  69.         end
  70.        
  71.         return overdue
  72.     end
  73.    
  74.     function Minisched:Dispatch()
  75.         local overdue = self:GetOverdueTasks(tick(), true)
  76.        
  77.         for _, task in ipairs(overdue) do
  78.             self:Resume(task)
  79.         end
  80.     end
  81.    
  82.     function Minisched:BindTo(event)
  83.         return event:Connect(function()
  84.             self:Dispatch()
  85.         end)
  86.     end
  87.    
  88.     function Minisched:New(...)
  89.         return Minisched(...)
  90.     end
  91.    
  92.     --------------------------------------------------------------------------------
  93.     -- Yields
  94.     --------------------------------------------------------------------------------
  95.    
  96.     local function ensureYieldable()
  97.         if not coroutine.isyieldable() then error('Cannot yield') end
  98.     end
  99.    
  100.     function Minisched:Wait(t, ...)
  101.         ensureYieldable()
  102.        
  103.         return coroutine.yield(self:Schedule(coroutine.running(), tick() + (t or 0), ...))
  104.     end
  105.    
  106.     local function eventSchedule(self, event)
  107.         local task = {coro = coroutine.running()}
  108.        
  109.         local conn
  110.         conn = event:Connect(function(...)
  111.             conn:Disconnect()
  112.             task.args = table.pack(...)
  113.             self:Resume(task)
  114.         end)
  115.        
  116.         return conn
  117.     end
  118.    
  119.     function Minisched:EventWait(event)
  120.         ensureYieldable()
  121.         eventSchedule(self, event)
  122.         return coroutine.yield()
  123.     end
  124.    
  125.     function Minisched:EventTimeout(event, t)
  126.         ensureYieldable()
  127.        
  128.         local running = coroutine.running()
  129.        
  130.         local symbol = newproxy()
  131.         local eventTask = eventSchedule(self, event)
  132.         local waitTask = self:Schedule(running, tick() + (t or 0), symbol)
  133.         local results = table.pack(coroutine.yield())
  134.        
  135.         if results[1] == symbol then
  136.             eventTask:Disconnect()
  137.             return false
  138.         end
  139.        
  140.         self:Unschedule(waitTask)
  141.        
  142.         return true, table.unpack(results, 1, results.n)
  143.     end
  144.    
  145.     function Minisched:Encapsulate(func, ...)
  146.         ensureYieldable()
  147.        
  148.         local task = {coro = coroutine.running()}
  149.         local err
  150.        
  151.         Minisched.Corospawn(function(...)
  152.             local results = table.pack(pcall(func, ...))
  153.             err = not results[1]
  154.             task.args = not err and results or table.pack(results[2])
  155.             self:Resume(task)
  156.         end, ...)
  157.        
  158.         local results = table.pack(coroutine.yield())
  159.        
  160.         if err then
  161.             error(results[1], 2)
  162.         end
  163.        
  164.         return results
  165.     end
  166.    
  167.     --------------------------------------------------------------------------------
  168.     -- Spawns
  169.     --------------------------------------------------------------------------------
  170.    
  171.     function Minisched.Corospawn(func, ...)
  172.         local coro = coroutine.create(func)
  173.         return coro, coroutine.resume(coro, ...)
  174.     end
  175.    
  176.     function Minisched.Quickspawn(func, ...)
  177.         if not Minisched.QuickspawnEvent then
  178.             Minisched.QuickspawnEvent = Instance.new('BindableEvent')
  179.             Minisched.QuickspawnEvent.Event:Connect(function(func, ...)
  180.                 func(...)
  181.             end)
  182.         end
  183.        
  184.         Minisched.QuickspawnEvent:Fire(func, ...)
  185.     end
  186.    
  187.     function Minisched:Queue(func, ...)
  188.         local coro = coroutine.create(func)
  189.         return coro, self:Schedule(coro, 0, ...)
  190.     end
  191.    
  192.     function Minisched:Delegate(func, ...)
  193.         local coro, queued = self:Queue(func, ...)
  194.         return coro, self:Resume(queued, true)
  195.     end
  196.    
  197.     function Minisched:Delay(func, t, ...)
  198.         local coro = coroutine.create(func)
  199.         return coro, self:Schedule(coro, tick() + (t or 0), ...)
  200.     end
  201.    
  202.     --------------------------------------------------------------------------------
  203.     -- Auto-targeting
  204.     --------------------------------------------------------------------------------
  205.    
  206.     Minisched.Current = nil
  207.    
  208.     local function getCurrentMinisched()
  209.         return Minisched.Current or error('Not running in Minisched')
  210.     end
  211.    
  212.     function Minisched.TWait(...)         getCurrentMinisched():Wait(...)         end
  213.     function Minisched.TEventWait(...)    getCurrentMinisched():EventWait(...)    end
  214.     function Minisched.TEventTimeout(...) getCurrentMinisched():EventTimeout(...) end
  215.     function Minisched.TEncapsulate(...)  getCurrentMinisched():Encapsulate(...)  end
  216.     function Minisched.TQueue(...)        getCurrentMinisched():Queue(...)        end
  217.     function Minisched.TDelegate(...)     getCurrentMinisched():Delegate(...)     end
  218.     function Minisched.TDelay(...)        getCurrentMinisched():Delay(...)        end
  219. end
  220.  
  221. return Minisched()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement