V15.1.0 #26

Merged
rayaman merged 18 commits from V15.1.0 into master 2021-11-30 21:28:18 -05:00
3 changed files with 215 additions and 85 deletions
Showing only changes of commit 804a117ed0 - Show all commits

View File

@ -3,6 +3,62 @@ Table of contents
--- ---
[Update 15.0.0 - The art of faking it](#update-1500---the-art-of-faking-it)</br>[Update 14.2.0 - Bloatware Removed](#update-1420---bloatware-removed)</br>[Update 14.1.0 - A whole new world of possibilities](#update-1410---a-whole-new-world-of-possibilities)</br>[Update 14.0.0 - Consistency, Additions and Stability](#update-1400---consistency-additions-and-stability)</br>[Update 13.1.0 - Bug fixes and features added](#update-1310---bug-fixes-and-features-added)</br>[Update 13.0.0 - Added some documentation, and some new features too check it out!](#update-1300---added-some-documentation-and-some-new-features-too-check-it-out)</br>[Update 12.2.2 - Time for some more bug fixes!](#update-1222---time-for-some-more-bug-fixes)</br>[Update 12.2.1 - Time for some bug fixes!](#update-1221---time-for-some-bug-fixes)</br>[Update 12.2.0 - The chains of binding](#update-1220---the-chains-of-binding)</br>[Update 12.1.0 - Threads just can't hold on anymore](#update-1210---threads-just-cant-hold-on-anymore)</br>[Update: 12.0.0 - Big update (Lots of additions some changes)](#update-1200---big-update-lots-of-additions-some-changes)</br>[Update: 1.11.1 - Small Clarification on Love](#update-1111---small-clarification-on-love)</br>[Update: 1.11.0](#update-1110)</br>[Update: 1.10.0](#update-1100)</br>[Update: 1.9.2](#update-192)</br>[Update: 1.9.1 - Threads can now argue](#update-191---threads-can-now-argue)</br>[Update: 1.9.0](#update-190)</br>[Update: 1.8.7](#update-187)</br>[Update: 1.8.6](#update-186)</br>[Update: 1.8.5](#update-185)</br>[Update: 1.8.4](#update-184)</br>[Update: 1.8.3 - Mainloop recieves some needed overhauling](#update-183---mainloop-recieves-some-needed-overhauling)</br>[Update: 1.8.2](#update-182)</br>[Update: 1.8.1](#update-181)</br>[Update: 1.7.6](#update-176)</br>[Update: 1.7.5](#update-175)</br>[Update: 1.7.4](#update-174)</br>[Update: 1.7.3](#update-173)</br>[Update: 1.7.2](#update-172)</br>[Update: 1.7.1 - Bug Fixes Only](#update-171---bug-fixes-only)</br>[Update: 1.7.0 - Threading the systems](#update-170---threading-the-systems)</br>[Update: 1.6.0](#update-160)</br>[Update: 1.5.0](#update-150)</br>[Update: 1.4.1 (4/10/2017) - First Public release of the library](#update-141-4102017---first-public-release-of-the-library)</br>[Update: 1.4.0 (3/20/2017)](#update-140-3202017)</br>[Update: 1.3.0 (1/29/2017)](#update-130-1292017)</br>[Update: 1.2.0 (12.31.2016)](#update-120-12312016)</br>[Update: 1.1.0](#update-110)</br>[Update: 1.0.0](#update-100)</br>[Update: 0.6.3](#update-063)</br>[Update: 0.6.2](#update-062)</br>[Update: 0.6.1-6](#update-061-6)</br>[Update: 0.5.1-6](#update-051-6)</br>[Update: 0.4.1](#update-041)</br>[Update: 0.3.0 - The update that started it all](#update-030---the-update-that-started-it-all)</br>[Update: EventManager 2.0.0](#update-eventmanager-200)</br>[Update: EventManager 1.2.0](#update-eventmanager-120)</br>[Update: EventManager 1.1.0](#update-eventmanager-110)</br>[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)</br>[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different) [Update 15.0.0 - The art of faking it](#update-1500---the-art-of-faking-it)</br>[Update 14.2.0 - Bloatware Removed](#update-1420---bloatware-removed)</br>[Update 14.1.0 - A whole new world of possibilities](#update-1410---a-whole-new-world-of-possibilities)</br>[Update 14.0.0 - Consistency, Additions and Stability](#update-1400---consistency-additions-and-stability)</br>[Update 13.1.0 - Bug fixes and features added](#update-1310---bug-fixes-and-features-added)</br>[Update 13.0.0 - Added some documentation, and some new features too check it out!](#update-1300---added-some-documentation-and-some-new-features-too-check-it-out)</br>[Update 12.2.2 - Time for some more bug fixes!](#update-1222---time-for-some-more-bug-fixes)</br>[Update 12.2.1 - Time for some bug fixes!](#update-1221---time-for-some-bug-fixes)</br>[Update 12.2.0 - The chains of binding](#update-1220---the-chains-of-binding)</br>[Update 12.1.0 - Threads just can't hold on anymore](#update-1210---threads-just-cant-hold-on-anymore)</br>[Update: 12.0.0 - Big update (Lots of additions some changes)](#update-1200---big-update-lots-of-additions-some-changes)</br>[Update: 1.11.1 - Small Clarification on Love](#update-1111---small-clarification-on-love)</br>[Update: 1.11.0](#update-1110)</br>[Update: 1.10.0](#update-1100)</br>[Update: 1.9.2](#update-192)</br>[Update: 1.9.1 - Threads can now argue](#update-191---threads-can-now-argue)</br>[Update: 1.9.0](#update-190)</br>[Update: 1.8.7](#update-187)</br>[Update: 1.8.6](#update-186)</br>[Update: 1.8.5](#update-185)</br>[Update: 1.8.4](#update-184)</br>[Update: 1.8.3 - Mainloop recieves some needed overhauling](#update-183---mainloop-recieves-some-needed-overhauling)</br>[Update: 1.8.2](#update-182)</br>[Update: 1.8.1](#update-181)</br>[Update: 1.7.6](#update-176)</br>[Update: 1.7.5](#update-175)</br>[Update: 1.7.4](#update-174)</br>[Update: 1.7.3](#update-173)</br>[Update: 1.7.2](#update-172)</br>[Update: 1.7.1 - Bug Fixes Only](#update-171---bug-fixes-only)</br>[Update: 1.7.0 - Threading the systems](#update-170---threading-the-systems)</br>[Update: 1.6.0](#update-160)</br>[Update: 1.5.0](#update-150)</br>[Update: 1.4.1 (4/10/2017) - First Public release of the library](#update-141-4102017---first-public-release-of-the-library)</br>[Update: 1.4.0 (3/20/2017)](#update-140-3202017)</br>[Update: 1.3.0 (1/29/2017)](#update-130-1292017)</br>[Update: 1.2.0 (12.31.2016)](#update-120-12312016)</br>[Update: 1.1.0](#update-110)</br>[Update: 1.0.0](#update-100)</br>[Update: 0.6.3](#update-063)</br>[Update: 0.6.2](#update-062)</br>[Update: 0.6.1-6](#update-061-6)</br>[Update: 0.5.1-6](#update-051-6)</br>[Update: 0.4.1](#update-041)</br>[Update: 0.3.0 - The update that started it all](#update-030---the-update-that-started-it-all)</br>[Update: EventManager 2.0.0](#update-eventmanager-200)</br>[Update: EventManager 1.2.0](#update-eventmanager-120)</br>[Update: EventManager 1.1.0](#update-eventmanager-110)</br>[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)</br>[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different)
# Update 15.1.0 -
---
Full Update Showcase
```lua
package.path = "./?/init.lua;"..package.path
multi,thread = require("multi"):init()
test = thread:newFunction(function()
return 1,2,nil,3,4,5,6,7,8,9
end,true)
print(test())
multi:newThread("testing",function()
print("#Test = ",test())
print(thread.hold(function()
print("Hello!")
return false
end,{
interval = 2,
cycles = 3
})) -- End result, 3 attempts within 6 seconds. If still false then timeout
print("held")
end).OnError(function(...)
print(...)
end)
```
Added:
---
Changed:
---
- thread.hold(n,opt) [Ref. Issue](https://github.com/rayaman/multi/issues/24)
- Added option table to thread.hold
| Option | Description |
---|---
| cycles | Number of cycles before timing out |
| sleep | Number of seconds before timing out |
| interval | Time between each poll |
**Note:** cycles and sleep cannot both be used at the same time. Cycles take priority if both are present!
Removed:
---
Fixed:
---
- Threaded functions not returning multiple values [Ref. Issue](https://github.com/rayaman/multi/issues/21)
ToDo
---
# Update 15.0.0 - The art of faking it # Update 15.0.0 - The art of faking it
Full Update Showcase Full Update Showcase
--- ---

View File

@ -911,7 +911,7 @@ local threads = thread.__threads
local Gref = _G local Gref = _G
multi.GlobalVariables={} multi.GlobalVariables={}
local dFunc = function() return true end local dFunc = function() return true end
local dRef = {nil,nil,nil} local dRef = {nil,nil,nil,nil,nil}
thread.requests = {} thread.requests = {}
function thread.request(t,cmd,...) function thread.request(t,cmd,...)
thread.requests[t.thread] = {cmd,{...}} thread.requests[t.thread] = {cmd,{...}}
@ -941,11 +941,40 @@ function thread.sleep(n)
dRef[2] = n or 0 dRef[2] = n or 0
return coroutine.yield(dRef) return coroutine.yield(dRef)
end end
function thread.hold(n) -- function thread.hold(n)
-- thread._Requests()
-- dRef[1] = "_hold_"
-- dRef[2] = n or dFunc
-- return coroutine.yield(dRef)
-- end
function thread.hold(n,opt)
thread._Requests() thread._Requests()
dRef[1] = "_hold_" if opt and type(opt)=="table" then
dRef[2] = n or dFunc if opt.interval then
return coroutine.yield(dRef) dRef[4] = opt.interval
end
if opt.cycles then
dRef[1] = "_holdW_"
dRef[2] = opt.cycles or 1
dRef[3] = n or dFunc
return coroutine.yield(dRef)
elseif opt.sleep then
dRef[1] = "_holdF_"
dRef[2] = opt.sleep
dRef[3] = n or dFunc
return coroutine.yield(dRef)
end
end
if type(n) == "number" then
thread.getRunningThread().lastSleep = clock()
dRef[1] = "_sleep_"
dRef[2] = n or 0
return coroutine.yield(dRef)
else
dRef[1] = "_hold_"
dRef[2] = n or dFunc
return coroutine.yield(dRef)
end
end end
function thread.holdFor(sec,n) function thread.holdFor(sec,n)
thread._Requests() thread._Requests()
@ -1041,13 +1070,13 @@ function multi.holdFor(n,func)
end) end)
end end
local function cleanReturns(...) local function cleanReturns(...)
local n = select("#", ...)
local returns = {...} local returns = {...}
local rets = {} local rets = {}
local ind = 0 local ind = 0
for i=n,1,-1 do for i=#returns,1,-1 do
if returns[i] then if returns[i] then
ind=i ind = i
break
end end
end end
return unpack(returns,1,ind) return unpack(returns,1,ind)
@ -1061,7 +1090,7 @@ function thread:newFunction(func,holdme)
if err then if err then
return multi.NIL, err return multi.NIL, err
elseif rets then elseif rets then
return cleanReturns((rets[1] or multi.NIL),rets[2],rets[3],rets[4],rets[5],rets[6],rets[7]) return cleanReturns((rets[1] or multi.NIL),rets[2],rets[3],rets[4],rets[5],rets[6],rets[7],rets[8],rets[9],rets[10],rets[11],rets[12],rets[13],rets[14],rets[15],rets[16])
end end
end) end)
else else
@ -1071,7 +1100,7 @@ function thread:newFunction(func,holdme)
if err then if err then
return nil,err return nil,err
end end
return cleanReturns(rets[1],rets[2],rets[3],rets[4],rets[5],rets[6],rets[7]) return cleanReturns(rets[1],rets[2],rets[3],rets[4],rets[5],rets[6],rets[7],rets[8],rets[9],rets[10],rets[11],rets[12],rets[13],rets[14],rets[15],rets[16])
end end
end end
local t = multi:newThread("TempThread",func,...) local t = multi:newThread("TempThread",func,...)
@ -1084,7 +1113,7 @@ function thread:newFunction(func,holdme)
isTFunc = true, isTFunc = true,
wait = wait, wait = wait,
connect = function(f) connect = function(f)
t.OnDeath(function(self,status,...) f(cleanReturns(...)) end) t.OnDeath(function(self,status,...) f(...) end)
t.OnError(function(self,err) f(err) end) t.OnError(function(self,err) f(err) end)
end end
} }
@ -1206,8 +1235,8 @@ function multi.initThreads(justThreads)
self.skip=tonumber(n) or 24 self.skip=tonumber(n) or 24
end end
multi.scheduler.skip=0 multi.scheduler.skip=0
local t0,t1,t2,t3,t4,t5,t6 local t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15
local r1,r2,r3,r4,r5,r6 local r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16
local ret,_ local ret,_
local function CheckRets(i) local function CheckRets(i)
if threads[i] and not(threads[i].isError) then if threads[i] and not(threads[i].isError) then
@ -1216,7 +1245,7 @@ function multi.initThreads(justThreads)
threads[i].TempRets[1] = ret threads[i].TempRets[1] = ret
return return
end end
if ret or r1 or r2 or r3 or r4 or r5 or r6 then if ret or r1 or r2 or r3 or r4 or r5 or r6 or r7 or r8 or r9 or r10 or r11 or r12 or r13 or r14 or r15 or r16 then
threads[i].TempRets[1] = ret threads[i].TempRets[1] = ret
threads[i].TempRets[2] = r1 threads[i].TempRets[2] = r1
threads[i].TempRets[3] = r2 threads[i].TempRets[3] = r2
@ -1224,6 +1253,16 @@ function multi.initThreads(justThreads)
threads[i].TempRets[5] = r4 threads[i].TempRets[5] = r4
threads[i].TempRets[6] = r5 threads[i].TempRets[6] = r5
threads[i].TempRets[7] = r6 threads[i].TempRets[7] = r6
threads[i].TempRets[8] = r7
threads[i].TempRets[9] = r8
threads[i].TempRets[10] = r9
threads[i].TempRets[11] = r10
threads[i].TempRets[12] = r11
threads[i].TempRets[13] = r12
threads[i].TempRets[14] = r13
threads[i].TempRets[15] = r14
threads[i].TempRets[16] = r15
threads[i].TempRets[17] = r16
end end
end end
end end
@ -1241,7 +1280,7 @@ function multi.initThreads(justThreads)
local function helper(i) local function helper(i)
if type(ret)=="table" then if type(ret)=="table" then
if ret[1]=="_kill_" then if ret[1]=="_kill_" then
threads[i].OnDeath:Fire(threads[i],"killed",ret,r1,r2,r3,r4,r5,r6) threads[i].OnDeath:Fire(threads[i],"killed",ret,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16)
multi.setType(threads[i],multi.DestroyedObj) multi.setType(threads[i],multi.DestroyedObj)
table.remove(threads,i) table.remove(threads,i)
ret = nil ret = nil
@ -1262,6 +1301,8 @@ function multi.initThreads(justThreads)
threads[i].func = ret[2] threads[i].func = ret[2]
threads[i].task = "hold" threads[i].task = "hold"
threads[i].__ready = false threads[i].__ready = false
threads[i].interval = ret[4] or 0
threads[i].intervalR = clock()
ret = nil ret = nil
elseif ret[1]=="_holdF_" then elseif ret[1]=="_holdF_" then
holdconn(3) holdconn(3)
@ -1270,6 +1311,8 @@ function multi.initThreads(justThreads)
threads[i].task = "holdF" threads[i].task = "holdF"
threads[i].time = clock() threads[i].time = clock()
threads[i].__ready = false threads[i].__ready = false
threads[i].interval = ret[4] or 0
threads[i].intervalR = clock()
ret = nil ret = nil
elseif ret[1]=="_holdW_" then elseif ret[1]=="_holdW_" then
holdconn(3) holdconn(3)
@ -1279,6 +1322,8 @@ function multi.initThreads(justThreads)
threads[i].task = "holdW" threads[i].task = "holdW"
threads[i].time = clock() threads[i].time = clock()
threads[i].__ready = false threads[i].__ready = false
threads[i].interval = ret[4] or 0
threads[i].intervalR = clock()
ret = nil ret = nil
end end
end end
@ -1295,7 +1340,7 @@ function multi.initThreads(justThreads)
end end
if threads[i] and not threads[i].__started then if threads[i] and not threads[i].__started then
if coroutine.running() ~= threads[i].thread then if coroutine.running() ~= threads[i].thread then
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,unpack(threads[i].startArgs)) _,ret,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16=coroutine.resume(threads[i].thread,unpack(threads[i].startArgs))
end end
threads[i].__started = true threads[i].__started = true
helper(i) helper(i)
@ -1306,7 +1351,7 @@ function multi.initThreads(justThreads)
end end
if threads[i] and coroutine.status(threads[i].thread)=="dead" then if threads[i] and coroutine.status(threads[i].thread)=="dead" then
local t = threads[i].TempRets or {} local t = threads[i].TempRets or {}
threads[i].OnDeath:Fire(threads[i],"ended",t[1],t[2],t[3],t[4],t[5],t[6],t[7]) threads[i].OnDeath:Fire(threads[i],"ended",t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16])
multi.setType(threads[i],multi.DestroyedObj) multi.setType(threads[i],multi.DestroyedObj)
table.remove(threads,i) table.remove(threads,i)
elseif threads[i] and threads[i].task == "skip" then elseif threads[i] and threads[i].task == "skip" then
@ -1316,13 +1361,16 @@ function multi.initThreads(justThreads)
threads[i].__ready = true threads[i].__ready = true
end end
elseif threads[i] and threads[i].task == "hold" then elseif threads[i] and threads[i].task == "hold" then
t0,t1,t2,t3,t4,t5,t6 = threads[i].func() if clock() - threads[i].intervalR>=threads[i].interval then
if t0 then t0,t1,t2,t3,t4,t5,t6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16 = threads[i].func()
if t0==multi.NIL then if t0 then
t0 = nil if t0==multi.NIL then
t0 = nil
end
threads[i].task = ""
threads[i].__ready = true
end end
threads[i].task = "" threads[i].intervalR = clock()
threads[i].__ready = true
end end
elseif threads[i] and threads[i].task == "sleep" then elseif threads[i] and threads[i].task == "sleep" then
if clock() - threads[i].time>=threads[i].sec then if clock() - threads[i].time>=threads[i].sec then
@ -1330,33 +1378,40 @@ function multi.initThreads(justThreads)
threads[i].__ready = true threads[i].__ready = true
end end
elseif threads[i] and threads[i].task == "holdF" then elseif threads[i] and threads[i].task == "holdF" then
t0,t1,t2,t3,t4,t5,t6 = threads[i].func() if clock() - threads[i].intervalR>=threads[i].interval then
if t0 then t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15 = threads[i].func()
threads[i].task = "" if t0 then
threads[i].__ready = true threads[i].task = ""
elseif clock() - threads[i].time>=threads[i].sec then threads[i].__ready = true
threads[i].task = "" elseif clock() - threads[i].time>=threads[i].sec then
threads[i].__ready = true threads[i].task = ""
t0 = nil threads[i].__ready = true
t1 = "TIMEOUT" t0 = nil
t1 = "TIMEOUT"
end
threads[i].intervalR = clock()
end end
elseif threads[i] and threads[i].task == "holdW" then elseif threads[i] and threads[i].task == "holdW" then
threads[i].pos = threads[i].pos + 1 if clock() - threads[i].intervalR>=threads[i].interval then
t0,t1,t2,t3,t4,t5,t6 = threads[i].func() threads[i].pos = threads[i].pos + 1
if t0 then print(threads[i].pos,threads[i].count)
threads[i].task = "" t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15 = threads[i].func()
threads[i].__ready = true if t0 then
elseif threads[i].count==threads[i].pos then threads[i].task = ""
threads[i].task = "" threads[i].__ready = true
threads[i].__ready = true elseif threads[i].count==threads[i].pos then
t0 = nil threads[i].task = ""
t1 = "TIMEOUT" threads[i].__ready = true
t0 = nil
t1 = "TIMEOUT"
end
threads[i].intervalR = clock()
end end
end end
if threads[i] and threads[i].__ready then if threads[i] and threads[i].__ready then
threads[i].__ready = false threads[i].__ready = false
if coroutine.running() ~= threads[i].thread then if coroutine.running() ~= threads[i].thread then
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6) _,ret,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15)
CheckRets(i) CheckRets(i)
end end
end end

103
test.lua
View File

@ -2,50 +2,69 @@ package.path = "./?/init.lua;"..package.path
multi,thread = require("multi"):init() multi,thread = require("multi"):init()
--GLOBAL,THREAD = require("multi.integration.threading"):init() -- Auto detects your enviroment and uses what's available --GLOBAL,THREAD = require("multi.integration.threading"):init() -- Auto detects your enviroment and uses what's available
local sandcount = 0
function multi:newProcessor(name)
local c = {}
setmetatable(c,{__index = self})
local multi,thread = require("multi"):init() -- We need to capture the t in thread
local name = name or "Processor_"..sandcount
sandcount = sandcount + 1
c.Mainloop = {}
c.Type = "process"
c.Active = false
c.OnError = multi:newConnection()
c.process = self:newThread(name,function()
while true do
thread.hold(function()
return sandbox.Active
end)
c:uManager()
end
end).OnError(c.OnError)
function c.Start()
c.Active = true
end
function c.Stop()
c.Active = false
end
return c
end
sandbox = multi:newProcessor() test = thread:newFunction(function()
sandbox:newTLoop(function() return 1,2,nil,3,4,5,6,7,8,9
print("testing...") end,true)
end,1) print(test())
multi:newThread("testing",function()
test2 = multi:newTLoop(function() print("#Test = ",test())
print("testing2...") print(thread.hold(function()
end,1) print("Hello!")
return false
sandbox:newThread("Test Thread",function() end,{
while true do interval = 2,
thread.sleep(1) cycles = 3
print("Thread Test...") })) -- End result, 3 attempts within 6 seconds. If still false then timeout
end print("held")
end).OnError(function(...)
print(...)
end) end)
sandbox.Start() -- local sandcount = 0
-- function multi:newProcessor(name)
-- local c = {}
-- setmetatable(c,{__index = self})
-- local multi,thread = require("multi"):init() -- We need to capture the t in thread
-- local name = name or "Processor_"..sandcount
-- sandcount = sandcount + 1
-- c.Mainloop = {}
-- c.Type = "process"
-- c.Active = false
-- c.OnError = multi:newConnection()
-- c.process = self:newThread(name,function()
-- while true do
-- thread.hold(function()
-- return sandbox.Active
-- end)
-- c:uManager()
-- end
-- end).OnError(c.OnError)
-- function c.Start()
-- c.Active = true
-- end
-- function c.Stop()
-- c.Active = false
-- end
-- return c
-- end
-- sandbox = multi:newProcessor()
-- sandbox:newTLoop(function()
-- print("testing...")
-- end,1)
-- test2 = multi:newTLoop(function()
-- print("testing2...")
-- end,1)
-- sandbox:newThread("Test Thread",function()
-- while true do
-- thread.sleep(1)
-- print("Thread Test...")
-- end
-- end)
-- sandbox.Start()
multi:mainloop() multi:mainloop()