diff --git a/README.html b/README.html index b305f3d..0b2f88b 100644 --- a/README.html +++ b/README.html @@ -9,7 +9,7 @@
-Note: The changes section has information on how to use the new features as they come out. Why put the infomation twice on the readme? Also I added a Testing Branch. That Branch will have the latest updates, but those updates may be unstable. I like to keep the master as bug free as possible
In Changes you’ll find documentation for(In Order):
Note: The changes section has information on how to use the new features as they come out. Why put the infomation twice on the readme? Also I added a Testing Branch. That Branch will have the latest updates, but those updates may be unstable. I like to keep the master as bug free as possible
In Changes you’ll find documentation for(In Order):
My multitasking library for lua
To install copy the multi folder into your enviroment and you are good to go
It is a pure lua binding if you ingore the integrations and the love2d compat
If you find any bugs or have any issues please let me know :)
If you don’t see a table of contents try using the ReadMe.html file. It is eaiser to navigate the readme
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Loop timed out! tloop Trying again…
Looping…
Looping…
Looping…
Looping…
Looping…
We did it! 1 2 3
Added:
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Loop timed out! tloop Trying again…
Looping…
Looping…
Looping…
Looping…
Looping…
We did it! 1 2 3
Added:
This will run said function in every thread.
-- Going to use love2d code this time, almost the same as last time... See ramblings
+require("core.Library")
+GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
+require("core.GuiManager")
+gui.ff.Color=Color.Black
+jQueue=multi:newSystemThreadedJobQueue()
+jQueue:registerJob("TEST_JOB",function(a,s)
+ math.randomseed(s)
+ TEST_JOB2()
+ return math.random(0,255)
+end)
+jQueue:registerJob("TEST_JOB2",function()
+ print("Test Works!")
+end)
+-- 1.8.6 EXAMPLE Change
+jQueue:start() -- This is now needed!
+--
+jQueue:doToAll(function()
+ print("Doing this 2? times!")
+end)
+tableOfOrder={}
+jQueue.OnJobCompleted(function(JOBID,n)
+ tableOfOrder[JOBID]=n
+ if #tableOfOrder==10 then
+ t.text="We got all of the pieces!"
+ end
+end)
+for i=1,10 do -- Job Name of registered function, ... varargs
+ jQueue:pushJob("TEST_JOB","This is a test!",math.random(1,1000000))
+end
+t=gui:newTextLabel("no done yet!",0,0,300,100)
+t:centerX()
+t:centerY()
+Added:
Allows the execution of system calls without hold up. It is possible to do the same using io.popen()! You decide which works best for you!
function
print("...") -- lets show that we aren't being held up
end,1)
multi:mainloop()
-Added:
Added:
First you need to create the object
This works the same way as love2d as it does with lanes… It is getting increasing harder to make both work the same way with speed in mind… Anyway…
fun
end
print("I pushed all of the jobs :)")
multi:mainloop() -- Start the main loop :D
-Thats it from this version!
Added:
New Mainloop functions Below you can see the slight differences… Function overhead is not too bad in lua, but has a real difference. multi:mainloop() and multi:unprotectedMainloop() use the same algorithm yet the dedicated unprotected one is slightly faster due to having less function overhead.
* The OG mainloop function remains the same and old methods to achieve what we have with the new ones still exist
These new methods help by removing function overhead that is caused through the original mainloop function. The one downside is that you no longer have the flexiblity to change the processing during runtime.
However there is a work around! You can use processes to run multiobjs as well and use the other methods on them.
I may make a full comparison between each method and which is faster, but for now trust that the dedicated ones with less function overhead are infact faster. Not by much but still faster. :D
Added:
Thats it from this version!
Added:
New Mainloop functions Below you can see the slight differences… Function overhead is not too bad in lua, but has a real difference. multi:mainloop() and multi:unprotectedMainloop() use the same algorithm yet the dedicated unprotected one is slightly faster due to having less function overhead.
* The OG mainloop function remains the same and old methods to achieve what we have with the new ones still exist
These new methods help by removing function overhead that is caused through the original mainloop function. The one downside is that you no longer have the flexiblity to change the processing during runtime.
However there is a work around! You can use processes to run multiobjs as well and use the other methods on them.
I may make a full comparison between each method and which is faster, but for now trust that the dedicated ones with less function overhead are infact faster. Not by much but still faster. :D
Added:
The threaded table is setup just like the threaded queue.
It provids GLOBAL like features without having to write to GLOBAL!
This is useful for module creators who want to keep their data private, but also use GLOBAL like coding.
It has a few features that makes it a bit better than plain ol GLOBAL (For now…)
(ThreadedTable - TT for short)
we also have the “sync” method, this one was made for love2d because we do a syncing trick to get data in a table format. The lanes side has a sync method as well so no worries. Using indexing calls sync once and may grab your variable. This allows you to have the lanes indexing ‘like’ syntax when doing regular indexing in love2d side of the module. As of right now both sides work flawlessly! And this effect is now the GLOBAL as well
On GLOBALS sync is a internal method for keeping the GLOBAL table in order. You can still use sThread.waitFor(name) to wait for variables that may of may not yet exist!
Time for some examples:
"test2","no done yet!",0,0,300,100)
t:centerX()
t:centerY()
-No real change!
Changed the structure of the library. Combined the coroutine based threads into the core!
Only compat and integrations are not part of the core and never will be by nature.
This should make the library more convient to use.
I left multi/all.lua file so if anyone had libraries/projects that used that it will still work!
Updated from 1.7.6 to 1.8.0
(How much thread could a thread thread if a thread could thread thread?)
Added:
No real change!
Changed the structure of the library. Combined the coroutine based threads into the core!
Only compat and integrations are not part of the core and never will be by nature.
This should make the library more convient to use.
I left multi/all.lua file so if anyone had libraries/projects that used that it will still work!
Updated from 1.7.6 to 1.8.0
(How much thread could a thread thread if a thread could thread thread?)
Added:
"test!",end
end)
multi:mainloop()
-Fixed:
Typos like always
Added:
multi:getPlatform() — returns “love2d” if using the love2d platform or returns “lanes” if using lanes for threading
examples files
In Events added method setTask(func)
The old way still works and is more convient to be honest, but I felt a method to do this was ok.
Updated:
some example files to reflect changes to the core. Changes allow for less typing
loveManager to require the compat if used so you don’t need 2 require line to retrieve the library
Fixed some typos in the readme… (I am sure there are more there are always more)
Added more features for module support
TODO:
Work on performance of the library… I see 3 places where I can make this thing run quicker
I’ll show case some old versions of the multitasking library eventually so you can see its changes in days past!
Added: the example folder which will be populated with more examples in the near future!
The loveManager integration that mimics the lanesManager integration almost exactly to keep coding in both enviroments as close to possible. This is done mostly for library creation support!
An example of the loveManager in action using almost the same code as the lanesintergreationtest2.lua
NOTE: This code has only been tested to work on love2d version 1.10.2 thoough it should work version 0.9.0
Update: 1.7.6Fixed:
Typos like always
Added:
multi:getPlatform() — returns “love2d” if using the love2d platform or returns “lanes” if using lanes for threading
examples files
In Events added method setTask(func)
The old way still works and is more convient to be honest, but I felt a method to do this was ok.
Updated:
some example files to reflect changes to the core. Changes allow for less typing
loveManager to require the compat if used so you don’t need 2 require line to retrieve the library
Update: 1.7.5
Fixed some typos in the readme… (I am sure there are more there are always more)
Added more features for module support
TODO:
Work on performance of the library… I see 3 places where I can make this thing run quicker
I’ll show case some old versions of the multitasking library eventually so you can see its changes in days past!
Update: 1.7.4
Added: the example folder which will be populated with more examples in the near future!
The loveManager integration that mimics the lanesManager integration almost exactly to keep coding in both enviroments as close to possible. This is done mostly for library creation support!
An example of the loveManager in action using almost the same code as the lanesintergreationtest2.lua
NOTE: This code has only been tested to work on love2d version 1.10.2 thoough it should work version 0.9.0
"Bench"]=3"no done yet!",0,0,300,100)
t:centerX()
t:centerY()
-
Updated from 1.7.2 to 1.7.3
Changed how requiring the library works!
require("multi.all") Will still work as expected; however, with the exception of threading, compat, and integrations everything else has been moved into the core of the library.
Update: 1.7.3Changed how requiring the library works!
require("multi.all") Will still work as expected; however, with the exception of threading, compat, and integrations everything else has been moved into the core of the library.
require("multi.step")
require("multi.task")
-- ^ they are all part of the core now
-
Updated from 1.7.1 to 1.7.2
Moved updaters, loops, and alarms into the init.lua file. I consider them core features and they are referenced in the init.lua file so they need to exist there. Threaded versions are still separate though. Added another example file
Updated from 1.7.0 to 1.7.1 Bug fixes only
Updated from 1.6.0 to 1.7.0
Modified: multi.integration.lanesManager.lua
It is now in a stable and simple state Works with the latest lanes version! Tested with version 3.11 I cannot promise that everything will work with eariler versions. Future versions are good though.
Example Usage:
sThread is a handle to a global interface for system threads to interact with themself
thread is the interface for multithreads as seen in the threading section
GLOBAL a table that can be used throughout each and every thread
sThreads have a few methods
sThread.set(name,val) — you can use the GLOBAL table instead modifies the same table anyway
sThread.get(name) — you can use the GLOBAL table instead modifies the same table anyway
sThread.waitFor(name) — waits until a value exists, if it does it returns it
sThread.getCores() — returns the number of cores on your cpu
sThread.sleep(n) — sleeps for a bit stopping the entire thread from running
sThread.hold(n) — sleeps until a condition is met
Update: 1.7.2Moved updaters, loops, and alarms into the init.lua file. I consider them core features and they are referenced in the init.lua file so they need to exist there. Threaded versions are still separate though. Added another example file
Update: 1.7.1 Bug Fixes Only
Update: 1.7.0
Modified: multi.integration.lanesManager.lua
It is now in a stable and simple state Works with the latest lanes version! Tested with version 3.11 I cannot promise that everything will work with eariler versions. Future versions are good though.
Example Usage:
sThread is a handle to a global interface for system threads to interact with themself
thread is the interface for multithreads as seen in the threading section
GLOBAL a table that can be used throughout each and every thread
sThreads have a few methods
sThread.set(name,val) — you can use the GLOBAL table instead modifies the same table anyway
sThread.get(name) — you can use the GLOBAL table instead modifies the same table anyway
sThread.waitFor(name) — waits until a value exists, if it does it returns it
sThread.getCores() — returns the number of cores on your cpu
sThread.sleep(n) — sleeps for a bit stopping the entire thread from running
sThread.hold(n) — sleeps until a condition is met
"test",end)
multi:mainloop()
-
Updated from 1.5.0 to 1.6.0
Changed: steps and loops
Update: 1.6.0Changed: steps and loops
function
">require("multi.all")
require("multi.compat.backwards[1,5,0]") -- allows for the use of features that were scrapped/changed in 1.6.0+
-
Updated from 1.4.1 to 1.5.0
Added:
-- An easy way to manage timeouts
- Small bug fixes
1.4.1 - First Public release of the library
IMPORTANT:
Every update I make aims to make things simpler more efficent and just better, but a lot of old code, which can be really big, uses a lot of older features. I know the pain of having to rewrite everything. My promise to my library users is that I will always have backwards support for older features! New ways may exist that are quicker and eaiser, but the old features/methods will be supported.
Rambling
Love2d: Sleeping reduces the cpu time making my load detection think the system is under more load, thus preventing it from sleeping… I will look into other means. As of right now it will not eat all of your cpu if threads are active. For now I suggest killing threads that aren’t needed anymore. On lanes threads at idle use 0% cpu and it is amazing. A state machine may solve what I need though. One state being idle state that sleeps and only goes into the active state if a job request or data is sent to it… after some time of not being under load it wil switch back into the idle state… We’ll see what happens.
Love2d doesn’t like to send functions through channels. By defualt it does not support this. I achieve this by dumping the function and loadstring it on the thread. This however is slow. For the System Threaded Job Queue I had to change my original idea of sending functions as jobs. The current way you do it now is register a job functions once and then call that job across the thread through a queue. Each worker thread pops from the queue and returns the job. The Job ID is automatically updated and allows you to keep track of the order that the data comes in. A table with # indexes can be used to originze the data…
In regards to benchmarking. If you see my bench marks and are wondering they are 10x better its because I am using luajit for my tests. I highly recommend using luajit for my library, but lua 5.1 will work just as well, but not as fast.
+
Update: 1.5.0
Added:
+- An easy way to manage timeouts
- Small bug fixes
Update: 1.4.1 - First Public release of the library
IMPORTANT:
Every update I make aims to make things simpler more efficent and just better, but a lot of old code, which can be really big, uses a lot of older features. I know the pain of having to rewrite everything. My promise to my library users is that I will always have backwards support for older features! New ways may exist that are quicker and eaiser, but the old features/methods will be supported.
Rambling
Love2d Sleeping reduces the cpu time making my load detection think the system is under more load, thus preventing it from sleeping… I will look into other means. As of right now it will not eat all of your cpu if threads are active. For now I suggest killing threads that aren’t needed anymore. On lanes threads at idle use 0% cpu and it is amazing. A state machine may solve what I need though. One state being idle state that sleeps and only goes into the active state if a job request or data is sent to it… after some time of not being under load it wil switch back into the idle state… We’ll see what happens.
Love2d doesn’t like to send functions through channels. By defualt it does not support this. I achieve this by dumping the function and loadstring it on the thread. This however is slow. For the System Threaded Job Queue I had to change my original idea of sending functions as jobs. The current way you do it now is register a job functions once and then call that job across the thread through a queue. Each worker thread pops from the queue and returns the job. The Job ID is automatically updated and allows you to keep track of the order that the data comes in. A table with # indexes can be used to originze the data…
In regards to benchmarking. If you see my bench marks and are wondering they are 10x better its because I am using luajit for my tests. I highly recommend using luajit for my library, but lua 5.1 will work just as well, but not as fast.
So while working on the jobQueue:doToAll() method I figured out why love2d’s threaded tables were acting up when more than 1 thread was sharing the table. It turns out 1 thread was eating all of the pops from the queue and starved all of the other queues… Ill need to use the same trick I did with GLOBAL to fix the problem… However at the rate I am going threading in love will become way slower. I might use the regualr GLOBAL to manage data internally for threadedtables…
It has been awhile since I had to bring out the Multi Functions… Syncing within threads are a pain! I had no idea what a task it would be to get something as simple as syncing data was going to be… I will probably add a SystemThreadedSyncer in the future because it will make life eaiser for you guys as well. SystemThreadedTables are still not going to work on love2d, but will work fine on lanes… I have a solution and it is being worked on… Depending on when I pust the next update to this library the second half of this ramble won’t apply anymore
I have been using this (EventManager —> MultiManager —> now multi) for my own purposes and started making this when I first started learning lua. You are able to see how the code changed and evolved throughout the years. I tried to include all the versions that still existed on my HDD.
I added my old versions to this library… It started out as the EventManager and was kinda crappy but it was the start to this library. It kept getting better and better until it became what it is today. There are some features that nolonger exist in the latest version, but they were remove because they were useless… I added these files to the github so for those interested can see into my mind in a sense and see how I developed the library before I used github.
The first version of the EventManager was function based not object based and benched at about 2000 steps per second… Yeah that was bad… I used loadstring and it was a mess… Take a look and see how it grew throughout the years I think it may intrest some of you guys!
diff --git a/README.md b/README.md
index 1f69280..d42b804 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-# multi Version: 1.8.5 (System Threaded Execute) Looking into some bugs...
+# multi Version: 1.8.6 (System Threaded Job Queues gets an update!) Also On the github you can check out the old versions of this library! It stems back from 2012 see rambling for more info...
**Note: The changes section has information on how to use the new features as they come out. Why put the infomation twice on the readme?** Also I added a Testing Branch. That Branch will have the latest updates, but those updates may be unstable. I like to keep the master as bug free as possible
-# Note SystemThreadedTable's behavior is not stable! I am looking into this.
+# Note SystemThreadedTable's behavior is not stable! I have found the cause of the problem and am currently figuring out a solution... The next update will probably include the fix!
In Changes you'll find documentation for(In Order):
- System Threaded Job Queues
@@ -801,8 +801,52 @@ We did it! 1 2 3
Changes
-------
-Updated from 1.8.4 to 1.8.5
----------------------------
+Update: 1.8.6
+-------------
+Added:
+- jobQueue:doToAll(function)
+- jobQueue:start() is now required Call this after all calls to registerJob()'s. Calling it afterwards will not guarantee your next push job with that job will work. Not calling this will make pushing jobs impossible!
+- Fixed a bug with love2d Threaded Queue
+- Fixed some bugs
+
+This will run said function in every thread.
+```lua
+-- Going to use love2d code this time, almost the same as last time... See ramblings
+require("core.Library")
+GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
+require("core.GuiManager")
+gui.ff.Color=Color.Black
+jQueue=multi:newSystemThreadedJobQueue()
+jQueue:registerJob("TEST_JOB",function(a,s)
+ math.randomseed(s)
+ TEST_JOB2()
+ return math.random(0,255)
+end)
+jQueue:registerJob("TEST_JOB2",function()
+ print("Test Works!")
+end)
+-- 1.8.6 EXAMPLE Change
+jQueue:start() -- This is now needed!
+--
+jQueue:doToAll(function()
+ print("Doing this 2? times!")
+end)
+tableOfOrder={}
+jQueue.OnJobCompleted(function(JOBID,n)
+ tableOfOrder[JOBID]=n
+ if #tableOfOrder==10 then
+ t.text="We got all of the pieces!"
+ end
+end)
+for i=1,10 do -- Job Name of registered function, ... varargs
+ jQueue:pushJob("TEST_JOB","This is a test!",math.random(1,1000000))
+end
+t=gui:newTextLabel("no done yet!",0,0,300,100)
+t:centerX()
+t:centerY()
+```
+Update: 1.8.5
+-------------
Added:
- SystemThreadedExecute(cmd)
@@ -818,8 +862,8 @@ multi:newTLoop(function()
end,1)
multi:mainloop()
```
-Updated from 1.8.3 to 1.8.4
----------------------------
+Update: 1.8.4
+-------------
Added:
- multi:newSystemThreadedJobQueue()
- Improved stability of the library
@@ -863,8 +907,8 @@ multi:mainloop() -- Start the main loop :D
Thats it from this version!
-Updated from 1.8.2 to 1.8.3
----------------------------
+Update: 1.8.3
+-------------
Added:
**New Mainloop functions** Below you can see the slight differences... Function overhead is not too bad in lua, but has a real difference. multi:mainloop() and multi:unprotectedMainloop() use the same algorithm yet the dedicated unprotected one is slightly faster due to having less function overhead.
- multi:mainloop()\* -- Bench: 16830003 Steps in 3 second(s)!
@@ -881,8 +925,8 @@ However there is a work around! You can use processes to run multiobjs as well a
I may make a full comparison between each method and which is faster, but for now trust that the dedicated ones with less function overhead are infact faster. Not by much but still faster. :D
-Updated from 1.8.1 to 1.8.2
----------------------------
+Update: 1.8.2
+-------------
Added:
- multi:newsystemThreadedTable(name) NOTE: Metatables are not supported in transfers. However there is a work around obj:init() that you see does this. Take a look in the multi/integration/shared/shared.lua files to see how I did it!
- Modified the GLOBAL metatable to sync before doing its tests
@@ -945,8 +989,8 @@ t:centerX()
t:centerY()
```
-Updated from 1.8.0 to 1.8.1
----------------------------
+Update: 1.8.1
+-------------
No real change!
Changed the structure of the library. Combined the coroutine based threads into the core!
Only compat and integrations are not part of the core and never will be by nature.
@@ -1073,8 +1117,8 @@ multi:newThread("test!",function() -- this is a lua thread
end)
multi:mainloop()
```
-Updated from 1.7.5 to 1.7.6
----------------------------
+Update: 1.7.6
+-------------
Fixed:
Typos like always
Added:
@@ -1086,8 +1130,9 @@ The old way still works and is more convient to be honest, but I felt a method t
Updated:
some example files to reflect changes to the core. Changes allow for less typing
loveManager to require the compat if used so you don't need 2 require line to retrieve the library
-Updated from 1.7.4 to 1.7.5
----------------------------
+
+Update: 1.7.5
+-------------
Fixed some typos in the readme... (I am sure there are more there are always more)
Added more features for module support
TODO:
@@ -1095,8 +1140,8 @@ Work on performance of the library... I see 3 places where I can make this thing
I'll show case some old versions of the multitasking library eventually so you can see its changes in days past!
-Updated from 1.7.3 to 1.7.4
----------------------------
+Update: 1.7.4
+-------------
Added: the example folder which will be populated with more examples in the near future!
The loveManager integration that mimics the lanesManager integration almost exactly to keep coding in both enviroments as close to possible. This is done mostly for library creation support!
An example of the loveManager in action using almost the same code as the lanesintergreationtest2.lua
@@ -1173,8 +1218,8 @@ t=gui:newTextLabel("no done yet!",0,0,300,100)
t:centerX()
t:centerY()
```
-Updated from 1.7.2 to 1.7.3
----------------------------
+Update: 1.7.3
+-------------
Changed how requiring the library works!
`require("multi.all")` Will still work as expected; however, with the exception of threading, compat, and integrations everything else has been moved into the core of the library.
```lua
@@ -1190,15 +1235,15 @@ require("multi.task")
-- ^ they are all part of the core now
```
-Updated from 1.7.1 to 1.7.2
----------------------------
+Update: 1.7.2
+-------------
Moved updaters, loops, and alarms into the init.lua file. I consider them core features and they are referenced in the init.lua file so they need to exist there. Threaded versions are still separate though. Added another example file
-Updated from 1.7.0 to 1.7.1 Bug fixes only
----------------------------
+Update: 1.7.1 Bug Fixes Only
+-------------
-Updated from 1.6.0 to 1.7.0
----------------------------
+Update: 1.7.0
+-------------
Modified: multi.integration.lanesManager.lua
It is now in a stable and simple state Works with the latest lanes version! Tested with version 3.11 I cannot promise that everything will work with eariler versions. Future versions are good though.
Example Usage:
@@ -1251,8 +1296,8 @@ end)
multi:mainloop()
```
-Updated from 1.5.0 to 1.6.0
----------------------------
+Update: 1.6.0
+-------------
Changed: steps and loops
```lua
-- Was
@@ -1275,21 +1320,31 @@ Reasoning I wanted to keep objects consistant, but a lot of my older libraries u
require("multi.all")
require("multi.compat.backwards[1,5,0]") -- allows for the use of features that were scrapped/changed in 1.6.0+
```
-Updated from 1.4.1 to 1.5.0
----------------------------
+Update: 1.5.0
+-------------
Added:
- An easy way to manage timeouts
- Small bug fixes
-1.4.1 - First Public release of the library
----------------------------
+Update: 1.4.1 - First Public release of the library
+-------------
IMPORTANT:
Every update I make aims to make things simpler more efficent and just better, but a lot of old code, which can be really big, uses a lot of older features. I know the pain of having to rewrite everything. My promise to my library users is that I will always have backwards support for older features! New ways may exist that are quicker and eaiser, but the old features/methods will be supported.
Rambling
--------
-Love2d: Sleeping reduces the cpu time making my load detection think the system is under more load, thus preventing it from sleeping... I will look into other means. As of right now it will not eat all of your cpu if threads are active. For now I suggest killing threads that aren't needed anymore. On lanes threads at idle use 0% cpu and it is amazing. A state machine may solve what I need though. One state being idle state that sleeps and only goes into the active state if a job request or data is sent to it... after some time of not being under load it wil switch back into the idle state... We'll see what happens.
+Love2d Sleeping reduces the cpu time making my load detection think the system is under more load, thus preventing it from sleeping... I will look into other means. As of right now it will not eat all of your cpu if threads are active. For now I suggest killing threads that aren't needed anymore. On lanes threads at idle use 0% cpu and it is amazing. A state machine may solve what I need though. One state being idle state that sleeps and only goes into the active state if a job request or data is sent to it... after some time of not being under load it wil switch back into the idle state... We'll see what happens.
Love2d doesn't like to send functions through channels. By defualt it does not support this. I achieve this by dumping the function and loadstring it on the thread. This however is slow. For the System Threaded Job Queue I had to change my original idea of sending functions as jobs. The current way you do it now is register a job functions once and then call that job across the thread through a queue. Each worker thread pops from the queue and returns the job. The Job ID is automatically updated and allows you to keep track of the order that the data comes in. A table with # indexes can be used to originze the data...
In regards to benchmarking. If you see my bench marks and are wondering they are 10x better its because I am using luajit for my tests. I highly recommend using luajit for my library, but lua 5.1 will work just as well, but not as fast.
+
+So while working on the jobQueue:doToAll() method I figured out why love2d's threaded tables were acting up when more than 1 thread was sharing the table. It turns out 1 thread was eating all of the pops from the queue and starved all of the other queues... Ill need to use the same trick I did with GLOBAL to fix the problem... However at the rate I am going threading in love will become way slower. I might use the regualr GLOBAL to manage data internally for threadedtables...
+
+It has been awhile since I had to bring out the Multi Functions... Syncing within threads are a pain! I had no idea what a task it would be to get something as simple as syncing data was going to be... I will probably add a SystemThreadedSyncer in the future because it will make life eaiser for you guys as well. SystemThreadedTables are still not going to work on love2d, but will work fine on lanes... I have a solution and it is being worked on... Depending on when I pust the next update to this library the second half of this ramble won't apply anymore
+
+I have been using this (EventManager --> MultiManager --> now multi) for my own purposes and started making this when I first started learning lua. You are able to see how the code changed and evolved throughout the years. I tried to include all the versions that still existed on my HDD.
+
+I added my old versions to this library... It started out as the EventManager and was kinda crappy but it was the start to this library. It kept getting better and better until it became what it is today. There are some features that nolonger exist in the latest version, but they were remove because they were useless... I added these files to the github so for those interested can see into my mind in a sense and see how I developed the library before I used github.
+
+The first version of the EventManager was function based not object based and benched at about 2000 steps per second... Yeah that was bad... I used loadstring and it was a mess... Take a look and see how it grew throughout the years I think it may intrest some of you guys!
\ No newline at end of file
diff --git a/examples/lanesintegratetest7.lua b/examples/lanesintegratetest7.lua
index 4d8c3b4..a77c05b 100644
--- a/examples/lanesintegratetest7.lua
+++ b/examples/lanesintegratetest7.lua
@@ -11,6 +11,7 @@ end)
jQueue:registerJob("TEST_JOB2",function()
print("Test Works!") -- this is called from the job since it is registered on the same queue
end)
+jQueue:start()
tableOfOrder={} -- This is how we will keep order of our completed jobs. There is no guarantee that the order will be correct
jQueue.OnJobCompleted(function(JOBID,n) -- whenever a job is completed you hook to the event that is called. This passes the JOBID folled by the returns of the job
-- JOBID is the completed job, starts at 1 and counts up by 1.
diff --git a/examples/lanesintegratetest9.lua b/examples/lanesintegratetest9.lua
new file mode 100644
index 0000000..eac0284
--- /dev/null
+++ b/examples/lanesintegratetest9.lua
@@ -0,0 +1,26 @@
+package.path="?/init.lua;"..package.path
+local GLOBAL,sThread=require("multi.integration.lanesManager").init()
+jQueue=multi:newSystemThreadedJobQueue(n)
+jQueue:registerJob("TEST_JOB",function(a,s)
+ math.randomseed(s)
+ TEST_JOB2()
+ return math.random(0,255)
+end)
+jQueue:registerJob("TEST_JOB2",function()
+ print("Test Works!")
+end)
+jQueue:start()
+jQueue:doToAll(function()
+ print("Doing this 6? times!")
+end)
+for i=1,10 do -- Job Name of registered function, ... varargs
+ jQueue:pushJob("TEST_JOB","This is a test!",math.random(1,1000000))
+end
+tableOfOrder={}
+jQueue.OnJobCompleted(function(JOBID,n)
+ tableOfOrder[JOBID]=n
+ if #tableOfOrder==10 then
+ print("We got all of the pieces!")
+ end
+end)
+multi:mainloop()
diff --git a/examples/love2d Threading Example/main5.lua b/examples/love2d Threading Example/main5.lua
index 94a8a45..d491c6a 100644
--- a/examples/love2d Threading Example/main5.lua
+++ b/examples/love2d Threading Example/main5.lua
@@ -13,6 +13,7 @@ end)
jQueue:registerJob("TEST_JOB2",function(a,s)
print("Test Works!")
end)
+jQueue:start()
tableOfOrder={}
jQueue.OnJobCompleted(function(JOBID,n)
-- JOBID is the completed job, starts at 1 and counts up by 1.
diff --git a/examples/love2d Threading Example/multi/init.lua b/examples/love2d Threading Example/multi/init.lua
index 2349735..1c98dfa 100644
--- a/examples/love2d Threading Example/multi/init.lua
+++ b/examples/love2d Threading Example/multi/init.lua
@@ -45,8 +45,8 @@ function print(...)
end
end
multi = {}
-multi.Version="1.8.5"
-multi._VERSION="1.8.5"
+multi.Version="1.8.6"
+multi._VERSION="1.8.6"
multi.stage='mostly-stable'
multi.__index = multi
multi.Mainloop={}
@@ -607,7 +607,11 @@ function multi:hold(task)
timer:Start()
while timer:Get()=]]..set,[[event:removeAlarm("]]..tag..[[")]]) event:addTracker("_Alarm_"..tag,SetCounter()) end,
+setEvent=function(self,fname,condition,also) if not(string.find(fname,"(",1,true)) and not(string.find(fname,")",1,true)) then fname=fname.."()" end event:new("Event_"..fname,condition,also) end,
+removeAlarm=function(self,tag) event:destroy("Alarm_"..tag) event:removeTracker("_Alarm_"..tag) end,
+updateAlarm=function(self,tag,set) event:removeAlarm(tag) event:setAlarm(tag,set) end,
+addTracker=function(self,varname,var) event.EventTracker[varname]=var end,
+getTracker=function(self,var) return event.EventTracker[var] end,
+removeTracker=function(self,var) event.EventTracker[var]=nil end,
+trackerExist=function(self,tag) return event.EventTracker[tag]~=nil end,
+updateTracker=function(self,tag,val) if event:trackerExist(tag) then event.EventTracker[tag]=val end end,
+alarmExist=function(self,tag) return (event:getTracker("_Alarm_"..tag)~=nil) end,
+new=function(self,fname,condition,also) if not(also) then also="" end table.insert(self.Events,"if "..condition.." then "..also.." "..fname.." end") table.insert(event.tag,fname) end,
+eventExist=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then return true end end return false end,
+destroy=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then table.remove(event.tag,j) table.remove(event.Events,j) end end end,
+Stop=function() event.Active=false end,
+OnCreate=function() end,
+OnUpdate=function() end,
+OnClose=function() end,
+getActive=function() return event.tag end,
+Manager=function() event.OnCreate() while event.Active==true do for d=1,#event.Events do if event.Active==true then loadstring(event.Events[d])() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end event.OnClose() end,
+CManager=function() for d=1,#event.Events do if event.Active==true then loadstring(event.Events[d])() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end,
+UManager=function() if event.CT==false then event.CT=true event.OnCreate() end for d=1,#event.Events do if event.Active==true then loadstring(event.Events[d])() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end,
+createStep=function(self,tag,reset,endc)
+if not(endc) then endc=false end
+if not(reset) then reset=0 end
+temp={Name=tag,pos=1,endAt=reset,active=true,endc=endc,
+Step=function(self) if self~=nil then _G.__CStep__=self if self.active==true then loadstring("Step_"..tag.."("..self.pos..",__CStep__)")() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then loadstring("Step_"..self.Name.."_End(__CStep__)")() end end end,
+Remove=function(self) for as=1,#event.Steps do if event.Steps[as].Name==self.Name then table.remove(event.Steps,as) end end end,
+Reset=function(self) self.pos=1 end,
+Set=function(self,amt) self.pos=amt end,
+Pause=function(self) self.active=false end,
+Resume=function(self) self.active=true end,
+Stop=function(self) self:Reset() self:Pause() end,
+Start=function(self) self:Resume() end,
+End=function(self) self.pos=self.EndAt self.endc=true end,
+}
+table.insert(event.Steps,temp) return temp end,
+stepExist=function(self,tag)
+for a_s=1,#event.Steps do
+if event.Steps[a_s].Name==tag then
+return true
+end
+end
+return false
+end,
+}
diff --git a/oldversions/EventManager(0.9.0).lua b/oldversions/EventManager(0.9.0).lua
new file mode 100644
index 0000000..3b31066
--- /dev/null
+++ b/oldversions/EventManager(0.9.0).lua
@@ -0,0 +1,55 @@
+IsEvent=true
+event={
+Active=true,
+CT=false,
+tag={},
+Events={},
+EventTracker={},
+Steps={},
+--addAlarm=function(self,tag) end,
+setAlarm=function(self,tag,set) event:new("Alarm_"..tag.."(\""..tag.."\")",[[GetCounter(event:getTracker("_Alarm_]]..tag..[["))>=]]..set,[[event:removeAlarm("]]..tag..[[")]]) event:addTracker("_Alarm_"..tag,SetCounter()) assert(loadstring("if Alarm_"..tag.."==nil then function Alarm_"..tag.."() print('No function \"Alarm_"..tag.."()\" exists make sure you created it') end end"))() end,
+setEvent=function(self,fname,condition,also) if not(string.find(fname,"(",1,true)) and not(string.find(fname,")",1,true)) then fname=fname.."()" end a=string.find(fname,"(",1,true) tempstr=string.sub(fname,1,a-1) event:new("Event_"..fname,condition,also) assert(loadstring("if Event_"..tempstr.."==nil then function Event_"..tempstr.."() print('No function \"Event_"..tempstr.."()\" exists make sure you created it') end end"))() end,
+removeAlarm=function(self,tag) event:destroy("Alarm_"..tag) event:removeTracker("_Alarm_"..tag) end,
+updateAlarm=function(self,tag,set) event:removeAlarm(tag) event:setAlarm(tag,set) end,
+addTracker=function(self,varname,var) event.EventTracker[varname]=var end,
+getTracker=function(self,var) return event.EventTracker[var] end,
+removeTracker=function(self,var) event.EventTracker[var]=nil end,
+trackerExist=function(self,tag) return event.EventTracker[tag]~=nil end,
+updateTracker=function(self,tag,val) if event:trackerExist(tag) then event.EventTracker[tag]=val end end,
+alarmExist=function(self,tag) return (event:getTracker("_Alarm_"..tag)~=nil) end,
+new=function(self,fname,condition,also) if not(also) then also="" end table.insert(self.Events,"if "..condition.." then "..also.." "..fname.." end") table.insert(event.tag,fname) end,
+eventExist=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then return true end end return false end,
+destroy=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then table.remove(event.tag,j) table.remove(event.Events,j) end end end,
+Stop=function() event.Active=false end,
+OnCreate=function() end,
+OnUpdate=function() end,
+OnClose=function() end,
+getActive=function() return event.tag end,
+Manager=function() event.OnCreate() while event.Active==true do for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end event.OnClose() end,
+CManager=function() for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end,
+UManager=function() if event.CT==false then event.CT=true event.OnCreate() end for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end,
+RManager=function() event.OnCreate() while event.Active==true do event.OnUpdate() for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end end event.OnClose() end,
+createStep=function(self,tag,reset,endc)
+if not(endc) then endc=false end
+if not(reset) then reset=0 end
+temp={Name=tag,pos=1,endAt=reset,active=true,endc=endc,
+Step=function(self) if self~=nil then _G.__CStep__=self if self.active==true then assert(loadstring("Step_"..tag.."("..self.pos..",__CStep__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("Step_"..self.Name.."_End(__CStep__)"))() end end end,
+Remove=function(self) for as=1,#event.Steps do if event.Steps[as].Name==self.Name then table.remove(event.Steps,as) end end end,
+Reset=function(self) self.pos=1 end,
+Set=function(self,amt) self.pos=amt end,
+Pause=function(self) self.active=false end,
+Resume=function(self) self.active=true end,
+Stop=function(self) self:Reset() self:Pause() end,
+Start=function(self) self:Resume() end,
+End=function(self) self.pos=self.EndAt self.endc=true end,
+}
+table.insert(event.Steps,temp) return temp end,
+stepExist=function(self,tag)
+for a_s=1,#event.Steps do
+if event.Steps[a_s].Name==tag then
+return true
+end
+end
+return false
+end,
+}
diff --git a/oldversions/EventManager(1.0.0).lua b/oldversions/EventManager(1.0.0).lua
new file mode 100644
index 0000000..3b31066
--- /dev/null
+++ b/oldversions/EventManager(1.0.0).lua
@@ -0,0 +1,55 @@
+IsEvent=true
+event={
+Active=true,
+CT=false,
+tag={},
+Events={},
+EventTracker={},
+Steps={},
+--addAlarm=function(self,tag) end,
+setAlarm=function(self,tag,set) event:new("Alarm_"..tag.."(\""..tag.."\")",[[GetCounter(event:getTracker("_Alarm_]]..tag..[["))>=]]..set,[[event:removeAlarm("]]..tag..[[")]]) event:addTracker("_Alarm_"..tag,SetCounter()) assert(loadstring("if Alarm_"..tag.."==nil then function Alarm_"..tag.."() print('No function \"Alarm_"..tag.."()\" exists make sure you created it') end end"))() end,
+setEvent=function(self,fname,condition,also) if not(string.find(fname,"(",1,true)) and not(string.find(fname,")",1,true)) then fname=fname.."()" end a=string.find(fname,"(",1,true) tempstr=string.sub(fname,1,a-1) event:new("Event_"..fname,condition,also) assert(loadstring("if Event_"..tempstr.."==nil then function Event_"..tempstr.."() print('No function \"Event_"..tempstr.."()\" exists make sure you created it') end end"))() end,
+removeAlarm=function(self,tag) event:destroy("Alarm_"..tag) event:removeTracker("_Alarm_"..tag) end,
+updateAlarm=function(self,tag,set) event:removeAlarm(tag) event:setAlarm(tag,set) end,
+addTracker=function(self,varname,var) event.EventTracker[varname]=var end,
+getTracker=function(self,var) return event.EventTracker[var] end,
+removeTracker=function(self,var) event.EventTracker[var]=nil end,
+trackerExist=function(self,tag) return event.EventTracker[tag]~=nil end,
+updateTracker=function(self,tag,val) if event:trackerExist(tag) then event.EventTracker[tag]=val end end,
+alarmExist=function(self,tag) return (event:getTracker("_Alarm_"..tag)~=nil) end,
+new=function(self,fname,condition,also) if not(also) then also="" end table.insert(self.Events,"if "..condition.." then "..also.." "..fname.." end") table.insert(event.tag,fname) end,
+eventExist=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then return true end end return false end,
+destroy=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then table.remove(event.tag,j) table.remove(event.Events,j) end end end,
+Stop=function() event.Active=false end,
+OnCreate=function() end,
+OnUpdate=function() end,
+OnClose=function() end,
+getActive=function() return event.tag end,
+Manager=function() event.OnCreate() while event.Active==true do for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end event.OnClose() end,
+CManager=function() for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end,
+UManager=function() if event.CT==false then event.CT=true event.OnCreate() end for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end,
+RManager=function() event.OnCreate() while event.Active==true do event.OnUpdate() for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end end event.OnClose() end,
+createStep=function(self,tag,reset,endc)
+if not(endc) then endc=false end
+if not(reset) then reset=0 end
+temp={Name=tag,pos=1,endAt=reset,active=true,endc=endc,
+Step=function(self) if self~=nil then _G.__CStep__=self if self.active==true then assert(loadstring("Step_"..tag.."("..self.pos..",__CStep__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("Step_"..self.Name.."_End(__CStep__)"))() end end end,
+Remove=function(self) for as=1,#event.Steps do if event.Steps[as].Name==self.Name then table.remove(event.Steps,as) end end end,
+Reset=function(self) self.pos=1 end,
+Set=function(self,amt) self.pos=amt end,
+Pause=function(self) self.active=false end,
+Resume=function(self) self.active=true end,
+Stop=function(self) self:Reset() self:Pause() end,
+Start=function(self) self:Resume() end,
+End=function(self) self.pos=self.EndAt self.endc=true end,
+}
+table.insert(event.Steps,temp) return temp end,
+stepExist=function(self,tag)
+for a_s=1,#event.Steps do
+if event.Steps[a_s].Name==tag then
+return true
+end
+end
+return false
+end,
+}
diff --git a/oldversions/EventManager(1.1.0).lua b/oldversions/EventManager(1.1.0).lua
new file mode 100644
index 0000000..9ad29ad
--- /dev/null
+++ b/oldversions/EventManager(1.1.0).lua
@@ -0,0 +1,98 @@
+require("Data/BasicCommands")
+IsEvent=true
+event={
+ Active=true,
+ CT=false,
+ tag={},
+ Events={},
+ EventTracker={},
+ Steps={},
+ TSteps={},
+ LoadOrder="/E/S/U",-- types = ESU,EUS,USE,UES,SEU,SUE
+ setLoadOrder=function(self,str) event.LoadOrder=string.upper(str) end,
+ DO_Order=function() LoadOrder=event.LoadOrder LoadOrder=LoadOrder:gsub("/E", "event.RUN_EVENTS(); ") LoadOrder=LoadOrder:gsub("/S", "event.RUN_STEPS(); ") LoadOrder=LoadOrder:gsub("/U", "event.RUN_UPDATES(); ") assert(loadstring(LoadOrder))() end,
+ RUN_EVENTS=function() for d=1,#event.Events do assert(loadstring(event.Events[d]))() end end,
+ RUN_STEPS=function() for s_g=1,#event.Steps do event.Steps[s_g]:Step() end end,
+ RUN_UPDATES=function() event.OnUpdate() end,
+ setAlarm=function(self,tag,set) event:new("Alarm_"..tag.."(\""..tag.."\")",[[GetCounter(event:getTracker("_Alarm_]]..tag..[["))>=]]..set,[[event:removeAlarm("]]..tag..[[")]]) event:addTracker("_Alarm_"..tag,SetCounter()) assert(loadstring("if Alarm_"..tag.."==nil then function Alarm_"..tag.."() print('No function \"Alarm_"..tag.."()\" exists make sure you created it') end end"))() end,
+ setEvent=function(self,fname,condition,also) if not(string.find(fname,"(",1,true)) and not(string.find(fname,")",1,true)) then fname=fname.."()" end a=string.find(fname,"(",1,true) tempstr=string.sub(fname,1,a-1) event:new("Event_"..fname,condition,also) assert(loadstring("if Event_"..tempstr.."==nil then function Event_"..tempstr.."() print('No function \"Event_"..tempstr.."()\" exists make sure you created it') end end"))() end,
+ removeAlarm=function(self,tag) event:destroy("Alarm_"..tag) event:removeTracker("_Alarm_"..tag) end,
+ updateAlarm=function(self,tag,set) event:removeAlarm(tag) event:setAlarm(tag,set) end,
+ addTracker=function(self,varname,var) event.EventTracker[varname]=var end,
+ getTracker=function(self,varname) return event.EventTracker[varname] end,
+ removeTracker=function(self,var) event.EventTracker[var]=nil end,
+ trackerExist=function(self,tag) return event.EventTracker[tag]~=nil end,
+ updateTracker=function(self,tag,val) if event:trackerExist(tag) then event.EventTracker[tag]=val end end,
+ alarmExist=function(self,tag) return (event:getTracker("_Alarm_"..tag)~=nil) end,
+ new=function(self,fname,condition,also) if not(also) then also="" end table.insert(self.Events,"if "..condition.." then "..also.." "..fname.." end") table.insert(event.tag,fname) end,
+ eventExist=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then return true end end return false end,
+ destroy=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then table.remove(event.tag,j) table.remove(event.Events,j) end end end,
+ Stop=function() event.Active=false end,
+ OnCreate=function() end,
+ OnUpdate=function() end,
+ OnClose=function() end,
+ getActive=function() return event.tag end,
+ Manager=function() event.OnCreate() while event.Active==true do event.DO_Order() end event.OnClose() end,
+ --Manager=function() event.OnCreate() while event.Active==true do for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end event.OnClose() end,
+ CManager=function() for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end,
+ UManager=function() if event.CT==false then event.CT=true event.OnCreate() end for d=1,#event.Events do if event.Active==true then assert(loadstring(event.Events[d]))() end end for s_g=1,#event.Steps do event.Steps[s_g]:Step() end event.OnUpdate() end,
+ createStep=function(self,tag,reset,skip,endc)
+ if not(endc) then endc=false end
+ temp=
+ {
+ Name=tag,
+ pos=1,
+ endAt=reset or math.huge,
+ active=true,
+ endc=endc,
+ skip=skip or 0,
+ spos=0,
+ Step=function(self) if self~=nil then if self.spos==0 then _G.__CStep__=self if self.active==true then assert(loadstring("Step_"..tag.."("..self.pos..",__CStep__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("Step_"..self.Name.."_End(__CStep__)"))() end end end self.spos=self.spos+1 if self.spos>=self.skip then self.spos=0 end end,
+ FStep=function(self) if self~=nil then if self.spos==0 then _G.__CStep__=self assert(loadstring("Step_"..tag.."("..self.pos..",__CStep__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("Step_"..self.Name.."_End(__CStep__)"))() end end self.spos=self.spos+1 if self.spos>=self.skip then self.spos=0 end end,
+ Remove=function(self) for as=1,#event.Steps do if event.Steps[as].Name==self.Name then table.remove(event.Steps,as) end end end,
+ Reset=function(self) self.pos=1 end,
+ Set=function(self,amt) self.pos=amt end,
+ Pause=function(self) self.active=false end,
+ Resume=function(self) self.active=true end,
+ Stop=function(self) self:Reset() self:Pause() end,
+ Start=function(self) self:Resume() end,
+ End=function(self) self.pos=self.EndAt self.endc=true end,
+ }
+ table.insert(event.Steps,temp) return temp end,
+ createTStep=function(self,tag,reset,timer,endc)
+ if not(endc) then endc=false end
+ timer=timer or 1
+ temp=
+ {
+ Name=tag,
+ pos=1,
+ endAt=reset or math.huge,
+ active=true,
+ endc=endc,
+ skip= 0,
+ spos=0,
+ Step=function(self) if self~=nil then if self.spos==0 then _G.__CStep__=self if self.active==true then assert(loadstring("TStep_"..tag.."("..self.pos..",__CStep__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("TStep_"..self.Name.."_End(__CStep__)"))() end end end self.spos=self.spos+1 if self.spos>=self.skip then self.spos=0 end end,
+ FStep=function(self) if self~=nil then if self.spos==0 then _G.__CStep__=self assert(loadstring("TStep_"..tag.."("..self.pos..",__CStep__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("TStep_"..self.Name.."_End(__CStep__)"))() end end self.spos=self.spos+1 if self.spos>=self.skip then self.spos=0 end end,
+ Remove=function(self) for as=1,#event.Steps do if event.Steps[as].Name==self.Name then table.remove(event.Steps,as) end end end,
+ Reset=function(self) self.pos=1 end,
+ Set=function(self,amt) self.pos=amt end,
+ Pause=function(self) self.active=false end,
+ Resume=function(self) self.active=true end,
+ Stop=function(self) self:Reset() self:Pause() end,
+ Start=function(self) self:Resume() end,
+ End=function(self) self.pos=self.EndAt self.endc=true end,
+ }
+ event:setAlarm("TStep_"..tag,timer)
+ event:addTracker("_TStep_"..tag,temp)
+ table.insert(event.TSteps,temp)
+ assert(loadstring("function Alarm_TStep_"..tag.."(alarm) event:getTracker(\"_\"..alarm):Step() event:setAlarm(alarm,"..timer..") end"))()
+ return temp end,
+ stepExist=function(self,tag)
+ for a_s=1,#event.Steps do
+ if event.Steps[a_s].Name==tag then
+ return true
+ end
+ end
+ return false
+ end,
+}
diff --git a/oldversions/EventManager(1.2.0).lua b/oldversions/EventManager(1.2.0).lua
new file mode 100644
index 0000000..25d8f49
--- /dev/null
+++ b/oldversions/EventManager(1.2.0).lua
@@ -0,0 +1,203 @@
+function dump(t,indent)
+ local names = {}
+ if not indent then indent = "" end
+ for n,g in pairs(t) do
+ table.insert(names,n)
+ end
+ table.sort(names)
+ for i,n in pairs(names) do
+ local v = t[n]
+ if type(v) == "table" then
+ if(v==t) then -- prevent endless loop if table contains reference to itself
+ print(indent..tostring(n)..": <-")
+ else
+ print(indent..tostring(n)..":")
+ dump(v,indent.." ")
+ end
+ else
+ if type(v) == "function" then
+ print(indent..tostring(n).."()")
+ else
+ print(indent..tostring(n)..": "..tostring(v))
+ end
+ end
+ end
+end
+function SetCounter()
+ return os.clock()
+end
+----------------------------------------------------------------------------------------------------
+function GetCounter(count)
+ if count~=nil then
+ return os.clock()-count
+ else
+ return 0
+ end
+end
+----------------------------------------------------------------------------------------------------
+clock=os.clock
+event={
+ Active=true,
+ CT=false,
+ tag={},
+ Events={},
+ Alarms={},
+ EventTracker={},
+ Steps={},
+ TSteps={},
+ CTask="",
+ LoadOrder="/E/S/A/U",
+ UpdateObj=
+ {
+ LoadOrder="",
+ Resume=function(self) event.LoadOrder=self.LoadOrder end,
+ Pause=function(self) self.LoadOrder=event.LoadOrder event.LoadOrder=event.LoadOrder:gsub("/U", "") end,
+ },
+ setLoadOrder=function(self,str) event.LoadOrder=string.upper(str) end,
+ DO_Order=function() LoadOrder=event.LoadOrder LoadOrder=LoadOrder:gsub("/A", "event.RUN_ALARMS(); ") LoadOrder=LoadOrder:gsub("/E", "event.RUN_EVENTS(); ") LoadOrder=LoadOrder:gsub("/S", "event.RUN_STEPS(); ") LoadOrder=LoadOrder:gsub("/U", "event.RUN_UPDATES(); ") assert(loadstring(LoadOrder))() end,
+ RUN_EVENTS=function() event.CTask="events" for d=1,#event.Events do assert(loadstring(event.Events[d]))() end end,
+ RUN_STEPS=function() event.CTask="steps" for s_g=1,#event.Steps do event.Steps[s_g]:Step() end end,
+ RUN_UPDATES=function() _G.__CAction__=event.UpdateObj event.CTask="updates" event.OnUpdate() end,
+ RUN_ALARMS=function() for i=1,#event.Alarms do event.Alarms[i]:Tick() end end,
+ --System Used Functions
+ Hold=function(self,task) -- as many conditions and times that you want can be used
+ local action=__CAction__
+ action:Pause()
+ if type(task)=="number" then
+ local func=function() end
+ local alarm=event:newAlarm(task,func,true)
+ while alarm.active==true do
+ event.CManager()
+ end
+ alarm:Destroy()
+ action:Resume()
+ elseif type(task)=="string" then
+ assert(loadstring("while not("..task..") do event.CManager() end"))()
+ action:Resume()
+ end
+ end,
+ newAlarm=function(self,set,func,start)
+ if not(start) then timer=0 active=false else timer=clock() active=true end
+ if not(func) then func=(function() end) end
+ Alarm=
+ {
+ active=active,
+ timer=timer,
+ set=set or 0,
+ func=func,
+ Tick=function(self) _G.__CAction__=self if self.active==true then if clock()-self.timer>=self.set then self:Pause() self:Ring() end end end,
+ Pause=function(self) self.active=false end,
+ Set=function(self,amt) self.set=amt self.timer=clock() self:Resume() end,
+ OnRing=function(self,func) self.func=func end,
+ Ring=function(self) self:func(self) end,
+ Reset=function(self) self.timer=clock() self:Resume() end,
+ Resume=function(self) self.active=true end,
+ Destroy=function(self) for i=1,#event.Alarms do if tostring(event.Alarms[i])==tostring(self) then table.remove(event.Alarms,i) end end end,
+ }
+ table.insert(event.Alarms,Alarm)
+ return Alarm
+ end,
+ setAlarm=function(self,tag,set)
+ if event:eventExist("Alarm_"..tag.."(\""..tag.."\")")==false then
+ event:new("Alarm_"..tag.."(\""..tag.."\")",[[GetCounter(event:getTracker("_Alarm_]]..tag..[["))>=]]..set,[[event:removeAlarm("]]..tag..[[")]])
+ event:addTracker("_Alarm_"..tag,SetCounter())
+ assert(loadstring("if Alarm_"..tag.."==nil then function Alarm_"..tag.."() print('No function \"Alarm_"..tag.."()\" exists make sure you created it') end end"))()
+ else
+ event:addTracker("_Alarm_"..tag,SetCounter())
+ end
+ end,
+ setEvent=function(self,fname,condition,also) if not(string.find(fname,"(",1,true)) and not(string.find(fname,")",1,true)) then fname=fname.."()" end a=string.find(fname,"(",1,true) tempstr=string.sub(fname,1,a-1) event:new("Event_"..fname,condition,also) assert(loadstring("if Event_"..tempstr.."==nil then function Event_"..tempstr.."() print('No function \"Event_"..tempstr.."()\" exists make sure you created it') end end"))() end,
+ removeAlarm=function(self,tag) event:destroyEvent("Alarm_"..tag) event:removeTracker("_Alarm_"..tag) end,
+ updateAlarm=function(self,tag,set) event:removeAlarm(tag) event:setAlarm(tag,set) end,
+ addTracker=function(self,varname,var) event.EventTracker[varname]=var end,
+ getTracker=function(self,varname) return event.EventTracker[varname] end,
+ listTrackers=function(self) return event.EventTracker end,
+ removeTracker=function(self,var) event.EventTracker[var]=nil end,
+ trackerExist=function(self,tag) return event.EventTracker[tag]~=nil end,
+ updateTracker=function(self,tag,val) if event:trackerExist(tag) then event.EventTracker[tag]=val end end,
+ alarmExist=function(self,tag) return (event:getTracker("_Alarm_"..tag)~=nil) end,
+ new=function(self,fname,condition,also) if not(also) then also="" end table.insert(self.Events,"if "..condition.." then "..also.." "..fname.." end") table.insert(event.tag,fname) end,
+ eventExist=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then return true end end return false end,
+ destroyEvent=function(self,tag) for j=1,#event.tag do if event.tag[j]==tag then table.remove(event.tag,j) table.remove(event.Events,j) end end end,
+ Stop=function() event.Active=false end,
+ OnCreate=function() end,
+ OnUpdate=function() end,
+ OnClose=function() end,
+ getActive=function() return event.tag end,
+ Manager=function() event.OnCreate() while event.Active==true do event.DO_Order() end event.OnClose() end,
+ CManager=function() if event.Active==true then event.DO_Order() end end,
+ UManager=function() if event.CT==false then event.CT=true event.OnCreate() end if event.Active==true then event.DO_Order() end end,
+ createStep=function(self,tag,reset,skip,endc)
+ if not(endc) then
+ endc=false
+ end
+ temp=
+ {
+ Name=tag,
+ pos=1,
+ endAt=reset or math.huge,
+ active=true,
+ endc=endc,
+ skip=skip or 0,
+ spos=0,
+ Step=function(self) if self~=nil then if self.spos==0 then _G.__CAction__=self if self.active==true then assert(loadstring("Step_"..tag.."("..self.pos..",__CAction__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("Step_"..self.Name.."_End(__CAction__)"))() end end end self.spos=self.spos+1 if self.spos>=self.skip then self.spos=0 end end,
+ FStep=function(self) if self~=nil then if self.spos==0 then _G.__CAction__=self assert(loadstring("Step_"..tag.."("..self.pos..",__CAction__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("Step_"..self.Name.."_End(__CAction__)"))() end end self.spos=self.spos+1 if self.spos>=self.skip then self.spos=0 end end,
+ Remove=function(self) for as=1,#event.Steps do if event.Steps[as].Name==self.Name then table.remove(event.Steps,as) end end end,
+ Reset=function(self) self.pos=1 end,
+ Set=function(self,amt) self.pos=amt end,
+ Pause=function(self) self.active=false end,
+ Resume=function(self) self.active=true end,
+ Stop=function(self) self:Reset() self:Pause() end,
+ Start=function(self) self:Resume() end,
+ End=function(self) _G.__CAction__=self assert(loadstring("Step_"..self.Name.."_End(__CAction__)"))() self:Reset() end,
+ }
+ table.insert(event.Steps,temp) return temp
+ end,
+ createTStep=function(self,tag,reset,timer,endc)
+ if not(endc) then
+ endc=false
+ end
+ timer=timer or 1
+ temp=
+ {
+ Name=tag,
+ pos=1,
+ endAt=reset or math.huge,
+ active=true,
+ endc=endc,
+ skip= 0,
+ spos=0,
+ Step=function(self) if self~=nil then if self.spos==0 then _G.__CAction__=self if self.active==true then assert(loadstring("TStep_"..tag.."("..self.pos..",__CAction__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("TStep_"..self.Name.."_End(__CAction__)"))() end end end self.spos=self.spos+1 if self.spos>=self.skip then self.spos=0 end end,
+ FStep=function(self) if self~=nil then if self.spos==0 then _G.__CAction__=self assert(loadstring("TStep_"..tag.."("..self.pos..",__CAction__)"))() self.pos=self.pos+1 end end if self.endAt+1<=self.pos then self:Reset() if endc==true then assert(loadstring("TStep_"..self.Name.."_End(__CAction__)"))() end end self.spos=self.spos+1 if self.spos>=self.skip then self.spos=0 end end,
+ Remove=function(self) for as=1,#event.Steps do if event.Steps[as].Name==self.Name then table.remove(event.Steps,as) end end end,
+ Reset=function(self) self.pos=1 end,
+ Set=function(self,amt) self.pos=amt end,
+ Pause=function(self) self.active=false end,
+ Resume=function(self) self.active=true end,
+ Stop=function(self) self:Reset() self:Pause() end,
+ Start=function(self) self:Resume() end,
+ End=function(self) self.pos=self.EndAt self.endc=true end,
+ }
+ event:setAlarm("TStep_"..tag,timer)
+ event:addTracker("_TStep_"..tag,temp)
+ table.insert(event.TSteps,temp)
+ assert(loadstring("function Alarm_TStep_"..tag.."(alarm) event:getTracker(\"_\"..alarm):Step() event:updateAlarm(alarm,"..timer..") end"))()
+ return temp
+ end,
+ stepExist=function(self,tag)
+ for a_s=1,#event.Steps do
+ if event.Steps[a_s].Name==tag then
+ return true
+ end
+ end
+ return false
+ end,
+ tstepExist=function(self,tag)
+ for a_s=1,#event.TSteps do
+ if event.TSteps[a_s].Name==tag then
+ return true
+ end
+ end
+ return false
+ end,
+}
diff --git a/oldversions/EventManager(1.3.0).lua b/oldversions/EventManager(1.3.0).lua
new file mode 100644
index 0000000..a51a84f
--- /dev/null
+++ b/oldversions/EventManager(1.3.0).lua
@@ -0,0 +1,728 @@
+function readonlytable(table)
+ return setmetatable({}, {
+ __index = table,
+ __newindex = function(table, key, value)
+ error("Attempt to modify read-only table")
+ end,
+ __metatable = false
+ });
+end
+local EventRef=
+readonlytable{
+ Pause=function(self)
+ self.active=false
+ if not(event.isPaused(self)) then
+ table.insert(event.Paused,self)
+ for _j=1,#event.Mainloop do
+ if tostring(event.Mainloop[_j])==tostring(self) then
+ table.remove(event.Mainloop,_j)
+ end
+ end
+ end
+ end,
+ Resume=function(self)
+ self.active=true
+ if event.isPaused(self) then
+ table.insert(event.Mainloop,self)
+ for _j=1,#event.Paused do
+ if tostring(event.Paused[_j])==tostring(self) then
+ table.remove(event.Paused,_j)
+ end
+ end
+ end
+ end,
+ Stop=function(self)
+ self.active=nil
+ end,
+}
+
+local StepRef=
+readonlytable{
+ Step=function(self)
+ if self~=nil then
+ if self.spos==0 then
+ _G.__CAction__=self
+ if self.active==true then
+ for i=1,#self.steps do
+ self.steps[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ end
+ end
+ if self.endAt+self.count<=self.pos and self.endAt>self.start then
+ self:Reset()
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ elseif self.pos<=0 then
+ self:Reset()
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end,
+ FStep=function(self)
+ if self~=nil then
+ if self.spos==0 then
+ _G.__CAction__=self
+ for i=1,#self.steps do
+ self.steps[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ end
+ if self.endAt+self.count<=self.pos and self.endAt>self.start then
+ self:Reset()
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ elseif self.pos==0 then
+ self:Reset()
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for as=1,#event.Mainloop do
+ if tostring(event.Mainloop[as])==tostring(self) then
+ table.remove(event.Mainloop,as)
+ end
+ end
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ Reset=function(self)
+ self.pos=self.start
+ end,
+ Set=function(self,amt)
+ self.pos=amt
+ end,
+ Pause=EventRef.Pause,
+ Resume=EventRef.Resume,
+ Stop=function(self)
+ self:Reset()
+ self.active=nil
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ end,
+ End=function(self)
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ self:Reset()
+ end,
+ Update=function(self,start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end,
+ OnEnd=function(self,func)
+ table.insert(self.funcs,func)
+ end,
+ OnStep=function(self,func)
+ table.insert(self.steps,func)
+ end,
+ FreeConnections=function(self)
+ self.funcs={}
+ self.steps={}
+ end,
+}
+--thread and run setup
+if love then
+ function love.run()
+ if love.math then
+ love.math.setRandomSeed(os.time())
+ end
+ if love.event then
+ love.event.pump()
+ end
+ if love.load then love.load(arg) end
+ if love.timer then love.timer.step() end
+ local dt = 0
+ while true do
+ -- Process events.
+ if love.event then
+ love.event.pump()
+ for e,a,b,c,d in love.event.poll() do
+ if e == "quit" then
+ if not love.quit or not love.quit() then
+ if love.audio then
+ love.audio.stop()
+ end
+ return
+ end
+ end
+ love.handlers[e](a,b,c,d)
+ end
+ end
+ if love.timer then
+ love.timer.step()
+ dt = love.timer.getDelta()
+ end
+ if love.update then love.update(dt) end
+ event.uManager(dt)
+ if love.window and love.graphics and love.window.isCreated() then
+ love.graphics.clear()
+ love.graphics.origin()
+ if love.draw then love.draw() end
+ event.dManager()
+ love.graphics.setColor(255,255,255,255)
+ if event.draw then event.draw() end
+ love.graphics.present()
+ end
+ end
+ end
+end
+eThreads={
+ send=function() end,
+
+
+
+
+}
+function RunTasks()
+ for i=1,#event.DoTasks do
+ event.DoTasks[i]()
+ end
+end
+event={
+ VERSION="1.0.0 (Build Version: 5.7.3)",
+ Priority_Core=1,
+ Priority_High=2,
+ Priority_Above_Normal=4,
+ Priority_Normal=16,
+ Priority_Low=256,
+ Priority_Idle=65536,
+ Start=0,
+ Active=true,
+ CT=false,
+ Tasks={},
+ DoTasks={},
+ garbage={},
+ Paused={},
+ last={},
+ func={},
+ drawF={},
+ pump=false,
+ pumpvar=0,
+ Mainloop={},
+ PEnabled=true,
+ PCount=1,
+ Triggers={},
+ oneTimeObj=
+ {
+ last={},
+ Resume=function(self) end,
+ Pause=function(self) end,
+ },
+ RemoveAll=function()
+ event.Mainloop={}
+ end,
+ GarbageObj=
+ {
+ Resume=function() end,
+ Pause=function() end
+ },
+ isPaused=function(obj)
+ for _j=1,#event.Paused do
+ if tostring(event.Paused[_j])==tostring(obj) then
+ return true
+ end
+ end
+ return false
+ end,
+ DO_Order=function()
+ event.oneTime(RunTasks)
+ event.PCount=event.PCount+1
+ for i=1,#event.Mainloop do
+ if event.Mainloop[i]~=nil then
+ local obj = event.Mainloop[i]
+ if event.PCount%obj.Priority==0 and event.PEnabled then
+ obj:Act()
+ elseif event.PEnabled==false then
+ obj:Act()
+ end
+ if event.PCount>event.Priority_Idle then
+ event.PCount=event.Priority_Core
+ end
+ end
+ end
+ event.MANAGE_GARBAGE()
+ end,
+ MANAGE_GARBAGE=function()
+ _G.__CAction__=event.GarbageObj
+ for _i=1,#event.garbage do
+ event.garbage[_i]:Remove()
+ table.remove(event.garbage,_i)
+ end
+ end,
+ oneTime=function(func)
+ event.oneTimeObj.last=_G.__CAction__
+ _G.__CAction__=event.oneTimeObj
+ for _k=1,#event.Tasks do
+ if event.Tasks[_k]==func then
+ _G.__CAction__=event.oneTimeObj.last
+ return false
+ end
+ end
+ table.insert(event.Tasks,func)
+ func()
+ _G.__CAction__=event.oneTimeObj.last
+ return true
+ end,
+ oneETime=function(func)
+ for _k=1,#event.Tasks do
+ if event.Tasks[_k]==string.dump(func) then
+ return false
+ end
+ end
+ table.insert(event.Tasks,string.dump(func))
+ func()
+ return true
+ end,
+ hold=function(task) -- as many conditions and times that you want can be used
+ local action=__CAction__
+ action:Pause()
+ if type(task)=="number" then
+ local alarm=event.newAlarm(task,function() end,true)
+ while alarm.active==true do
+ if love then
+ event.lManager()
+ else
+ event.cManager()
+ end
+ end
+ alarm:Remove()
+ action:Resume()
+ elseif type(task)=="function" then
+ local env=event.newEvent(task,function(envt) envt:Pause() envt:Stop() end)
+ while env.active do
+ if love then
+ event.lManager()
+ else
+ event.cManager()
+ end
+ end
+ env:Remove()
+ action:Resume()
+ else
+ print("Error Data Type!!!")
+ end
+ end,
+ waitFor=function(obj)
+ local obj=obj
+ event.hold(function() return not(obj.active) end)
+ end,
+ getType=function(obj)
+ if obj.Type~=nil then
+ return obj.Type
+ end
+ end,
+ newEvent=function(test,task)
+ temp=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ Parent=event.Events,
+ Type="Event",
+ active=true,
+ test=test or (function() end),
+ task={task} or {},
+ Act=function(self)
+ _G.__CAction__=self
+ if self:test(self)==true then
+ self:Pause()
+ self:Stop()
+ for i=1,#self.task do
+ self.task[i](self)
+ end
+ end
+ end,
+ Reset=function(self) self:Resume() end,
+ Stop=EventRef.Stop,
+ Pause=EventRef.Pause,
+ Resume=EventRef.Resume,
+ OnEvent=function(self,func)
+ table.insert(self.task,func)
+ end,
+ FreeConnections=function(self)
+ self.task={}
+ end,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for i=1,#event.Mainloop do
+ if tostring(event.Mainloop[i])==tostring(self) then
+ table.remove(event.Mainloop,i)
+ end
+ end
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ }
+ table.insert(event.Mainloop,temp)
+ event.last=temp
+ return temp
+ end,
+ newAlarm=function(set,func,start)
+ if not(start) then
+ timer=0
+ active=false
+ else
+ timer=os.clock()
+ active=true
+ end
+ if not(func) then
+ func=(function() end)
+ end
+ Alarm=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ Parent=event.Alarms,
+ Type="Alarm",
+ active=active,
+ timer=timer,
+ set=set or 0,
+ func={func},
+ Act=function(self)
+ _G.__CAction__=self
+ if self.active==true then
+ if os.clock()-self.timer>=self.set then
+ self:Pause()
+ self:Stop()
+ self:Ring()
+ end
+ end
+ end,
+ FreeConnections=function(self)
+ self.func={}
+ end,
+ Stop=EventRef.Stop,
+ Pause=EventRef.Pause,
+ Set=function(self,amt)
+ self.set=amt
+ self.timer=os.clock()
+ self:Resume()
+ end,
+ OnRing=function(self,func)
+ table.insert(self.func,func)
+ end,
+ Ring=function(self)
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end,
+ Reset=function(self)
+ self.timer=os.clock()
+ self:Resume()
+ end,
+ Resume=EventRef.Resume,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for i=1,#event.Mainloop do
+ if tostring(event.Mainloop[i])==tostring(self) then
+ table.remove(event.Mainloop,i)
+ end
+ end
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ }
+ table.insert(event.Mainloop,Alarm)
+ event.last=temp
+ return Alarm
+ end,
+ newTask=function(func)
+ table.insert(event.DoTasks,func)
+ end,
+ createLoop=function()
+ temp=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ Parent=event.Loops,
+ Type="Loop",
+ active=true,
+ func={},
+ OnLoop=function(self,func)
+ table.insert(self.func,func)
+ end,
+ Stop=EventRef.Stop,
+ Pause=EventRef.Pause,
+ Resume=EventRef.Resume,
+ Act=function(self)
+ _G.__CAction__=self
+ for i=1,#self.func do
+ self.func[i](os.clock()-event.Start,self)
+ end
+ end,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for i=1,#event.Mainloop do
+ if tostring(event.Mainloop[i])==tostring(self) then
+ table.remove(event.Mainloop,i)
+ end
+ end
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ FreeConnections=function(self)
+ self.func={}
+ end,
+ }
+ table.insert(event.Mainloop,temp)
+ event.last=temp
+ return temp
+ end,
+ createStep=function(start,reset,count,skip)
+ think=1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ if not(endc) then
+ endc=false
+ end
+ temp=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ start=start or 1,
+ Parent=event.Steps,
+ Type="Step",
+ pos=start or 1,
+ endAt=reset or math.huge,
+ active=true,
+ skip=skip or 0,
+ spos=0,
+ count=count or 1*think,
+ funcs={},
+ steps={},
+ Act=StepRef.Step,
+ FAct=StepRef.FStep,
+ Remove=StepRef.Remove,
+ Reset=StepRef.Reset,
+ Set=StepRef.Set,
+ Pause=StepRef.Pause,
+ Resume=StepRef.Resume,
+ Stop=StepRef.Stop,
+ End=StepRef.End,
+ Update=StepRef.Update,
+ OnEnd=StepRef.OnEnd,
+ OnStep=StepRef.OnStep,
+ FreeConnections=StepRef.FreeConnections
+ }
+ table.insert(event.Mainloop,temp)
+ event.last=temp
+ return temp
+ end,
+ createTStep=function(start,reset,timer,count)
+ think=1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ if not(endc) then
+ endc=false
+ end
+ timer=timer or 1
+ local _alarm=event.newAlarm(timer,function(alarm) alarm.Link:Act() alarm:Reset() end,true)
+ temp=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ start=start or 1,
+ Parent=event.TSteps,
+ Type="TStep",
+ pos=start or 1,
+ endAt=reset or math.huge,
+ active=true,
+ skip= 0,
+ spos=0,
+ count=count or 1*think,
+ funcs={},
+ steps={},
+ alarm=_alarm,
+ Act=StepRef.Step,
+ FAct=StepRef.FStep,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for as=1,#event.Mainloop do
+ if tostring(event.Mainloop[as])==tostring(self) then
+ table.remove(event.Mainloop,as)
+ end
+ end
+ self.alarm:Remove()
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ Reset=StepRef.Reset,
+ Set=StepRef.Set,
+ Pause=StepRef.Pause,
+ Resume=StepRef.Resume,
+ Stop=StepRef.Stop,
+ End=StepRef.End,
+ Update=function(self,start,reset,timer,count)
+ if start~=nil and reset~=nil then
+ if start>reset then
+ if not(count<0) then
+ print("less")
+ count=-count
+ end
+ end
+ end
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ if timer~=nil then
+ self.alarm:Set(timer)
+ end
+ self.count=count or self.count
+ self.pos=self.start
+ self:Resume()
+ end,
+ OnEnd=StepRef.OnEnd,
+ OnStep=StepRef.OnStep,
+ FreeConnections=StepRef.FreeConnections
+ }
+ _alarm.Link=temp
+ event.last=temp
+ return temp
+ end,
+ createTrigger=function(func)
+ temp={
+ active=true,
+ trigfunc=func,
+ Remove=function(self)
+ for i=1,#event.Triggers do
+ if event.Triggers[i]==self then
+ table.remove(event.Triggers,i)
+ end
+ end
+ end,
+ Pause=function(self) self.active=false end,
+ Resume=function(self) self.active=true end,
+ Fire=function(self,...)
+ if self.active==true then
+ local tempA=__CAction__
+ __CAction__=self
+ self:trigfunc(...)
+ __CAction__=tempA
+ end
+ end,
+ }
+ table.insert(event.Triggers,temp)
+ return temp
+ end,
+ stop=function()
+ event.Active=false
+ end,
+ onStart=function() end,
+ onUpdate=function(func)
+ local temp=event.createLoop()
+ temp:OnLoop(func)
+ temp.Priority=1
+ end,
+ onDraw=function(func)
+ table.insert(event.drawF,func)
+ end,
+ onClose=function() end,
+ manager=function()
+ if not(love) then
+ event.onStart()
+ event.Start=os.clock()
+ while event.Active==true do
+ event.DO_Order()
+ end
+ event.onClose()
+ return os.clock()-event.Start
+ else
+ return false
+ end
+ end,
+ cManager=function()
+ if event.Active==true then
+ event.DO_Order()
+ end
+ end,
+ uManager=function(dt)
+ if event.CT==false then
+ if dt then
+ event.pump=true
+ end
+ event.CT=true
+ event.onStart()
+ event.Start=os.clock()
+ end
+ event.pumpvar=dt
+ if event.Active==true then
+ event.DO_Order()
+ end
+ end,
+ dManager=function()
+ for ii=1,#event.drawF do
+ event.drawF[ii]()
+ end
+ end,
+ lManager=function()
+ if love.event then
+ love.event.pump()
+ for e,a,b,c,d in love.event.poll() do
+ if e == "quit" then
+ if not love.quit or not love.quit() then
+ if love.audio then
+ love.audio.stop()
+ end
+ return
+ end
+ end
+ love.handlers[e](a,b,c,d)
+ end
+ end
+ if love.timer then
+ love.timer.step()
+ dt = love.timer.getDelta()
+ end
+ if love.update then love.update(dt) end
+ event.uManager(dt)
+ if love.window and love.graphics and love.window.isCreated() then
+ love.graphics.clear()
+ love.graphics.origin()
+ if love.draw then love.draw() end
+ event.dManager()
+ love.graphics.present()
+ end
+ end,
+ benchMark=function(sec,p)
+ p=p or event.Priority_Normal
+ local temp=event.createStep(10)
+ temp.CC=0
+ temp:OnStep(function(pos,step) step.CC=step.CC+1 end)
+ local Loud=event.newAlarm(sec,nil,true)
+ Loud.Link=temp
+ Loud:OnRing(function(alarm) print((alarm.Link.CC).." steps in "..alarm.set.." second(s)") end)
+ temp.Priority=p
+ Loud.Priority=p
+ return Loud
+ end,
+}
diff --git a/oldversions/EventManager(5.7.3).lua b/oldversions/EventManager(5.7.3).lua
new file mode 100644
index 0000000..a51a84f
--- /dev/null
+++ b/oldversions/EventManager(5.7.3).lua
@@ -0,0 +1,728 @@
+function readonlytable(table)
+ return setmetatable({}, {
+ __index = table,
+ __newindex = function(table, key, value)
+ error("Attempt to modify read-only table")
+ end,
+ __metatable = false
+ });
+end
+local EventRef=
+readonlytable{
+ Pause=function(self)
+ self.active=false
+ if not(event.isPaused(self)) then
+ table.insert(event.Paused,self)
+ for _j=1,#event.Mainloop do
+ if tostring(event.Mainloop[_j])==tostring(self) then
+ table.remove(event.Mainloop,_j)
+ end
+ end
+ end
+ end,
+ Resume=function(self)
+ self.active=true
+ if event.isPaused(self) then
+ table.insert(event.Mainloop,self)
+ for _j=1,#event.Paused do
+ if tostring(event.Paused[_j])==tostring(self) then
+ table.remove(event.Paused,_j)
+ end
+ end
+ end
+ end,
+ Stop=function(self)
+ self.active=nil
+ end,
+}
+
+local StepRef=
+readonlytable{
+ Step=function(self)
+ if self~=nil then
+ if self.spos==0 then
+ _G.__CAction__=self
+ if self.active==true then
+ for i=1,#self.steps do
+ self.steps[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ end
+ end
+ if self.endAt+self.count<=self.pos and self.endAt>self.start then
+ self:Reset()
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ elseif self.pos<=0 then
+ self:Reset()
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end,
+ FStep=function(self)
+ if self~=nil then
+ if self.spos==0 then
+ _G.__CAction__=self
+ for i=1,#self.steps do
+ self.steps[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ end
+ if self.endAt+self.count<=self.pos and self.endAt>self.start then
+ self:Reset()
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ elseif self.pos==0 then
+ self:Reset()
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for as=1,#event.Mainloop do
+ if tostring(event.Mainloop[as])==tostring(self) then
+ table.remove(event.Mainloop,as)
+ end
+ end
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ Reset=function(self)
+ self.pos=self.start
+ end,
+ Set=function(self,amt)
+ self.pos=amt
+ end,
+ Pause=EventRef.Pause,
+ Resume=EventRef.Resume,
+ Stop=function(self)
+ self:Reset()
+ self.active=nil
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ end,
+ End=function(self)
+ for i=1,#self.funcs do
+ self.funcs[i](self)
+ end
+ self:Reset()
+ end,
+ Update=function(self,start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end,
+ OnEnd=function(self,func)
+ table.insert(self.funcs,func)
+ end,
+ OnStep=function(self,func)
+ table.insert(self.steps,func)
+ end,
+ FreeConnections=function(self)
+ self.funcs={}
+ self.steps={}
+ end,
+}
+--thread and run setup
+if love then
+ function love.run()
+ if love.math then
+ love.math.setRandomSeed(os.time())
+ end
+ if love.event then
+ love.event.pump()
+ end
+ if love.load then love.load(arg) end
+ if love.timer then love.timer.step() end
+ local dt = 0
+ while true do
+ -- Process events.
+ if love.event then
+ love.event.pump()
+ for e,a,b,c,d in love.event.poll() do
+ if e == "quit" then
+ if not love.quit or not love.quit() then
+ if love.audio then
+ love.audio.stop()
+ end
+ return
+ end
+ end
+ love.handlers[e](a,b,c,d)
+ end
+ end
+ if love.timer then
+ love.timer.step()
+ dt = love.timer.getDelta()
+ end
+ if love.update then love.update(dt) end
+ event.uManager(dt)
+ if love.window and love.graphics and love.window.isCreated() then
+ love.graphics.clear()
+ love.graphics.origin()
+ if love.draw then love.draw() end
+ event.dManager()
+ love.graphics.setColor(255,255,255,255)
+ if event.draw then event.draw() end
+ love.graphics.present()
+ end
+ end
+ end
+end
+eThreads={
+ send=function() end,
+
+
+
+
+}
+function RunTasks()
+ for i=1,#event.DoTasks do
+ event.DoTasks[i]()
+ end
+end
+event={
+ VERSION="1.0.0 (Build Version: 5.7.3)",
+ Priority_Core=1,
+ Priority_High=2,
+ Priority_Above_Normal=4,
+ Priority_Normal=16,
+ Priority_Low=256,
+ Priority_Idle=65536,
+ Start=0,
+ Active=true,
+ CT=false,
+ Tasks={},
+ DoTasks={},
+ garbage={},
+ Paused={},
+ last={},
+ func={},
+ drawF={},
+ pump=false,
+ pumpvar=0,
+ Mainloop={},
+ PEnabled=true,
+ PCount=1,
+ Triggers={},
+ oneTimeObj=
+ {
+ last={},
+ Resume=function(self) end,
+ Pause=function(self) end,
+ },
+ RemoveAll=function()
+ event.Mainloop={}
+ end,
+ GarbageObj=
+ {
+ Resume=function() end,
+ Pause=function() end
+ },
+ isPaused=function(obj)
+ for _j=1,#event.Paused do
+ if tostring(event.Paused[_j])==tostring(obj) then
+ return true
+ end
+ end
+ return false
+ end,
+ DO_Order=function()
+ event.oneTime(RunTasks)
+ event.PCount=event.PCount+1
+ for i=1,#event.Mainloop do
+ if event.Mainloop[i]~=nil then
+ local obj = event.Mainloop[i]
+ if event.PCount%obj.Priority==0 and event.PEnabled then
+ obj:Act()
+ elseif event.PEnabled==false then
+ obj:Act()
+ end
+ if event.PCount>event.Priority_Idle then
+ event.PCount=event.Priority_Core
+ end
+ end
+ end
+ event.MANAGE_GARBAGE()
+ end,
+ MANAGE_GARBAGE=function()
+ _G.__CAction__=event.GarbageObj
+ for _i=1,#event.garbage do
+ event.garbage[_i]:Remove()
+ table.remove(event.garbage,_i)
+ end
+ end,
+ oneTime=function(func)
+ event.oneTimeObj.last=_G.__CAction__
+ _G.__CAction__=event.oneTimeObj
+ for _k=1,#event.Tasks do
+ if event.Tasks[_k]==func then
+ _G.__CAction__=event.oneTimeObj.last
+ return false
+ end
+ end
+ table.insert(event.Tasks,func)
+ func()
+ _G.__CAction__=event.oneTimeObj.last
+ return true
+ end,
+ oneETime=function(func)
+ for _k=1,#event.Tasks do
+ if event.Tasks[_k]==string.dump(func) then
+ return false
+ end
+ end
+ table.insert(event.Tasks,string.dump(func))
+ func()
+ return true
+ end,
+ hold=function(task) -- as many conditions and times that you want can be used
+ local action=__CAction__
+ action:Pause()
+ if type(task)=="number" then
+ local alarm=event.newAlarm(task,function() end,true)
+ while alarm.active==true do
+ if love then
+ event.lManager()
+ else
+ event.cManager()
+ end
+ end
+ alarm:Remove()
+ action:Resume()
+ elseif type(task)=="function" then
+ local env=event.newEvent(task,function(envt) envt:Pause() envt:Stop() end)
+ while env.active do
+ if love then
+ event.lManager()
+ else
+ event.cManager()
+ end
+ end
+ env:Remove()
+ action:Resume()
+ else
+ print("Error Data Type!!!")
+ end
+ end,
+ waitFor=function(obj)
+ local obj=obj
+ event.hold(function() return not(obj.active) end)
+ end,
+ getType=function(obj)
+ if obj.Type~=nil then
+ return obj.Type
+ end
+ end,
+ newEvent=function(test,task)
+ temp=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ Parent=event.Events,
+ Type="Event",
+ active=true,
+ test=test or (function() end),
+ task={task} or {},
+ Act=function(self)
+ _G.__CAction__=self
+ if self:test(self)==true then
+ self:Pause()
+ self:Stop()
+ for i=1,#self.task do
+ self.task[i](self)
+ end
+ end
+ end,
+ Reset=function(self) self:Resume() end,
+ Stop=EventRef.Stop,
+ Pause=EventRef.Pause,
+ Resume=EventRef.Resume,
+ OnEvent=function(self,func)
+ table.insert(self.task,func)
+ end,
+ FreeConnections=function(self)
+ self.task={}
+ end,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for i=1,#event.Mainloop do
+ if tostring(event.Mainloop[i])==tostring(self) then
+ table.remove(event.Mainloop,i)
+ end
+ end
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ }
+ table.insert(event.Mainloop,temp)
+ event.last=temp
+ return temp
+ end,
+ newAlarm=function(set,func,start)
+ if not(start) then
+ timer=0
+ active=false
+ else
+ timer=os.clock()
+ active=true
+ end
+ if not(func) then
+ func=(function() end)
+ end
+ Alarm=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ Parent=event.Alarms,
+ Type="Alarm",
+ active=active,
+ timer=timer,
+ set=set or 0,
+ func={func},
+ Act=function(self)
+ _G.__CAction__=self
+ if self.active==true then
+ if os.clock()-self.timer>=self.set then
+ self:Pause()
+ self:Stop()
+ self:Ring()
+ end
+ end
+ end,
+ FreeConnections=function(self)
+ self.func={}
+ end,
+ Stop=EventRef.Stop,
+ Pause=EventRef.Pause,
+ Set=function(self,amt)
+ self.set=amt
+ self.timer=os.clock()
+ self:Resume()
+ end,
+ OnRing=function(self,func)
+ table.insert(self.func,func)
+ end,
+ Ring=function(self)
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end,
+ Reset=function(self)
+ self.timer=os.clock()
+ self:Resume()
+ end,
+ Resume=EventRef.Resume,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for i=1,#event.Mainloop do
+ if tostring(event.Mainloop[i])==tostring(self) then
+ table.remove(event.Mainloop,i)
+ end
+ end
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ }
+ table.insert(event.Mainloop,Alarm)
+ event.last=temp
+ return Alarm
+ end,
+ newTask=function(func)
+ table.insert(event.DoTasks,func)
+ end,
+ createLoop=function()
+ temp=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ Parent=event.Loops,
+ Type="Loop",
+ active=true,
+ func={},
+ OnLoop=function(self,func)
+ table.insert(self.func,func)
+ end,
+ Stop=EventRef.Stop,
+ Pause=EventRef.Pause,
+ Resume=EventRef.Resume,
+ Act=function(self)
+ _G.__CAction__=self
+ for i=1,#self.func do
+ self.func[i](os.clock()-event.Start,self)
+ end
+ end,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for i=1,#event.Mainloop do
+ if tostring(event.Mainloop[i])==tostring(self) then
+ table.remove(event.Mainloop,i)
+ end
+ end
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ FreeConnections=function(self)
+ self.func={}
+ end,
+ }
+ table.insert(event.Mainloop,temp)
+ event.last=temp
+ return temp
+ end,
+ createStep=function(start,reset,count,skip)
+ think=1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ if not(endc) then
+ endc=false
+ end
+ temp=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ start=start or 1,
+ Parent=event.Steps,
+ Type="Step",
+ pos=start or 1,
+ endAt=reset or math.huge,
+ active=true,
+ skip=skip or 0,
+ spos=0,
+ count=count or 1*think,
+ funcs={},
+ steps={},
+ Act=StepRef.Step,
+ FAct=StepRef.FStep,
+ Remove=StepRef.Remove,
+ Reset=StepRef.Reset,
+ Set=StepRef.Set,
+ Pause=StepRef.Pause,
+ Resume=StepRef.Resume,
+ Stop=StepRef.Stop,
+ End=StepRef.End,
+ Update=StepRef.Update,
+ OnEnd=StepRef.OnEnd,
+ OnStep=StepRef.OnStep,
+ FreeConnections=StepRef.FreeConnections
+ }
+ table.insert(event.Mainloop,temp)
+ event.last=temp
+ return temp
+ end,
+ createTStep=function(start,reset,timer,count)
+ think=1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ if not(endc) then
+ endc=false
+ end
+ timer=timer or 1
+ local _alarm=event.newAlarm(timer,function(alarm) alarm.Link:Act() alarm:Reset() end,true)
+ temp=
+ {
+ Priority=event.Priority_Normal,
+ _Priority=0,
+ start=start or 1,
+ Parent=event.TSteps,
+ Type="TStep",
+ pos=start or 1,
+ endAt=reset or math.huge,
+ active=true,
+ skip= 0,
+ spos=0,
+ count=count or 1*think,
+ funcs={},
+ steps={},
+ alarm=_alarm,
+ Act=StepRef.Step,
+ FAct=StepRef.FStep,
+ Remove=function(self)
+ if self~=_G.__CAction__ then
+ for as=1,#event.Mainloop do
+ if tostring(event.Mainloop[as])==tostring(self) then
+ table.remove(event.Mainloop,as)
+ end
+ end
+ self.alarm:Remove()
+ else
+ table.insert(event.garbage,self)
+ end
+ end,
+ Reset=StepRef.Reset,
+ Set=StepRef.Set,
+ Pause=StepRef.Pause,
+ Resume=StepRef.Resume,
+ Stop=StepRef.Stop,
+ End=StepRef.End,
+ Update=function(self,start,reset,timer,count)
+ if start~=nil and reset~=nil then
+ if start>reset then
+ if not(count<0) then
+ print("less")
+ count=-count
+ end
+ end
+ end
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ if timer~=nil then
+ self.alarm:Set(timer)
+ end
+ self.count=count or self.count
+ self.pos=self.start
+ self:Resume()
+ end,
+ OnEnd=StepRef.OnEnd,
+ OnStep=StepRef.OnStep,
+ FreeConnections=StepRef.FreeConnections
+ }
+ _alarm.Link=temp
+ event.last=temp
+ return temp
+ end,
+ createTrigger=function(func)
+ temp={
+ active=true,
+ trigfunc=func,
+ Remove=function(self)
+ for i=1,#event.Triggers do
+ if event.Triggers[i]==self then
+ table.remove(event.Triggers,i)
+ end
+ end
+ end,
+ Pause=function(self) self.active=false end,
+ Resume=function(self) self.active=true end,
+ Fire=function(self,...)
+ if self.active==true then
+ local tempA=__CAction__
+ __CAction__=self
+ self:trigfunc(...)
+ __CAction__=tempA
+ end
+ end,
+ }
+ table.insert(event.Triggers,temp)
+ return temp
+ end,
+ stop=function()
+ event.Active=false
+ end,
+ onStart=function() end,
+ onUpdate=function(func)
+ local temp=event.createLoop()
+ temp:OnLoop(func)
+ temp.Priority=1
+ end,
+ onDraw=function(func)
+ table.insert(event.drawF,func)
+ end,
+ onClose=function() end,
+ manager=function()
+ if not(love) then
+ event.onStart()
+ event.Start=os.clock()
+ while event.Active==true do
+ event.DO_Order()
+ end
+ event.onClose()
+ return os.clock()-event.Start
+ else
+ return false
+ end
+ end,
+ cManager=function()
+ if event.Active==true then
+ event.DO_Order()
+ end
+ end,
+ uManager=function(dt)
+ if event.CT==false then
+ if dt then
+ event.pump=true
+ end
+ event.CT=true
+ event.onStart()
+ event.Start=os.clock()
+ end
+ event.pumpvar=dt
+ if event.Active==true then
+ event.DO_Order()
+ end
+ end,
+ dManager=function()
+ for ii=1,#event.drawF do
+ event.drawF[ii]()
+ end
+ end,
+ lManager=function()
+ if love.event then
+ love.event.pump()
+ for e,a,b,c,d in love.event.poll() do
+ if e == "quit" then
+ if not love.quit or not love.quit() then
+ if love.audio then
+ love.audio.stop()
+ end
+ return
+ end
+ end
+ love.handlers[e](a,b,c,d)
+ end
+ end
+ if love.timer then
+ love.timer.step()
+ dt = love.timer.getDelta()
+ end
+ if love.update then love.update(dt) end
+ event.uManager(dt)
+ if love.window and love.graphics and love.window.isCreated() then
+ love.graphics.clear()
+ love.graphics.origin()
+ if love.draw then love.draw() end
+ event.dManager()
+ love.graphics.present()
+ end
+ end,
+ benchMark=function(sec,p)
+ p=p or event.Priority_Normal
+ local temp=event.createStep(10)
+ temp.CC=0
+ temp:OnStep(function(pos,step) step.CC=step.CC+1 end)
+ local Loud=event.newAlarm(sec,nil,true)
+ Loud.Link=temp
+ Loud:OnRing(function(alarm) print((alarm.Link.CC).." steps in "..alarm.set.." second(s)") end)
+ temp.Priority=p
+ Loud.Priority=p
+ return Loud
+ end,
+}
diff --git a/oldversions/MultiManager(0.3.0).lua b/oldversions/MultiManager(0.3.0).lua
new file mode 100644
index 0000000..8cd58e3
--- /dev/null
+++ b/oldversions/MultiManager(0.3.0).lua
@@ -0,0 +1,365 @@
+multi = {}
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.Children={}
+multi.Paused={}
+multi.MasterId=0
+multi.Active=true
+multi.Id=-1
+-- System
+function multi:newBase(ins)
+ local c = {}
+ setmetatable(c, multi)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Act=function() end
+ if ins then
+ table.insert(multi.Mainloop,ins,c)
+ else
+ table.insert(multi.Mainloop,c)
+ end
+ multi.MasterId=multi.MasterId+1
+ return c
+end
+function multi:reboot(r)
+ multi.Mainloop={}
+ multi.Tasks={}
+ multi.Tasks2={}
+ multi.Garbage={}
+ multi.Children={}
+ multi.Paused={}
+ multi.MasterId=0
+ multi.Active=true
+ multi.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=="table" then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+end
+--Processor
+function multi.Do_Order()
+ for _D=#multi.Mainloop,1,-1 do
+ if multi.Mainloop[_D]~=nil then
+ multi.Mainloop[_D].Id=_D
+ multi.Mainloop[_D]:Act()
+ end
+ end
+end
+function multi:benchMark(sec)
+ local temp=multi:newStep(2)
+ temp.CC=0
+ temp:OnStep(function(pos,step) step.CC=step.CC+1 end)
+ local Loud=multi:newAlarm(sec)
+ Loud.Link=temp
+ Loud:OnRing(function(alarm) alarm.Link.CC=alarm.Link.CC print((alarm.Link.CC).." steps in "..alarm.set.." second(s)") alarm.bench=alarm.Link.CC alarm.Link:Destroy() alarm:Destroy() end)
+ return Loud
+end
+--Helpers
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:Pause(n)
+ if not(n) then
+ self.Active=false
+ table.remove(multi.Mainloop,self.Id)
+ table.insert(multi.Paused,self)
+ else
+ self:hold(n)
+ end
+end
+function multi:Resume()
+ if self:isPaused() then
+ self.Active=true
+ table.remove(multi.Paused,self.Id)
+ table.insert(multi.Mainloop,self)
+ end
+end
+function multi:Remove()
+ self:Pause()
+ self:Destroy()
+end
+function multi:Destroy()
+ self:Pause()
+ if self:isPaused() then
+ for i=1,#multi.Paused do
+ if multi.Paused[i]==self then
+ table.remove(multi.Paused,i)
+ return
+ end
+ end
+ else
+ table.remove(multi.Mainloop,self.Id)
+ end
+ self.Act=function() end
+end
+function multi:hold(task)
+ self:Pause()
+ if type(task)=="number" then
+ local alarm=multi:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ multi.lManager()
+ else
+ multi.Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ elseif type(task)=="function" then
+ local env=multi:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt:Stop() end)
+ while env.Active do
+ if love then
+ multi.lManager()
+ else
+ multi.Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ else
+ print("Error Data Type!!!")
+ end
+end
+function multi:oneTime(func,...)
+ for _k=1,#multi.Tasks2 do
+ if multi.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(multi.Tasks2,func)
+ func(...)
+ return true
+end
+--Constructors
+function multi:newEvent(task)
+ local c=multi:newBase()
+ c.Type="Event"
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) and self.Active==true then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+function multi:newAlarm(set)
+ local c=multi:newBase()
+ c.Type="Alarm"
+ c.timer=os.clock()
+ c.set=set or 0
+ function c:Act()
+ if self.Active==true then
+ if os.clock()-self.timer>=self.set then
+ self:Pause()
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=os.clock()
+ self:Resume()
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+function multi:newTask(func)
+ table.insert(multi.Tasks,func)
+end
+function multi:newLoop()
+ local c=multi:newBase()
+ c.Type="Loop"
+ function c:Act()
+ if self.Active==true then
+ for i=1,#self.func do
+ self.func[i](os.clock()-multi.Start,self)
+ end
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c=multi:newBase()
+ think=1
+ c.Type="Step"
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.Active==true then
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ c:OnStep(function(p,s)
+ if s.count>0 and s.endAt==p then
+ for fe=1,#s.funcE do
+ s.funcE[fe](s)
+ end
+ s.pos=s.start-1
+ elseif s.count<0 and s.endAt==p then
+ for fe=1,#s.funcE do
+ s.funcE[fe](s)
+ end
+ s.pos=s.start-1
+ end
+ end)
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c=multi:newBase()
+ think=1
+ c.Type="TStep"
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=os.clock()
+ c.set=set or 1
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=os.clock()
+ self:Resume()
+ end
+ function c:Act()
+ if self.Active then
+ if os.clock()-self.timer>=self.set then
+ self:Reset()
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ if self.endAt==self.pos then
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start-1
+ end
+ self.pos=self.pos+self.count
+ end
+ end
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=os.clock()
+ self:Resume()
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+
+function multi:inQueue(func)
+ if self.Id==-1 then
+ print("Error: Can't queue the multi object")
+ return
+ end
+ local c=multi:newBase(self.Id)
+ self.Id=self.Id-1
+ c.Type="Queue"
+ c.Task=func
+ c.Link=self
+ function c:Act()
+ self.Task(self.Link)
+ self:Destroy()
+ end
+end
+function multi:newTrigger(func)
+ local c=multi:newBase()
+ c.Type="Trigger"
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ return c
+end
+--Managers
+function multi:mainloop()
+ for i=1,#multi.Tasks do
+ multi.Tasks[i]()
+ end
+ multi.Start=os.clock()
+ while self.Active do
+ multi.Do_Order()
+ end
+end
+function multi._tFunc(dt)
+ if dt then
+ multi.pump=true
+ end
+ multi.pumpvar=dt
+ multi.Start=os.clock()
+end
+function multi:uManager(dt)
+ multi:oneTime(multi._tFunc,dt)
+ multi.Do_Order()
+end
diff --git a/oldversions/MultiManager(0.4.0-1).lua b/oldversions/MultiManager(0.4.0-1).lua
new file mode 100644
index 0000000..1e38f26
--- /dev/null
+++ b/oldversions/MultiManager(0.4.0-1).lua
@@ -0,0 +1,506 @@
+multi = {}
+multi.Version="4.0.1"
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.Children={}
+multi.Paused={}
+multi.MasterId=0
+multi.Active=true
+multi.Id=-1
+multi.Type="mainint"
+multi.Rest=0
+multi._type=type
+--[[function type(v)
+ local t={}
+ if multi._type(v)=="table" then
+ t=getmetatable(v)
+ if v.Type~=nil then
+ if multi._type(v.Type)=="string" then
+ return v.Type
+ end
+ end
+ end
+ if t.__type~=nil then
+ return t.__type
+ else
+ return multi._type(v)
+ end
+end]]
+-- System
+function os.getOS()
+ if package.config:sub(1,1)=="\\" then
+ return "windows"
+ else
+ return "unix"
+ end
+end
+if os.getOS()=="windows" then
+ function os.sleep(n)
+ if n > 0 then os.execute("ping -n " .. tonumber(n+1) .. " localhost > NUL") end
+ end
+else
+ function os.sleep(n)
+ os.execute("sleep " .. tonumber(n))
+ end
+end
+function multi:newBase(ins)
+ if not(self.Type=="mainint" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end
+ local c = {}
+ if self.Type=="int" then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ self.MasterId=self.MasterId+1
+ return c
+end
+function multi:reboot(r)
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.MasterId=0
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=="table" then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:Do_Order()
+ for _D=#self.Mainloop,1,-1 do
+ if self.Mainloop[_D]~=nil then
+ self.Mainloop[_D].Id=_D
+ self.Mainloop[_D]:Act()
+ end
+ if self.Mainloop[_D]~=nil then
+ if self.Mainloop[_D].rem~=nil then
+ table.remove(self.Mainloop,_D)
+ end
+ end
+ end
+ if self.Rest>0 then
+ os.sleep(self.Rest)
+ end
+end
+function multi:benchMark(sec)
+ local temp=self:newLoop(function(t,self)
+ if os.clock()-self.init>self.sec then
+ print(self.c.." steps in "..self.sec.." second(s)")
+ self.tt(self.sec)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=os.clock()
+ temp.c=0
+ return temp
+end
+function multi:newInterface()
+ if not(self.Type=="mainint") then error("Can only create an interface on the multi obj") return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type="int"
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.MasterId=0
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Stop()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ return c
+end
+--Helpers
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:Pause(n)
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=false
+ if not(n) then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Pause()
+ end
+ else
+ self:hold(n)
+ end
+ else
+ if n==nil then
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ else
+ self:hold(n)
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:Destroy()
+ if self.Type=="int" or self.Type=="mainint" then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Destroy()
+ end
+ else
+ self.rem=true
+ self.Active=false
+ end
+end
+function multi:hold(task)
+ self:Pause()
+ if type(task)=="number" then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ elseif type(task)=="function" then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt:Stop() end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ else
+ print("Error Data Type!!!")
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=="mainint" or self.Type=="int") then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+--Constructors
+function multi:newEvent(task)
+ local c=self:newBase()
+ c.Type="event"
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) and self.Active==true then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+function multi:newAlarm(set)
+ local c=self:newBase()
+ c.Type="alarm"
+ c.timer=os.clock()
+ c.set=set or 0
+ function c:Act()
+ if self.Active==true then
+ if os.clock()-self.timer>=self.set then
+ self:Pause()
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=os.clock()
+ self:Resume()
+ self.Active=true
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newLoop(func)
+ local c=self:newBase()
+ c.Type="loop"
+ if func then
+ c.func={func}
+ end
+ function c:Act()
+ if self.Active==true then
+ for i=1,#self.func do
+ self.func[i](os.clock()-self.Parent.Start,self)
+ end
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c=self:newBase()
+ think=1
+ c.Type="step"
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.Active==true then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c=self:newBase()
+ think=1
+ c.Type="tstep"
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=os.clock()
+ c.set=set or 1
+ c.funcS={}
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=os.clock()
+ self:Resume()
+ end
+ function c:Act()
+ if self.Active then
+ if os.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=os.clock()
+ self:Resume()
+ end
+ return c
+end
+function multi:newTrigger(func)
+ local c=self:newBase()
+ c.Type="trigger"
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ return c
+end
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ self.Start=os.clock()
+ while self.Active do
+ self:Do_Order()
+ end
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ self.Start=os.clock()
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ self:Do_Order()
+ end
+end
diff --git a/oldversions/MultiManager(0.4.0-5).lua b/oldversions/MultiManager(0.4.0-5).lua
new file mode 100644
index 0000000..f17b2cd
--- /dev/null
+++ b/oldversions/MultiManager(0.4.0-5).lua
@@ -0,0 +1,596 @@
+multi = {}
+multi.Version="4.0.5"
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.Children={}
+multi.Paused={}
+multi.MasterId=0
+multi.Active=true
+multi.Id=-1
+multi.Type="mainint"
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+--[[function type(v)
+ local t={}
+ if multi._type(v)=="table" then
+ t=getmetatable(v)
+ if v.Type~=nil then
+ if multi._type(v.Type)=="string" then
+ return v.Type
+ end
+ end
+ end
+ if t.__type~=nil then
+ return t.__type
+ else
+ return multi._type(v)
+ end
+end]]
+-- System
+function os.getOS()
+ if package.config:sub(1,1)=="\\" then
+ return "windows"
+ else
+ return "unix"
+ end
+end
+if os.getOS()=="windows" then
+ function os.sleep(n)
+ if n > 0 then os.execute("ping -n " .. tonumber(n+1) .. " localhost > NUL") end
+ end
+else
+ function os.sleep(n)
+ os.execute("sleep " .. tonumber(n))
+ end
+end
+function multi:newBase(ins)
+ if not(self.Type=="mainint" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end
+ local c = {}
+ if self.Type=="int" then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ self.MasterId=self.MasterId+1
+ return c
+end
+function multi:reboot(r)
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.MasterId=0
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=="table" then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:Do_Order()
+ for _D=#self.Mainloop,1,-1 do
+ if self.Mainloop[_D]~=nil then
+ self.Mainloop[_D].Id=_D
+ self.Mainloop[_D]:Act()
+ end
+ if self.Mainloop[_D]~=nil then
+ if self.Mainloop[_D].rem~=nil then
+ table.remove(self.Mainloop,_D)
+ end
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+end
+function multi:benchMark(sec)
+ local temp=self:newLoop(function(t,self)
+ if os.clock()-self.init>self.sec then
+ print(self.c.." steps in "..self.sec.." second(s)")
+ self.tt(self.sec)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=os.clock()
+ temp.c=0
+ return temp
+end
+function multi:newInterface()
+ if not(self.Type=="mainint") then error("Can only create an interface on the multi obj") return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type="int"
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.MasterId=0
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ c.Jobs={}
+ c.queue={}
+ c.jobUS=2
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Stop()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ return c
+end
+--Helpers
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:Pause(n)
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=false
+ if not(n) then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Pause()
+ end
+ else
+ self:hold(n)
+ end
+ else
+ if n==nil then
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ else
+ self:hold(n)
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:Destroy()
+ if self.Type=="int" or self.Type=="mainint" then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Destroy()
+ end
+ else
+ self.rem=true
+ self.Active=false
+ end
+end
+function multi:hold(task)
+ self:Pause()
+ if type(task)=="number" then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ elseif type(task)=="function" then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt:Stop() end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ else
+ print("Error Data Type!!!")
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=="mainint" or self.Type=="int") then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+--Constructors
+function multi:newEvent(task)
+ local c=self:newBase()
+ c.Type="event"
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) and self.Active==true then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+function multi:newAlarm(set)
+ local c=self:newBase()
+ c.Type="alarm"
+ c.timer=os.clock()
+ c.set=set or 0
+ function c:Act()
+ if self.Active==true then
+ if os.clock()-self.timer>=self.set then
+ self:Pause()
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=os.clock()
+ self:Resume()
+ self.Active=true
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newLoop(func)
+ local c=self:newBase()
+ c.Type="loop"
+ if func then
+ c.func={func}
+ end
+ function c:Act()
+ if self.Active==true then
+ for i=1,#self.func do
+ self.func[i](os.clock()-self.Parent.Start,self)
+ end
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c=self:newBase()
+ think=1
+ c.Type="step"
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.Active==true then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c=self:newBase()
+ think=1
+ c.Type="tstep"
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=os.clock()
+ c.set=set or 1
+ c.funcS={}
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=os.clock()
+ self:Resume()
+ end
+ function c:Act()
+ if self.Active then
+ if os.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=os.clock()
+ self:Resume()
+ end
+ return c
+end
+function multi:newTrigger(func)
+ local c={}--self:newBase()
+ c.Type="trigger"
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ return c
+end
+function multi:newConnection()
+ local c={}
+ c.Type="connector"
+ c.func={}
+ function c:Fire(...)
+ for i=1,#self.func do
+ t,e=pcall(self.func[i],...)
+ if not(t) then
+ print(e)
+ end
+ end
+ end
+ function c:connect(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+function multi:newJob(func,name)
+ if not(self.Type=="mainint" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end
+ local c = {}
+ if self.Type=="int" then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type="job"
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+--Incomplete
+function multi:addToQueue(name,job)
+ if self.queue[name]~=nil then
+ table.insert(self.queue[name],job)
+ else
+ self.queue[name]={}
+ end
+ if self.QRunner==nil then
+ self.QRunner=self:newAlarm(.5)
+ self.QRunner:OnRing(function(self)
+ if #self.Parent.queue>0 then
+ local w=math.random(1,#self.Parent.Jobs)
+ self.Parent.Jobs[w]:Act()
+ table.remove(self.Parent.Jobs,w)
+ end
+ self:Reset()
+ end)
+ end
+end
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ self.Start=os.clock()
+ while self.Active do
+ self:Do_Order()
+ end
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ self.Start=os.clock()
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ self:Do_Order()
+ end
+end
diff --git a/oldversions/MultiManager(0.5.1-6).lua b/oldversions/MultiManager(0.5.1-6).lua
new file mode 100644
index 0000000..8aef936
--- /dev/null
+++ b/oldversions/MultiManager(0.5.1-6).lua
@@ -0,0 +1,767 @@
+multi = {}
+multi.Version="5.1.6"
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.Children={}
+multi.Paused={}
+multi.MasterId=0
+multi.Active=true
+multi.Id=-1
+multi.Type="mainint"
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+-- System
+function multi:Stop()
+ self.Active=false
+end
+function os.getOS()
+ if package.config:sub(1,1)=="\\" then
+ return "windows"
+ else
+ return "unix"
+ end
+end
+if os.getOS()=="windows" then
+ function os.sleep(n)
+ if n > 0 then os.execute("ping -n " .. tonumber(n+1) .. " localhost > NUL") end
+ end
+else
+ function os.sleep(n)
+ os.execute("sleep " .. tonumber(n))
+ end
+end
+function multi:newBase(ins)
+ if not(self.Type=="mainint" or self.Type=="int" or self.Type=="stack") then error("Can only create an object on multi or an interface obj") return false end
+ local c = {}
+ if self.Type=="int" or self.Type=="stack" then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.ender={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ self.MasterId=self.MasterId+1
+ return c
+end
+function multi:reboot(r)
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.MasterId=0
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=="table" then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:getError()
+ if self.error then
+ return self.error
+ end
+end
+function multi:Do_Order()
+ for _D=#self.Mainloop,1,-1 do
+ if self.Mainloop[_D]~=nil then
+ self.Mainloop[_D].Id=_D
+ self.Mainloop[_D]:Act()
+ end
+ if self.Mainloop[_D]~=nil then
+ if self.Mainloop[_D].rem~=nil then
+ table.remove(self.Mainloop,_D)
+ end
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+end
+function multi:benchMark(sec)
+ local temp=self:newLoop(function(t,self)
+ if os.clock()-self.init>self.sec then
+ print(self.c.." steps in "..self.sec.." second(s)")
+ self.tt(self.sec)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=os.clock()
+ temp.c=0
+ return temp
+end
+function multi:newInterface()
+ if not(self.Type=="mainint") then error("Can only create an interface on the multi obj") return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type="int"
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.MasterId=0
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ c.Jobs={}
+ c.queue={}
+ c.jobUS=2
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Stop()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ return c
+end
+function multi:newStack(file)
+ local c=self:newInterface()
+ c.Type="stack"
+ stack=c
+ c.last={}
+ c.funcE={}
+ if file then
+ dofile(file)
+ end
+ function c:OnStackCompleted(func)
+ table.insert(self.funcE,func)
+ end
+ return c
+end
+--Helpers
+function multi:protect()
+ function self:Do_Order()
+ for _D=#self.Mainloop,1,-1 do
+ if self.Mainloop[_D]~=nil then
+ self.Mainloop[_D].Id=_D
+ local status, err=pcall(self.Mainloop[_D].Act,self.Mainloop[_D])
+ if err and not(self.Mainloop[_D].error) then
+ self.Mainloop[_D].error=err
+ print(err..": Ingoring error continuing...")
+ end
+ end
+ if self.Mainloop[_D]~=nil then
+ if self.Mainloop[_D].rem~=nil then
+ table.remove(self.Mainloop,_D)
+ end
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+ end
+end
+function multi:unProtect()
+ function self:Do_Order()
+ for _D=#self.Mainloop,1,-1 do
+ if self.Mainloop[_D]~=nil then
+ self.Mainloop[_D].Id=_D
+ self.Mainloop[_D]:Act()
+ end
+ if self.Mainloop[_D]~=nil then
+ if self.Mainloop[_D].rem~=nil then
+ table.remove(self.Mainloop,_D)
+ end
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+ end
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:connectFinal(func)
+ if self.Type=="event" then
+ self:OnEvent(func)
+ elseif self.Type=="alarm" then
+ self:OnRing(func)
+ elseif self.Type=="step" or self.Type=="tstep" then
+ self:OnEnd(func)
+ elseif self.Type=="loop" then
+ self:OnBreak(func)
+ else
+ error("No final event exists for: "..self.Type)
+ end
+end
+function multi:Break()
+ self:Pause()
+ self.Active=nil
+ for i=1,#self.ender do
+ self.ender[i](self)
+ end
+end
+function multi:OnBreak(func)
+ table.insert(self.ender,func)
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:Pause(n)
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=false
+ if not(n) then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Pause()
+ end
+ else
+ self:hold(n)
+ end
+ else
+ if n==nil then
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ else
+ self:hold(n)
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:Destroy()
+ if self.Type=="int" or self.Type=="mainint" then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Destroy()
+ end
+ else
+ self.rem=true
+ self.Active=false
+ end
+end
+function multi:hold(task)
+ self:Pause()
+ if type(task)=="number" then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ elseif type(task)=="function" then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt:Stop() end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ else
+ print("Error Data Type!!!")
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=="mainint" or self.Type=="int") then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+function multi:Reset(n)
+ self:Resume()
+end
+function multi:isDone()
+ return self.Active~=true
+end
+--Constructors
+function multi:newEvent(task)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="event"
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) and self.Active==true then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newAlarm(set)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="alarm"
+ c.timer=os.clock()
+ c.set=set or 0
+ function c:Act()
+ if self.Active==true then
+ if os.clock()-self.timer>=self.set then
+ self:Pause()
+ self.Active=false
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ end
+ function c:Resume()
+ self.Parent.Resume(self)
+ self.timer=os.clock()
+ self.Active=true
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=os.clock()
+ self:Resume()
+ self.Active=true
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ table.remove(self.Parent.Mainloop,#self.Parent.Mainloop)
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newLoop(func)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="loop"
+ c.Start=os.clock()
+ if func then
+ c.func={func}
+ end
+ function c:Act()
+ if self.Active==true then
+ for i=1,#self.func do
+ self.func[i](os.clock()-self.Start,self)
+ end
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type="step"
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.Active==true then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type="tstep"
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=os.clock()
+ c.set=set or 1
+ c.funcS={}
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=os.clock()
+ self:Resume()
+ end
+ function c:Act()
+ if self.Active then
+ if os.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=os.clock()
+ self:Resume()
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newTrigger(func)
+ local c={}
+ c.Type="trigger"
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ return c
+end
+function multi:newConnection()
+ local c={}
+ c.Type="connector"
+ c.func={}
+ function c:Fire(...)
+ for i=1,#self.func do
+ t,e=pcall(self.func[i],...)
+ if not(t) then
+ print(e)
+ end
+ end
+ end
+ function c:bind(t)
+ self.func=t
+ end
+ function c:connect(func)
+ table.insert(self.func,func)
+ end
+ return c
+end
+function multi:newJob(func,name)
+ if not(self.Type=="mainint" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end
+ local c = {}
+ if self.Type=="int" then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type="job"
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ self.Start=os.clock()
+ while self.Active do
+ self:Do_Order()
+ end
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ self.Start=os.clock()
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ self:Do_Order()
+ end
+end
diff --git a/oldversions/MultiManager(0.6.1-6).lua b/oldversions/MultiManager(0.6.1-6).lua
new file mode 100644
index 0000000..cdd075a
--- /dev/null
+++ b/oldversions/MultiManager(0.6.1-6).lua
@@ -0,0 +1,929 @@
+multi = {}
+multi.Version={6,1,6}-- History: EventManager,EventManager+,MultiManager <-- Current
+multi.stage="stable"
+multi.Features=multi.Version[1].."."..multi.Version[2].."."..multi.Version[3].." "..multi.stage..[[
+ Objects:
+ Event
+ Alarm
+ Loop
+ Step
+ TStep
+ Trigger
+ Task
+ Connection
+ Timer
+ Job
+]]
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.Children={}
+multi.Paused={}
+multi.Active=true
+multi.Id=-1
+multi.Type="mainint"
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+multi.clock=os.clock
+multi.time=os.time
+-- System
+function multi:Stop()
+ self.Active=false
+end
+function os.getOS()
+ if package.config:sub(1,1)=="\\" then
+ return "windows"
+ else
+ return "unix"
+ end
+end
+if os.getOS()=="windows" then
+ function os.sleep(n)
+ if n > 0 then os.execute("ping -n " .. tonumber(n+1) .. " localhost > NUL") end
+ end
+else
+ function os.sleep(n)
+ os.execute("sleep " .. tonumber(n))
+ end
+end
+function multi.executeFunction(name,...)
+ if type(_G[name])=="function" then
+ _G[name](...)
+ else
+ print("Error: Not a function")
+ end
+end
+function multi:newBase(ins)
+ if not(self.Type=="mainint" or self.Type=="int" or self.Type=="stack") then error("Can only create an object on multi or an interface obj") return false end
+ local c = {}
+ if self.Type=="int" or self.Type=="stack" then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.ender={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ return c
+end
+function multi:reboot(r)
+ local before=collectgarbage("count")
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=="table" then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+ collectgarbage()
+ local after=collectgarbage("count")
+ print([[Before rebooting total Ram used was ]]..before..[[Kb
+After rebooting total Ram used is ]]..after..[[ Kb
+A total of ]]..(before-after)..[[Kb was cleaned up]])
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:getError()
+ if self.error then
+ return self.error
+ end
+end
+function multi:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ Loop[_D]:Act()
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+end
+function multi:fromfile(path,int)
+ int=int or multi
+ local test2={}
+ local test=bin.load(path)
+ local tp=test:getBlock("s")
+ if tp=="event" then
+ test2=int:newEvent(test:getBlock("f"))
+ local t=test:getBlock("t")
+ for i=1,#t do
+ test2:OnEvent(t[i])
+ end
+ elseif tp=="alarm" then
+ test2=int:newAlarm(test:getBlock("n"))
+ elseif tp=="loop" then
+ test2=int:newLoop(test:getBlock("t")[1])
+ elseif tp=="step" or tp=="tstep" then
+ local func=test:getBlock("t")
+ local funcE=test:getBlock("t")
+ local funcS=test:getBlock("t")
+ local tab=test:getBlock("t")
+ test2=int:newStep()
+ table.merge(test2,tab)
+ test2.funcE=funcE
+ test2.funcS=funcS
+ test2.func=func
+ elseif tp=="trigger" then
+ test2=int:newTrigger(test:getBlock("f"))
+ elseif tp=="connector" then
+ test2=int:newConnection()
+ test2.func=test:getBlock("t")
+ elseif tp=="timer" then
+ test2=int:newTimer()
+ test2.count=tonumber(test:getBlock("n"))
+ else
+ print("Error: The file you selected is not a valid multi file object!")
+ return false
+ end
+ return test2
+end
+function multi:benchMark(sec)
+ local temp=self:newLoop(function(t,self)
+ if multi.clock()-self.init>self.sec then
+ print(self.c.." steps in "..self.sec.." second(s)")
+ self.tt(self.sec)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=multi.clock()
+ temp.c=0
+ return temp
+end
+function multi:tofile(path)
+ local items=self:getChildren()
+ io.mkDir(io.getName(path))
+ for i=1,#items do
+ items[i]:tofile(io.getName(path).."\\item"..item[i]..".dat")
+ end
+ local int=bin.new()
+ int:addBlock("int")
+ int:addBlock(io.getName(path))
+ int:addBlock(#self.Mainloop)
+ int:addBlock(self.Active)
+ int:addBlock(self.Rest)
+ int:addBlock(self.Jobs)
+ int:tofile()
+end
+function multi:newInterface(file)
+ if not(self.Type=="mainint") then error("Can only create an interface on the multi obj") return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type="int"
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ c.Jobs={}
+ c.queue={}
+ c.jobUS=2
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Stop()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ if file then
+ multi.Cself=c
+ loadstring("interface=multi.Cself "..io.open(file,"rb"):read("*all"))()
+ end
+ return c
+end
+function multi:newStack(file)
+ local c=self:newInterface()
+ c.Type="stack"
+ c.last={}
+ c.funcE={}
+ if file then
+ multi.Cself=c
+ loadstring("stack=multi.Cself "..io.open(file,"rb"):read("*all"))()
+ end
+ function c:OnStackCompleted(func)
+ table.insert(self.funcE,func)
+ end
+ return c
+end
+--Helpers
+function multi:protect()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ local status, err=pcall(Loop[_D].Act,Loop[_D])
+ if err and not(Loop[_D].error) then
+ Loop[_D].error=err
+ print(err..": Ingoring error continuing...")
+ end
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+ end
+end
+function multi:unProtect()
+ function self:Do_Order()
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ Loop[_D]:Act()
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+ end
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:connectFinal(func)
+ if self.Type=="event" then
+ self:OnEvent(func)
+ elseif self.Type=="alarm" then
+ self:OnRing(func)
+ elseif self.Type=="step" or self.Type=="tstep" then
+ self:OnEnd(func)
+ elseif self.Type=="loop" then
+ self:OnBreak(func)
+ else
+ error("No final event exists for: "..self.Type)
+ end
+end
+function multi:Break()
+ self:Pause()
+ self.Active=nil
+ for i=1,#self.ender do
+ self.ender[i](self)
+ end
+end
+function multi:OnBreak(func)
+ table.insert(self.ender,func)
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:Pause(n)
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=false
+ if not(n) then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Pause()
+ end
+ else
+ self:hold(n)
+ end
+ else
+ if n==nil then
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ else
+ self:hold(n)
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:resurrect()
+ table.insert(self.Parent.Mainloop,self)
+ self.Active=true
+end
+function multi:Destroy()
+ if self.Type=="int" or self.Type=="mainint" then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Destroy()
+ end
+ else
+ for i=1,#self.Parent.Mainloop do
+ if self.Parent.Mainloop[i]==self then
+ table.remove(self.Parent.Mainloop,i)
+ break
+ end
+ end
+ self.Active=false
+ end
+end
+function multi:hold(task)
+ self:Pause()
+ if type(task)=="number" then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ elseif type(task)=="function" then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt:Stop() end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ else
+ print("Error Data Type!!!")
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=="mainint" or self.Type=="int") then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+function multi:Reset(n)
+ self:Resume()
+end
+function multi:isDone()
+ return self.Active~=true
+end
+--Constructors
+function multi:newEvent(task)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="event"
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) and self.Active==true then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.Task)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newAlarm(set)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="alarm"
+ c.timer=self:newTimer()
+ c.set=set or 0
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.set)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.Active==true then
+ if self.timer:Get()>=self.set then
+ self:Pause()
+ self.Active=false
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ end
+ function c:Resume()
+ self.Parent.Resume(self)
+ self.timer:Resume()
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self:Resume()
+ self.timer:Reset()
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ function c:Pause()
+ self.timer:Pause()
+ self.Parent.Pause(self)
+ end
+ if self.Type=="stack" then
+ c:Pause()
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ table.remove(self.Parent.Mainloop,#self.Parent.Mainloop)
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ else
+ c.timer:Start()
+ end
+ return c
+end
+function multi:newTimer()
+ local c={}
+ c.Type="timer"
+ c.time=0
+ c.count=0
+ function c:Start()
+ self.time=multi.clock()
+ end
+ function c:Get()
+ return (multi.clock()-self.time)+self.count
+ end
+ c.Reset=c.Start
+ function c:Pause()
+ self.time=self:Get()
+ end
+ function c:Resume()
+ self.time=multi.clock()-self.time
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ self.count=self.count+self:Get()
+ m:addBlock(self.Type)
+ m:addBlock(self.count)
+ m:tofile(path)
+ end
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newLoop(func)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="loop"
+ c.Start=multi.clock()
+ if func then
+ c.func={func}
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.Active==true then
+ for i=1,#self.func do
+ self.func[i](multi.clock()-self.Start,self)
+ end
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type="step"
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.Active==true then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type="tstep"
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=multi.clock()
+ c.set=set or 1
+ c.funcS={}
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=multi.clock()
+ self:Resume()
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.Active then
+ if multi.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=multi.clock()
+ self:Resume()
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newTrigger(func)
+ local c={}
+ c.Type="trigger"
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.trigfunc)
+ m:tofile(path)
+ end
+ return c
+end
+function multi:newConnection()
+ local c={}
+ c.Type="connector"
+ c.func={}
+ function c:Fire(...)
+ for i=1,#self.func do
+ t,e=pcall(self.func[i],...)
+ if not(t) then
+ print(e)
+ end
+ end
+ end
+ function c:bind(t)
+ self.func=t
+ end
+ function c:connect(func)
+ table.insert(self.func,func)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:tofile(path)
+ end
+ return c
+end
+function multi:newJob(func,name)
+ if not(self.Type=="mainint" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end
+ local c = {}
+ if self.Type=="int" then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type="job"
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ rawset(self,"Start",multi.clock())
+ while self.Active do
+ self:Do_Order()
+ end
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ rawset(self,"Start",multi.clock())
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ self:Do_Order()
+ end
+end
diff --git a/oldversions/MultiManager(0.6.2).lua b/oldversions/MultiManager(0.6.2).lua
new file mode 100644
index 0000000..ca66f34
--- /dev/null
+++ b/oldversions/MultiManager(0.6.2).lua
@@ -0,0 +1,1056 @@
+if not bin then
+ print("Warning the 'bin' library wasn't required! multi:tofile(path) and the multi:fromfile(path,int) feature will not work!")
+end
+function table.merge(t1, t2)
+ for k,v in pairs(t2) do
+ if type(v) == "table" then
+ if type(t1[k] or false) == "table" then
+ table.merge(t1[k] or {}, t2[k] or {})
+ else
+ t1[k] = v
+ end
+ else
+ t1[k] = v
+ end
+ end
+ return t1
+end
+multi = {}
+multi.Version={6,2,0}-- History: EventManager,EventManager+,MultiManager <-- Current
+multi.stage="stable"
+multi.Features=multi.Version[1].."."..multi.Version[2].."."..multi.Version[3].." "..multi.stage..[[
+ Objects:
+ Event
+ Alarm
+ Loop
+ Step
+ TStep
+ Trigger
+ Task
+ Connection
+ Timer
+ Job
+]]
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.Children={}
+multi.Paused={}
+multi.Active=true
+multi.Id=-1
+multi.Type="mainint"
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+multi.clock=os.clock
+multi.time=os.time
+multi.LinkedPath=multi
+-- System
+function multi:Stop()
+ self.Active=false
+end
+function os.getOS()
+ if package.config:sub(1,1)=="\\" then
+ return "windows"
+ else
+ return "unix"
+ end
+end
+if os.getOS()=="windows" then
+ function os.sleep(n)
+ if n > 0 then os.execute("ping -n " .. tonumber(n+1) .. " localhost > NUL") end
+ end
+else
+ function os.sleep(n)
+ os.execute("sleep " .. tonumber(n))
+ end
+end
+function multi.executeFunction(name,...)
+ if type(_G[name])=="function" then
+ _G[name](...)
+ else
+ print("Error: Not a function")
+ end
+end
+function multi:reboot(r)
+ local before=collectgarbage("count")
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=="table" then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+ collectgarbage()
+ local after=collectgarbage("count")
+ print([[Before rebooting total Ram used was ]]..before..[[Kb
+After rebooting total Ram used is ]]..after..[[ Kb
+A total of ]]..(before-after)..[[Kb was cleaned up]])
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:getError()
+ if self.error then
+ return self.error
+ end
+end
+function multi:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+end
+function multi:fromfile(path,int)
+ int=int or multi
+ local test2={}
+ local test=bin.load(path)
+ local tp=test:getBlock("s")
+ if tp=="event" then
+ test2=int:newEvent(test:getBlock("f"))
+ local t=test:getBlock("t")
+ for i=1,#t do
+ test2:OnEvent(t[i])
+ end
+ elseif tp=="alarm" then
+ test2=int:newAlarm(test:getBlock("n"))
+ elseif tp=="loop" then
+ test2=int:newLoop(test:getBlock("t")[1])
+ elseif tp=="step" or tp=="tstep" then
+ local func=test:getBlock("t")
+ local funcE=test:getBlock("t")
+ local funcS=test:getBlock("t")
+ local tab=test:getBlock("t")
+ test2=int:newStep()
+ table.merge(test2,tab)
+ test2.funcE=funcE
+ test2.funcS=funcS
+ test2.func=func
+ elseif tp=="trigger" then
+ test2=int:newTrigger(test:getBlock("f"))
+ elseif tp=="connector" then
+ test2=int:newConnection()
+ test2.func=test:getBlock("t")
+ elseif tp=="timer" then
+ test2=int:newTimer()
+ test2.count=tonumber(test:getBlock("n"))
+ else
+ print("Error: The file you selected is not a valid multi file object!")
+ return false
+ end
+ return test2
+end
+function multi:benchMark(sec)
+ local temp=self:newLoop(function(t,self)
+ if multi.clock()-self.init>self.sec then
+ print(self.c.." steps in "..self.sec.." second(s)")
+ self.tt(self.sec)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=multi.clock()
+ temp.c=0
+ return temp
+end
+function multi:tofile(path)
+ local items=self:getChildren()
+ io.mkDir(io.getName(path))
+ for i=1,#items do
+ items[i]:tofile(io.getName(path).."\\item"..item[i]..".dat")
+ end
+ local int=bin.new()
+ int:addBlock("int")
+ int:addBlock(io.getName(path))
+ int:addBlock(#self.Mainloop)
+ int:addBlock(self.Active)
+ int:addBlock(self.Rest)
+ int:addBlock(self.Jobs)
+ int:tofile()
+end
+--Helpers
+function multi:OnMainConnect(func)
+ table.insert(self.func,func)
+end
+function multi:protect()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ local status, err=pcall(Loop[_D].Act,Loop[_D])
+ if err and not(Loop[_D].error) then
+ Loop[_D].error=err
+ print(err..": Ingoring error continuing...")
+ end
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+ end
+end
+function multi:unProtect()
+ function self:Do_Order()
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ Loop[_D]:Act()
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+ end
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:connectFinal(func)
+ if self.Type=="event" then
+ self:OnEvent(func)
+ elseif self.Type=="alarm" then
+ self:OnRing(func)
+ elseif self.Type=="step" or self.Type=="tstep" then
+ self:OnEnd(func)
+ elseif self.Type=="loop" or self.Type=="updater" then
+ self:OnBreak(func)
+ else
+ error("No final event exists for: "..self.Type)
+ end
+end
+function multi:Break()
+ self:Pause()
+ self.Active=nil
+ for i=1,#self.ender do
+ self.ender[i](self)
+ end
+end
+function multi:OnBreak(func)
+ table.insert(self.ender,func)
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:Pause(n)
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=false
+ if not(n) then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Pause()
+ end
+ else
+ self:hold(n)
+ end
+ else
+ if n==nil then
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ else
+ self:hold(n)
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=="int" or self.Type=="mainint" then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:resurrect()
+ table.insert(self.Parent.Mainloop,self)
+ self.Active=true
+end
+function multi:Destroy()
+ if self.Type=="int" or self.Type=="mainint" then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Destroy()
+ end
+ else
+ for i=1,#self.Parent.Mainloop do
+ if self.Parent.Mainloop[i]==self then
+ table.remove(self.Parent.Mainloop,i)
+ break
+ end
+ end
+ self.Active=false
+ end
+end
+function multi:hold(task)
+ self:Pause()
+ if type(task)=="number" then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ elseif type(task)=="function" then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt:Stop() end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ else
+ print("Error Data Type!!!")
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=="mainint" or self.Type=="int") then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+function multi:Reset(n)
+ self:Resume()
+end
+function multi:isDone()
+ return self.Active~=true
+end
+--Constructors [CORE]
+function multi:newBase(ins)
+ if not(self.Type=="mainint" or self.Type=="int" or self.Type=="stack") then error("Can only create an object on multi or an interface obj") return false end
+ local c = {}
+ if self.Type=="int" or self.Type=="stack" then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.ender={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ return c
+end
+function multi:newInterface(file)
+ if not(self.Type=="mainint") then error("Can only create an interface on the multi obj") return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type="int"
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ c.Jobs={}
+ c.queue={}
+ c.jobUS=2
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Stop()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ if file then
+ multi.Cself=c
+ loadstring("interface=multi.Cself "..io.open(file,"rb"):read("*all"))()
+ end
+ return c
+end
+function multi:newStack(file)
+ local c=self:newInterface()
+ c.Type="stack"
+ c.last={}
+ c.funcE={}
+ if file then
+ multi.Cself=c
+ loadstring("stack=multi.Cself "..io.open(file,"rb"):read("*all"))()
+ end
+ function c:OnStackCompleted(func)
+ table.insert(self.funcE,func)
+ end
+ return c
+end
+--Constructors [ACTORS]
+function multi:coustomObject(objRef,t)
+ local c={}
+ if t=="process" then
+ c=self:newBase()
+ if type(objRef)=="table" then
+ table.merge(c,objRef)
+ end
+ if not c.Act then
+ function c:Act()
+ -- Empty function
+ end
+ end
+ else
+ c=objRef or {}
+ end
+ if not c.Type then
+ c.Type="coustomObject"
+ end
+end
+function multi:newEvent(task)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="event"
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.Task)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newAlarm(set)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="alarm"
+ c.timer=self:newTimer()
+ c.set=set or 0
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.set)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.timer:Get()>=self.set then
+ self:Pause()
+ self.Active=false
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ function c:Resume()
+ self.Parent.Resume(self)
+ self.timer:Resume()
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self:Resume()
+ self.timer:Reset()
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ function c:Pause()
+ self.timer:Pause()
+ self.Parent.Pause(self)
+ end
+ if self.Type=="stack" then
+ c:Pause()
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ table.remove(self.Parent.Mainloop,#self.Parent.Mainloop)
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ else
+ c.timer:Start()
+ end
+ return c
+end
+function multi:newLoop(func)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="loop"
+ c.Start=multi.clock()
+ if func then
+ c.func={func}
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ for i=1,#self.func do
+ self.func[i](multi.clock()-self.Start,self)
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newUpdater(skip)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type="updater"
+ c.pos=1
+ c.skip=skip or 1
+ function c:Act()
+ if self.pos>=skip then
+ self.pos=0
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ self.pos=self.pos+1
+ end
+ c.OnUpdate=multi.OnMainConnect
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type="step"
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ c.Reset=c.Resume
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c={}
+ if self.Type=="stack" then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type="tstep"
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=multi.clock()
+ c.set=set or 1
+ c.funcS={}
+ c.Reset=c.Resume
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=multi.clock()
+ self:Resume()
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if multi.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=multi.clock()
+ self:Resume()
+ end
+ if self.Type=="stack" then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+-- Constructors [SEMI-ACTORS]
+function multi:newJob(func,name)
+ if not(self.Type=="mainint" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end
+ local c = {}
+ if self.Type=="int" then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type="job"
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+-- Constructors [NON-ACTORS]
+function multi:newWatcher(namespace,name)
+ local function WatcherObj(ns,n)
+ local c=multi:newBase()
+ c.Type="watcher"
+ c.ns=ns
+ c.n=n
+ c.cv=ns[n]
+ function c:OnValueChanged(func)
+ table.insert(self.func,func)
+ end
+ function c:Act()
+ if self.cv~=self.ns[self.n] then
+ for i=1,#self.func do
+ self.func[i](self,self.cv,self.ns[self.n])
+ end
+ self.cv=self.ns[self.n]
+ end
+ end
+ return c
+ end
+ if type(namespace)~="table" and type(namespace)=="string" then
+ return WatcherObj(_G,namespace)
+ elseif type(namespace)=="table" and (type(name)=="string" or "number") then
+ return WatcherObj(namespace,name)
+ else
+ print("Warning, invalid arguments! Nothing returned!")
+ end
+end
+function multi:newTimer()
+ local c={}
+ c.Type="timer"
+ c.time=0
+ c.count=0
+ function c:Start()
+ self.time=multi.clock()
+ end
+ function c:Get()
+ return (multi.clock()-self.time)+self.count
+ end
+ c.Reset=c.Start
+ function c:Pause()
+ self.time=self:Get()
+ end
+ function c:Resume()
+ self.time=multi.clock()-self.time
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ self.count=self.count+self:Get()
+ m:addBlock(self.Type)
+ m:addBlock(self.count)
+ m:tofile(path)
+ end
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newTrigger(func)
+ local c={}
+ c.Type="trigger"
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.trigfunc)
+ m:tofile(path)
+ end
+ return c
+end
+function multi:newConnection()
+ local c={}
+ c.Type="connector"
+ c.func={}
+ c.ID=0
+ function c:Fire(...)
+ for i=#self.func,1,-1 do
+ t,e=pcall(self.func[i][1],...)
+ if not(t) then
+ print(e)
+ end
+ end
+ end
+ function c:bind(t)
+ self.func=t
+ end
+ function c:remove()
+ self.func={}
+ end
+ function c:connect(func)
+ self.ID=self.ID+1
+ table.insert(self.func,{func,self.ID})
+ return {
+ Link=self.func,
+ ID=self.ID,
+ remove=function(self)
+ for i=1,#self.Link do
+ if self.Link[i][2]~=nil then
+ if self.Link[i][2]==self.ID then
+ table.remove(self.Link,i)
+ self.remove=function() end
+ self.Link=nil
+ self.ID=nil
+ return true
+ end
+ end
+ end
+ end
+ }
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:tofile(path)
+ end
+ return c
+end
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ rawset(self,"Start",multi.clock())
+ while self.Active do
+ self:Do_Order()
+ end
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ rawset(self,"Start",multi.clock())
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ self:Do_Order()
+ end
+end
diff --git a/oldversions/MultiManager(0.6.3).lua b/oldversions/MultiManager(0.6.3).lua
new file mode 100644
index 0000000..5221c83
--- /dev/null
+++ b/oldversions/MultiManager(0.6.3).lua
@@ -0,0 +1,1112 @@
+if not bin then
+ print('Warning the \'bin\' library wasn\'t required! multi:tofile(path) and the multi:fromfile(path,int) features will not work!')
+end
+function table.merge(t1, t2)
+ for k,v in pairs(t2) do
+ if type(v) == 'table' then
+ if type(t1[k] or false) == 'table' then
+ table.merge(t1[k] or {}, t2[k] or {})
+ else
+ t1[k] = v
+ end
+ else
+ t1[k] = v
+ end
+ end
+ return t1
+end
+multi = {}
+multi.Version={6,3,0}-- History: EventManager,EventManager+,MultiManager <-- Current
+multi.help=[[
+For a list of features do print(multi.Features)
+For a list of changes do print(multi.changelog)
+For current version do print(multi.Version)
+For current stage do print(multi.stage)
+For help do print(multi.help) :D
+]]
+multi.stage='stable'
+multi.Features="Current Version: "..multi.Version[1]..'.'..multi.Version[2]..'.'..multi.Version[3]..' '..multi.stage..[[
+MultiManager has 15 Objects:
++Events
++Alarms
++Loops
++Steps
++TSteps
++Triggers
++Tasks
++Connections
++Timers
++Jobs
++Interfaces
++Stacks
++Updaters
++Watchers
++CustomObjects
+
+Constructors [Runners]
+----------------------
+multi:newInterface([string: FILE defualt: nil])
+multi:newStack([string: FILE defualt: nil])
+
+Constructors [ACTORS]
+---------------------
+multi:newEvent([function: TASK defualt: function() end])
+multi:newAlarm([number: SET defualt: 0])
+multi:newLoop([function: FUNC])
+multi:newStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SKIP defualt: 0])
+multi:newTStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SET defualt: 1])
+multi:newUpdater([number: SKIP defualt: 0])
+multi:newWatcher(table: NAMESPACE,string: NAME)
+multi:newCustomObject([table: OBJREF],[string: T="process"])
+
+Constructors [Semi-ACTORS]
+--------------------------
+multi:newJob()
+
+Constructors [NON-ACTORS]
+-------------------------
+multi:newTriggers()
+multi:newTasks()
+multi:newConnections()
+multi:newTimers()
+]]
+multi.changelog=[[Changelog starts at Version 6.3.0]]
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.Children={}
+multi.Paused={}
+multi.Active=true
+multi.Id=-1
+multi.Type='mainint'
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+multi.clock=os.clock
+multi.time=os.time
+multi.LinkedPath=multi
+multi.range={
+ getN = function(self) multi:Do_Order() self.n=self.n+self.c if self.n>self.b then self.Link:Resume() return nil end return self.n end,
+}
+setmetatable(multi.range,{
+ __call=function(self,a,b,c)
+ self.c=c or 1
+ self.n=a-self.c
+ self.a=a
+ self.b=b
+ self.Link=multi.Mainloop[multi.CID]
+ self.Link:Pause()
+ return function() return self:getN() end
+ end
+})
+-- System
+function multi:Stop()
+ self.Active=false
+end
+function os.getOS()
+ if package.config:sub(1,1)=='\\' then
+ return 'windows'
+ else
+ return 'unix'
+ end
+end
+if os.getOS()=='windows' then
+ function os.sleep(n)
+ if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end
+ end
+else
+ function os.sleep(n)
+ os.execute('sleep ' .. tonumber(n))
+ end
+end
+function multi.executeFunction(name,...)
+ if type(_G[name])=='function' then
+ _G[name](...)
+ else
+ print('Error: Not a function')
+ end
+end
+function multi:reboot(r)
+ local before=collectgarbage('count')
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=='table' then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+ collectgarbage()
+ local after=collectgarbage('count')
+ print([[Before rebooting total Ram used was ]]..before..[[Kb
+After rebooting total Ram used is ]]..after..[[ Kb
+A total of ]]..(before-after)..[[Kb was cleaned up]])
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:getError()
+ if self.error then
+ return self.error
+ end
+end
+function multi:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+end
+function multi:fromfile(path,int)
+ int=int or multi
+ local test2={}
+ local test=bin.load(path)
+ local tp=test:getBlock('s')
+ if tp=='event' then
+ test2=int:newEvent(test:getBlock('f'))
+ local t=test:getBlock('t')
+ for i=1,#t do
+ test2:OnEvent(t[i])
+ end
+ elseif tp=='alarm' then
+ test2=int:newAlarm(test:getBlock('n'))
+ elseif tp=='loop' then
+ test2=int:newLoop(test:getBlock('t')[1])
+ elseif tp=='step' or tp=='tstep' then
+ local func=test:getBlock('t')
+ local funcE=test:getBlock('t')
+ local funcS=test:getBlock('t')
+ local tab=test:getBlock('t')
+ test2=int:newStep()
+ table.merge(test2,tab)
+ test2.funcE=funcE
+ test2.funcS=funcS
+ test2.func=func
+ elseif tp=='trigger' then
+ test2=int:newTrigger(test:getBlock('f'))
+ elseif tp=='connector' then
+ test2=int:newConnection()
+ test2.func=test:getBlock('t')
+ elseif tp=='timer' then
+ test2=int:newTimer()
+ test2.count=tonumber(test:getBlock('n'))
+ else
+ print('Error: The file you selected is not a valid multi file object!')
+ return false
+ end
+ return test2
+end
+function multi:benchMark(sec)
+ local temp=self:newLoop(function(t,self)
+ if multi.clock()-self.init>self.sec then
+ print(self.c..' steps in '..self.sec..' second(s)')
+ self.tt(self.sec)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=multi.clock()
+ temp.c=0
+ return temp
+end
+function multi:tofile(path)
+ local items=self:getChildren()
+ io.mkDir(io.getName(path))
+ for i=1,#items do
+ items[i]:tofile(io.getName(path)..'\\item'..item[i]..'.dat')
+ end
+ local int=bin.new()
+ int:addBlock('int')
+ int:addBlock(io.getName(path))
+ int:addBlock(#self.Mainloop)
+ int:addBlock(self.Active)
+ int:addBlock(self.Rest)
+ int:addBlock(self.Jobs)
+ int:tofile()
+end
+--Helpers
+function multi:OnMainConnect(func)
+ table.insert(self.func,func)
+end
+function multi:protect()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ local status, err=pcall(Loop[_D].Act,Loop[_D])
+ if err and not(Loop[_D].error) then
+ Loop[_D].error=err
+ print(err..': Ingoring error continuing...')
+ end
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+ end
+end
+function multi:unProtect()
+ function self:Do_Order()
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ Loop[_D]:Act()
+ end
+ end
+ if self.Rest~=0 then
+ os.sleep(self.Rest)
+ end
+ end
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:connectFinal(func)
+ if self.Type=='event' then
+ self:OnEvent(func)
+ elseif self.Type=='alarm' then
+ self:OnRing(func)
+ elseif self.Type=='step' or self.Type=='tstep' then
+ self:OnEnd(func)
+ elseif self.Type=='loop' or self.Type=='updater' then
+ self:OnBreak(func)
+ else
+ error('No final event exists for: '..self.Type)
+ end
+end
+function multi:Break()
+ self:Pause()
+ self.Active=nil
+ for i=1,#self.ender do
+ self.ender[i](self)
+ end
+end
+function multi:OnBreak(func)
+ table.insert(self.ender,func)
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:Pause(n)
+ if self.Type=='int' or self.Type=='mainint' then
+ self.Active=false
+ if not(n) then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Pause()
+ end
+ else
+ self:hold(n)
+ end
+ else
+ if n==nil then
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ else
+ self:hold(n)
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=='int' or self.Type=='mainint' then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:resurrect()
+ table.insert(self.Parent.Mainloop,self)
+ self.Active=true
+end
+function multi:Destroy()
+ if self.Type=='int' or self.Type=='mainint' then
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Destroy()
+ end
+ else
+ for i=1,#self.Parent.Mainloop do
+ if self.Parent.Mainloop[i]==self then
+ table.remove(self.Parent.Mainloop,i)
+ break
+ end
+ end
+ self.Active=false
+ end
+end
+function multi:hold(task)
+ self:Pause()
+ if type(task)=='number' then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ elseif type(task)=='function' then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt:Stop() end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ else
+ print('Error Data Type!!!')
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=='mainint' or self.Type=='int') then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+function multi:Reset(n)
+ self:Resume()
+end
+function multi:isDone()
+ return self.Active~=true
+end
+--Constructors [CORE]
+function multi:newBase(ins)
+ if not(self.Type=='mainint' or self.Type=='int' or self.Type=='stack') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='int' or self.Type=='stack' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.ender={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ return c
+end
+function multi:newInterface(file)
+ if not(self.Type=='mainint') then error('Can only create an interface on the multi obj') return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type='int'
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ c.Jobs={}
+ c.queue={}
+ c.jobUS=2
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Stop()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ if file then
+ multi.Cself=c
+ loadstring('interface=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ return c
+end
+function multi:newStack(file)
+ local c=self:newInterface()
+ c.Type='stack'
+ c.last={}
+ c.funcE={}
+ if file then
+ multi.Cself=c
+ loadstring('stack=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ function c:OnStackCompleted(func)
+ table.insert(self.funcE,func)
+ end
+ return c
+end
+--Constructors [ACTORS]
+function multi:newCustomObject(objRef,t)
+ local c={}
+ if t=='process' then
+ c=self:newBase()
+ if type(objRef)=='table' then
+ table.merge(c,objRef)
+ end
+ if not c.Act then
+ function c:Act()
+ -- Empty function
+ end
+ end
+ else
+ c=objRef or {}
+ end
+ if not c.Type then
+ c.Type='coustomObject'
+ end
+end
+function multi:newEvent(task)
+ local c={}
+ if self.Type=='stack' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='event'
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.Task)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ if self.Type=='stack' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newAlarm(set)
+ local c={}
+ if self.Type=='stack' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='alarm'
+ c.timer=self:newTimer()
+ c.set=set or 0
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.set)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.timer:Get()>=self.set then
+ self:Pause()
+ self.Active=false
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ function c:Resume()
+ self.Parent.Resume(self)
+ self.timer:Resume()
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self:Resume()
+ self.timer:Reset()
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ function c:Pause()
+ self.timer:Pause()
+ self.Parent.Pause(self)
+ end
+ if self.Type=='stack' then
+ c:Pause()
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ table.remove(self.Parent.Mainloop,#self.Parent.Mainloop)
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ else
+ c.timer:Start()
+ end
+ return c
+end
+function multi:newLoop(func)
+ local c={}
+ if self.Type=='stack' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='loop'
+ c.Start=multi.clock()
+ if func then
+ c.func={func}
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ for i=1,#self.func do
+ self.func[i](multi.clock()-self.Start,self)
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=='stack' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newUpdater(skip)
+ local c={}
+ if self.Type=='stack' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='updater'
+ c.pos=1
+ c.skip=skip or 1
+ function c:Act()
+ if self.pos>=skip then
+ self.pos=0
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ self.pos=self.pos+1
+ end
+ c.OnUpdate=multi.OnMainConnect
+ if self.Type=='stack' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c={}
+ if self.Type=='stack' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='step'
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ c.Reset=c.Resume
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ if self.Type=='stack' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c={}
+ if self.Type=='stack' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='tstep'
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=multi.clock()
+ c.set=set or 1
+ c.funcS={}
+ c.Reset=c.Resume
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=multi.clock()
+ self:Resume()
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if multi.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=multi.clock()
+ self:Resume()
+ end
+ if self.Type=='stack' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(function(self)
+ if self.Parent.last==self then
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+ self:Destroy()
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end)
+ end
+ return c
+end
+function multi:newWatcher(namespace,name)
+ local function WatcherObj(ns,n)
+ local c=multi:newBase()
+ c.Type='watcher'
+ c.ns=ns
+ c.n=n
+ c.cv=ns[n]
+ function c:OnValueChanged(func)
+ table.insert(self.func,func)
+ end
+ function c:Act()
+ if self.cv~=self.ns[self.n] then
+ for i=1,#self.func do
+ self.func[i](self,self.cv,self.ns[self.n])
+ end
+ self.cv=self.ns[self.n]
+ end
+ end
+ return c
+ end
+ if type(namespace)~='table' and type(namespace)=='string' then
+ return WatcherObj(_G,namespace)
+ elseif type(namespace)=='table' and (type(name)=='string' or 'number') then
+ return WatcherObj(namespace,name)
+ else
+ print('Warning, invalid arguments! Nothing returned!')
+ end
+end
+-- Constructors [SEMI-ACTORS]
+function multi:newJob(func,name)
+ if not(self.Type=='mainint' or self.Type=='int') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='int' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type='job'
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+-- Constructors [NON-ACTORS]
+function multi:newTimer()
+ local c={}
+ c.Type='timer'
+ c.time=0
+ c.count=0
+ function c:Start()
+ self.time=multi.clock()
+ end
+ function c:Get()
+ return (multi.clock()-self.time)+self.count
+ end
+ c.Reset=c.Start
+ function c:Pause()
+ self.time=self:Get()
+ end
+ function c:Resume()
+ self.time=multi.clock()-self.time
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ self.count=self.count+self:Get()
+ m:addBlock(self.Type)
+ m:addBlock(self.count)
+ m:tofile(path)
+ end
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newTrigger(func)
+ local c={}
+ c.Type='trigger'
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.trigfunc)
+ m:tofile(path)
+ end
+ return c
+end
+function multi:newConnection()
+ local c={}
+ c.Type='connector'
+ c.func={}
+ c.ID=0
+ function c:Fire(...)
+ for i=#self.func,1,-1 do
+ t,e=pcall(self.func[i][1],...)
+ if not(t) then
+ print(e)
+ end
+ end
+ end
+ function c:bind(t)
+ self.func=t
+ end
+ function c:remove()
+ self.func={}
+ end
+ function c:connect(func)
+ self.ID=self.ID+1
+ table.insert(self.func,{func,self.ID})
+ return {
+ Link=self.func,
+ ID=self.ID,
+ remove=function(self)
+ for i=1,#self.Link do
+ if self.Link[i][2]~=nil then
+ if self.Link[i][2]==self.ID then
+ table.remove(self.Link,i)
+ self.remove=function() end
+ self.Link=nil
+ self.ID=nil
+ return true
+ end
+ end
+ end
+ end
+ }
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:tofile(path)
+ end
+ return c
+end
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ rawset(self,'Start',multi.clock())
+ while self.Active do
+ self:Do_Order()
+ end
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ rawset(self,'Start',multi.clock())
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ self:Do_Order()
+ end
+end
diff --git a/oldversions/MultiManager(1.0.0).lua b/oldversions/MultiManager(1.0.0).lua
new file mode 100644
index 0000000..efd1991
--- /dev/null
+++ b/oldversions/MultiManager(1.0.0).lua
@@ -0,0 +1,1375 @@
+if not bin then
+ print('Warning the \'bin\' library wasn\'t required! multi:tofile(path) and the multi:fromfile(path,int) features will not work!')
+end
+if table.unpack then
+ unpack=table.unpack
+end
+function table.merge(t1, t2)
+ for k,v in pairs(t2) do
+ if type(v) == 'table' then
+ if type(t1[k] or false) == 'table' then
+ table.merge(t1[k] or {}, t2[k] or {})
+ else
+ t1[k] = v
+ end
+ else
+ t1[k] = v
+ end
+ end
+ return t1
+end
+multi = {}
+multi.Version={'A',0,0}-- History: EventManager,EventManager+,MultiManager <-- Current After 6.3.0 Versioning scheme was altered. A.0.0
+multi.help=[[
+For a list of features do print(multi.Features)
+For a list of changes do print(multi.changelog)
+For current version do print(multi.Version)
+For current stage do print(multi.stage)
+For help do print(multi.help) :D
+]]
+multi.stage='stable'
+multi.Features='Current Version: '..multi.Version[1]..'.'..multi.Version[2]..'.'..multi.Version[3]..' '..multi.stage..[[
+MultiManager has 19 Objects:
++Events
++Alarms
++Loops
++Steps
++TSteps
++Triggers
++Tasks
++Connections
++Timers
++Jobs
++Interfaces
++Conditions
++Ranges
++Threads
++Functions
++Queuers
++Updaters
++Watchers
++CustomObjects
+
+Constructors [Runners]
+---------------------- Note: multi is the main Processor Obj It cannot be paused or destroyed (kinda)
+intObj=multi:newProcessor([string: FILE defualt: nil])
+intObj=multi:newQueuer([string: FILE defualt: nil])
+
+Constructors [ACTORS]
+--------------------- Note: everything is a multiObj!
+eventObj=multi:newEvent([function: TASK defualt: function() end])
+alarmObj=multi:newAlarm([number: SET defualt: 0])
+loopObj=multi:newLoop([function: FUNC])
+stepObj=multi:newStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SKIP defualt: 0])
+tstepObj=multi:newTStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SET defualt: 1])
+updaterObj=multi:newUpdater([number: SKIP defualt: 0])
+watcherObj=multi:newWatcher(table: NAMESPACE,string: NAME)
+multiObj=multi:newCustomObject([table: OBJREF],[string: T='process'])
+void=multi:newThread(string: name,function: func)
+
+Constructors [Semi-ACTORS]
+--------------------------
+multi:newJob(function: func,[string: name])
+multi:newRange(number: a,number: b,[number: c])
+multi:newCondition(func)
+
+Constructors [NON-ACTORS]
+-------------------------
+multi:newTrigger(function: func)
+multi:newTask(function: func)
+multi:newConnection()
+multi:newTimer()
+multi:newFunction(function: func)
+]]
+multi.changelog=[[Changelog starts at Version A.0.0
+
+]]
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.ender={}
+multi.Children={}
+multi.Paused={}
+multi.Active=true
+multi.fps=60
+multi.Id=-1
+multi.Type='mainprocess'
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+multi.clock=os.clock
+multi.time=os.time
+multi.LinkedPath=multi
+multi.queuefinal=function(self)
+ self:Destroy()
+ if self.Parent.Mainloop[#self.Parent.Mainloop] then
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ else
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+end
+--Do not change these ever...Any other number will not work (Unless you are using enablePriority2() then change can be made. Just ensure that Priority_Idle is the greatest and Priority_Core is 1!)
+multi.Priority_Core=1
+multi.Priority_High=4
+multi.Priority_Above_Normal=16
+multi.Priority_Normal=64
+multi.Priority_Below_Normal=256
+multi.Priority_Low=1024
+multi.Priority_Idle=4096
+multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
+multi.PStep=1
+--^^^^
+multi.PriorityTick=1 -- Between 1 and 4 any greater and problems arise
+multi.Priority=multi.Priority_Core
+function multi:setDomainName(name)
+ self[name]={}
+end
+function multi:linkDomain(name)
+ return self[name]
+end
+function multi:_Pause()
+ self.Active=false
+end
+function multi:setPriority(s)
+ if type(s)==number then
+ self.Priority=s
+ elseif type(s)=='string' then
+ if s:lower()=='core' or s:lower()=='c' then
+ self.Priority=self.Priority_Core
+ elseif s:lower()=='high' or s:lower()=='h' then
+ self.Priority=self.Priority_High
+ elseif s:lower()=='above' or s:lower()=='an' then
+ self.Priority=self.Priority_Above_Normal
+ elseif s:lower()=='normal' or s:lower()=='n' then
+ self.Priority=self.Priority_Normal
+ elseif s:lower()=='below' or s:lower()=='bn' then
+ self.Priority=self.Priority_Below_Normal
+ elseif s:lower()=='low' or s:lower()=='l' then
+ self.Priority=self.Priority_Low
+ elseif s:lower()=='idle' or s:lower()=='i' then
+ self.Priority=self.Priority_Idle
+ end
+ end
+end
+-- System
+function os.getOS()
+ if package.config:sub(1,1)=='\\' then
+ return 'windows'
+ else
+ return 'unix'
+ end
+end
+if os.getOS()=='windows' then
+ function os.sleep(n)
+ if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end
+ end
+else
+ function os.sleep(n)
+ os.execute('sleep ' .. tonumber(n))
+ end
+end
+function multi:getParentProcess()
+ return self.Mainloop[self.CID]
+end
+function multi:Stop()
+ self.Active=false
+end
+function multi:condition(cond)
+ if not self.CD then
+ self:Pause()
+ self.held=true
+ self.CD=cond.condition
+ elseif not(cond.condition()) then
+ self.held=false
+ self:Resume()
+ self.CD=nil
+ return false
+ end
+ self.Parent:Do_Order()
+ return true
+end
+function multi:isHeld()
+ return self.held
+end
+function multi.executeFunction(name,...)
+ if type(_G[name])=='function' then
+ _G[name](...)
+ else
+ print('Error: Not a function')
+ end
+end
+function multi:waitFor(obj)
+ self:hold(function() return obj:isActive() end)
+end
+function multi:reboot(r)
+ local before=collectgarbage('count')
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=='table' then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+ collectgarbage()
+ local after=collectgarbage('count')
+ print([[Before rebooting total Ram used was ]]..before..[[Kb
+After rebooting total Ram used is ]]..after..[[ Kb
+A total of ]]..(before-after)..[[Kb was cleaned up]])
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:getError()
+ if self.error then
+ return self.error
+ end
+end
+function multi:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:enablePriority()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>7 then
+ PS.PStep=1
+ end
+ end
+end
+function multi:enablePriority2()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PStep)%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>self.Priority_Idle then
+ PS.PStep=1
+ end
+ end
+end
+multi.disablePriority=multi.unProtect
+function multi:fromfile(path,int)
+ int=int or self
+ local test2={}
+ local test=bin.load(path)
+ local tp=test:getBlock('s')
+ if tp=='event' then
+ test2=int:newEvent(test:getBlock('f'))
+ local t=test:getBlock('t')
+ for i=1,#t do
+ test2:OnEvent(t[i])
+ end
+ elseif tp=='alarm' then
+ test2=int:newAlarm(test:getBlock('n'))
+ elseif tp=='loop' then
+ test2=int:newLoop(test:getBlock('t')[1])
+ elseif tp=='step' or tp=='tstep' then
+ local func=test:getBlock('t')
+ local funcE=test:getBlock('t')
+ local funcS=test:getBlock('t')
+ local tab=test:getBlock('t')
+ test2=int:newStep()
+ table.merge(test2,tab)
+ test2.funcE=funcE
+ test2.funcS=funcS
+ test2.func=func
+ elseif tp=='trigger' then
+ test2=int:newTrigger(test:getBlock('f'))
+ elseif tp=='connector' then
+ test2=int:newConnection()
+ test2.func=test:getBlock('t')
+ elseif tp=='timer' then
+ test2=int:newTimer()
+ test2.count=tonumber(test:getBlock('n'))
+ else
+ print('Error: The file you selected is not a valid multi file object!')
+ return false
+ end
+ return test2
+end
+function multi:benchMark(sec,p)
+ local temp=self:newLoop(function(t,self)
+ if self.clock()-self.init>self.sec then
+ print(self.c..' steps in '..self.sec..' second(s)')
+ self.tt(self.sec)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ temp.Priority=p or 1
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=self.clock()
+ temp.c=0
+ return temp
+end
+function multi:tofile(path)
+ local items=self:getChildren()
+ io.mkDir(io.getName(path))
+ for i=1,#items do
+ items[i]:tofile(io.getName(path)..'\\item'..item[i]..'.dat')
+ end
+ local int=bin.new()
+ int:addBlock('process')
+ int:addBlock(io.getName(path))
+ int:addBlock(#self.Mainloop)
+ int:addBlock(self.Active)
+ int:addBlock(self.Rest)
+ int:addBlock(self.Jobs)
+ int:tofile()
+end
+function multi.startFPSMonitior()
+ if not multi.runFPS then
+ multi.doFPS(s)
+ multi.runFPS=true
+ end
+end
+function multi.doFPS(s)
+ multi:benchMark(1):OnBench(doFPS)
+ if s then
+ multi.fps=s
+ end
+end
+--Helpers
+function multi:OnMainConnect(func)
+ table.insert(self.func,func)
+end
+function multi:protect()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ self.CID=_D
+ if Loop[_D].Active then
+ local status, err=pcall(Loop[_D].Act,Loop[_D])
+ if err and Loop[_D].error=="" then
+ Loop[_D].error=err
+ self.OnError:Fire(err,Loop[_D])
+ end
+ end
+ end
+ end
+ end
+end
+function multi:unProtect()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:connectFinal(func)
+ if self.Type=='event' then
+ self:OnEvent(func)
+ elseif self.Type=='alarm' then
+ self:OnRing(func)
+ elseif self.Type=='step' or self.Type=='tstep' then
+ self:OnEnd(func)
+ else
+ print("Warning!!! "..self.Type.." doesn't contain a Final Connection State! Use "..self.Type..":Break(function) to trigger it's final event!")
+ self:OnBreak(func)
+ end
+end
+function multi:Break()
+ self:Pause()
+ self.Active=nil
+ for i=1,#self.ender do
+ if self.ender[i] then
+ self.ender[i](self)
+ end
+ end
+end
+function multi:OnBreak(func)
+ table.insert(self.ender,func)
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:isActive()
+ return self.Active
+end
+function multi:getType()
+ return self.Type
+end
+function multi:Sleep(n)
+ self:hold(n)
+end
+function multi:Pause()
+ if self.Type=='mainprocess' then
+ print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()")
+ else
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:resurrect()
+ table.insert(self.Parent.Mainloop,self)
+ self.Active=true
+end
+function multi:Destroy()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ local c=self:getChildren()
+ for i=1,#c do
+ self.OnObjectDestroyed:Fire(c[i])
+ c[i]:Destroy()
+ end
+ else
+ for i=1,#self.Parent.Mainloop do
+ if self.Parent.Mainloop[i]==self then
+ self.Parent.OnObjectDestroyed:Fire(self)
+ table.remove(self.Parent.Mainloop,i)
+ break
+ end
+ end
+ self.Active=false
+ end
+end
+
+function multi:hold(task)
+ self:Pause()
+ self.held=true
+ if type(task)=='number' then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ self.held=false
+ elseif type(task)=='function' then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt.Active=false end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ self.held=false
+ else
+ print('Error Data Type!!!')
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=='mainprocess' or self.Type=='process') then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+function multi:Reset(n)
+ self:Resume()
+end
+function multi:isDone()
+ return self.Active~=true
+end
+function multi:create(ref)
+ multi.OnObjectCreated:Fire(ref)
+end
+--Constructors [CORE]
+function multi:newBase(ins)
+ if not(self.Type=='mainprocess' or self.Type=='process' or self.Type=='queue') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='process' or self.Type=='queue' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.ender={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ c.error=""
+ c.held=false
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ return c
+end
+function multi:newProcess(file)
+ if not(self.Type=='mainprocess') then error('Can only create an interface on the multi obj') return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type='process'
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ c.Jobs={}
+ c.queue={}
+ c.jobUS=2
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Pause()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ if file then
+ self.Cself=c
+ loadstring('local interface=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ self:create(c)
+ return c
+end
+function multi:newQueuer(file)
+ local c=self:newProcess()
+ c.Type='queue'
+ c.last={}
+ c.funcE={}
+ function c:OnQueueCompleted(func)
+ table.insert(self.funcE,func)
+ end
+ if file then
+ self.Cself=c
+ loadstring('local queue=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ self:create(c)
+ return c
+end
+--Constructors [ACTORS]
+function multi:newCustomObject(objRef,t)
+ local c={}
+ if t=='process' then
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ print("This Custom Object was created on a queue! Ensure that it has a way to end! All objects have a obj:Break() method!")
+ else
+ c=self:newBase()
+ end
+ if type(objRef)=='table' then
+ table.merge(c,objRef)
+ end
+ if not c.Act then
+ function c:Act()
+ -- Empty function
+ end
+ end
+ else
+ c=objRef or {}
+ end
+ if not c.Type then
+ c.Type='coustomObject'
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newEvent(task)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='event'
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.Task)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newAlarm(set)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='alarm'
+ c.Priority=self.Priority_Low
+ c.timer=self:newTimer()
+ c.set=set or 0
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.set)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.timer:Get()>=self.set then
+ self:Pause()
+ self.Active=false
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ function c:Resume()
+ self.Parent.Resume(self)
+ self.timer:Resume()
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self:Resume()
+ self.timer:Reset()
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ function c:Pause()
+ self.timer:Pause()
+ self.Parent.Pause(self)
+ end
+ if self.Type=='queue' then
+ c:Pause()
+ c:connectFinal(multi.queuefinal)
+ else
+ c.timer:Start()
+ end
+ self:create(c)
+ return c
+end
+function multi:newLoop(func)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='loop'
+ c.Start=self.clock()
+ if func then
+ c.func={func}
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ for i=1,#self.func do
+ self.func[i](self.Parent.clock()-self.Start,self)
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newUpdater(skip)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='updater'
+ c.pos=1
+ c.skip=skip or 1
+ function c:Act()
+ if self.pos>=self.skip then
+ self.pos=0
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ self.pos=self.pos+1
+ end
+ function c:setSkip(n)
+ self.skip=n
+ end
+ c.OnUpdate=self.OnMainConnect
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='step'
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self~=nil then
+ if self.Active then
+ if self.spos==0 then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ c.Reset=c.Resume
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='tstep'
+ c.Priority=self.Priority_Low
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=self.clock()
+ c.set=set or 1
+ c.funcS={}
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=self.start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=self.clock()
+ self:Resume()
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=self.clock()
+ self:Resume()
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newWatcher(namespace,name)
+ local function WatcherObj(ns,n)
+ if self.Type=='queue' then
+ print("Cannot create a watcher on a queue! Creating on 'multi' instead!")
+ self=multi
+ end
+ local c=self:newBase()
+ c.Type='watcher'
+ c.ns=ns
+ c.n=n
+ c.cv=ns[n]
+ function c:OnValueChanged(func)
+ table.insert(self.func,func)
+ end
+ function c:Act()
+ if self.cv~=self.ns[self.n] then
+ for i=1,#self.func do
+ self.func[i](self,self.cv,self.ns[self.n])
+ end
+ self.cv=self.ns[self.n]
+ end
+ end
+ self:create(c)
+ return c
+ end
+ if type(namespace)~='table' and type(namespace)=='string' then
+ return WatcherObj(_G,namespace)
+ elseif type(namespace)=='table' and (type(name)=='string' or 'number') then
+ return WatcherObj(namespace,name)
+ else
+ print('Warning, invalid arguments! Nothing returned!')
+ end
+end
+function multi:newThread(name,func)
+ local c={}
+ c.ref={}
+ c.Name=name
+ c.thread=coroutine.create(func)
+ c.sleep=1
+ c.firstRunDone=false
+ c.timer=multi.scheduler:newTimer()
+ c.ref.Globals=self:linkDomain("Globals")
+ function c.ref:send(name,val)
+ ret=coroutine.yield({Name=name,Value=val})
+ self:syncGlobals(ret)
+ end
+ function c.ref:get(name)
+ return self.Globals[name]
+ end
+ function c.ref:kill()
+ err=coroutine.yield({"_kill_"})
+ if err then
+ error("Failed to kill a thread! Exiting...")
+ end
+ end
+ function c.ref:sleep(n)
+ n = tonumber(n) or 0
+ ret=coroutine.yield({"_sleep_",n})
+ self:syncGlobals(ret)
+ end
+ function c.ref:syncGlobals(v)
+ self.Globals=v
+ end
+ table.insert(self:linkDomain("Threads"),c)
+ if not multi.scheduler:isActive() then
+ multi.scheduler:Resume()
+ end
+end
+-- Constructors [SEMI-ACTORS]
+function multi:newJob(func,name)
+ if not(self.Type=='mainprocess' or self.Type=='process') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='process' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type='job'
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+function multi:newRange()
+ selflink=self
+ local temp={
+ getN = function(self) selflink:Do_Order() self.n=self.n+self.c if self.n>self.b then self.Link.held=false self.Link:Resume() return nil end return self.n end,
+ }
+ setmetatable(temp,{
+ __call=function(self,a,b,c)
+ self.c=c or 1
+ self.n=a-self.c
+ self.a=a
+ self.b=b
+ self.Link=selflink.Parent.Mainloop[selflink.CID]
+ self.Link:Pause()
+ self.Link.held=true
+ return function() return self:getN() end
+ end
+ })
+ self:create(temp)
+ return temp
+end
+function multi:newCondition(func)
+ local c={['condition']=func}
+ self:create(c)
+ return c
+end
+-- Constructors [NON-ACTORS]
+function multi:newFunction(func)
+ local c={}
+ c.func=func
+ mt={
+ __index=multi,
+ __call=function(self,...) if self.Active then return self:func(...) end local t={...} return "PAUSED" end
+ }
+ c.Parent=self
+ function c:Pause()
+ self.Active=false
+ end
+ function c:Resume()
+ self.Active=true
+ end
+ setmetatable(c,mt)
+ self:create(c)
+ return c
+end
+function multi:newTimer()
+ local c={}
+ c.Type='timer'
+ c.time=0
+ c.count=0
+ function c:Start()
+ self.time=os.clock()
+ end
+ function c:Get()
+ return (os.clock()-self.time)+self.count
+ end
+ c.Reset=c.Start
+ function c:Pause()
+ self.time=self:Get()
+ end
+ function c:Resume()
+ self.time=os.clock()-self.time
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ self.count=self.count+self:Get()
+ m:addBlock(self.Type)
+ m:addBlock(self.count)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newTrigger(func)
+ local c={}
+ c.Type='trigger'
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.trigfunc)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newConnection(protect)
+ local c={}
+ c.Type='connector'
+ c.func={}
+ c.ID=0
+ c.protect=protect or true
+ function c:Fire(...)
+ local ret={}
+ for i=#self.func,1,-1 do
+ if self.protect then
+ local temp={pcall(self.func[i][1],...)}
+ if temp[1] then
+ table.remove(temp,1)
+ table.insert(ret,temp)
+ else
+ print(temp[2])
+ end
+ else
+ table.insert(ret,{self.func[i][1](...)})
+ end
+ end
+ return ret
+ end
+ function c:bind(t)
+ self.func=t
+ end
+ function c:remove()
+ self.func={}
+ end
+ function c:connect(func)
+ self.ID=self.ID+1
+ table.insert(self.func,1,{func,self.ID})
+ return {
+ Link=self.func,
+ ID=self.ID,
+ remove=function(self)
+ for i=1,#self.Link do
+ if self.Link[i][2]~=nil then
+ if self.Link[i][2]==self.ID then
+ table.remove(self.Link,i)
+ self.remove=function() end
+ self.Link=nil
+ self.ID=nil
+ return true
+ end
+ end
+ end
+ end
+ }
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:tofile(path)
+ end
+ return c
+end
+multi.OnObjectCreated=multi:newConnection()
+multi.OnObjectDestroyed=multi:newConnection()
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ rawset(self,'Start',self.clock())
+ while self.Active do
+ self:Do_Order()
+ end
+ print("Did you call multi:_Pause()? This method should not be used when using multi:mainloop()! There is now no way to restart the multiManager, except by using multi:reboot() and calling multi:mainloop() again or by using multi:uManager()")
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ rawset(self,'Start',self.clock())
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ function self:uManager(dt)
+ self:Do_Order()
+ end
+ self:Do_Order()
+ end
+end
+--Thread Setup Stuff
+multi:setDomainName("Threads")
+multi:setDomainName("Globals")
+-- Scheduler
+multi.scheduler=multi:newUpdater()
+multi.scheduler.Type="scheduler"
+function multi.scheduler:setStep(n)
+ self.skip=tonumber(n) or 24
+end
+multi.scheduler.Threads=multi:linkDomain("Threads")
+multi.scheduler.Globals=multi:linkDomain("Globals")
+multi.scheduler:OnUpdate(function(self)
+ for i=#self.Threads,1,-1 do
+ ret={}
+ if coroutine.status(self.Threads[i].thread)=="dead" then
+ table.remove(self.Threads,i)
+ else
+ if self.Threads[i].timer:Get()>=self.Threads[i].sleep then
+ if self.Threads[i].firstRunDone==false then
+ self.Threads[i].firstRunDone=true
+ self.Threads[i].timer:Start()
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Threads[i].ref)
+ else
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Globals)
+ end
+ if ret==true or ret==false then
+ print("Thread Ended!!!")
+ ret={}
+ end
+ end
+ if ret then
+ if ret[1]=="_kill_" then
+ table.remove(self.Threads,i)
+ elseif ret[1]=="_sleep_" then
+ self.Threads[i].timer:Reset()
+ self.Threads[i].sleep=ret[2]
+ elseif ret.Name then
+ self.Globals[ret.Name]=ret.Value
+ end
+ end
+ end
+ end
+end)
+multi.scheduler:setStep()
+multi.scheduler:Pause()
+multi.OnError=multi:newConnection()
diff --git a/oldversions/MultiManager(1.0.1).lua b/oldversions/MultiManager(1.0.1).lua
new file mode 100644
index 0000000..d3a2dd2
--- /dev/null
+++ b/oldversions/MultiManager(1.0.1).lua
@@ -0,0 +1,1391 @@
+if not bin then
+ print('Warning the \'bin\' library wasn\'t required! multi:tofile(path) and the multi:fromfile(path,int) features will not work!')
+end
+if table.unpack then
+ unpack=table.unpack
+end
+function table.merge(t1, t2)
+ for k,v in pairs(t2) do
+ if type(v) == 'table' then
+ if type(t1[k] or false) == 'table' then
+ table.merge(t1[k] or {}, t2[k] or {})
+ else
+ t1[k] = v
+ end
+ else
+ t1[k] = v
+ end
+ end
+ return t1
+end
+multi = {}
+multi.Version={'A',0,1}-- History: EventManager,EventManager+,MultiManager <-- Current After 6.3.0 Versioning scheme was altered. A.0.0
+multi.help=[[
+For a list of features do print(multi.Features)
+For a list of changes do print(multi.changelog)
+For current version do print(multi.Version)
+For current stage do print(multi.stage)
+For help do print(multi.help) :D
+]]
+multi.stage='stable'
+multi.Features='Current Version: '..multi.Version[1]..'.'..multi.Version[2]..'.'..multi.Version[3]..' '..multi.stage..[[
+MultiManager has 19 Objects: # indicates most commonly used 1-19 1 being the most used by me
++Events #7
++Alarms #2
++Loops #3
++Steps #4
++TSteps #6
++Triggers #16
++Tasks #12
++Connections #1 -- This is a rather new feature of this library, but has become the most useful for async handling. Knowing this is already 50% of this library
++Timers #14 -- this was tricky because these make up both Alarms and TSteps, but in purly using this standalone is almost non existent
++Jobs #11
++Process #10
++Conditions #15
++Ranges #8
++Threads #13
++Functions #5
++Queuers #17
++Updaters #9
++Watchers #18
++CustomObjects #19
+
+Constructors [Runners]
+---------------------- Note: multi is the main Processor Obj It cannot be paused or destroyed (kinda)
+intObj=multi:newProcess([string: FILE defualt: nil])
+intObj=multi:newQueuer([string: FILE defualt: nil])
+
+Constructors [ACTORS]
+--------------------- Note: everything is a multiObj!
+eventObj=multi:newEvent([function: TASK defualt: function() end])
+alarmObj=multi:newAlarm([number: SET defualt: 0])
+loopObj=multi:newLoop([function: FUNC])
+stepObj=multi:newStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SKIP defualt: 0])
+tstepObj=multi:newTStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SET defualt: 1])
+updaterObj=multi:newUpdater([number: SKIP defualt: 0])
+watcherObj=multi:newWatcher(table: NAMESPACE,string: NAME)
+multiObj=multi:newCustomObject([table: OBJREF],[string: T='process'])
+void=multi:newThread(string: name,function: func)
+
+Constructors [Semi-ACTORS]
+--------------------------
+multi:newJob(function: func,[string: name])
+multi:newRange(number: a,number: b,[number: c])
+multi:newCondition(func)
+
+Constructors [NON-ACTORS]
+-------------------------
+multi:newTrigger(function: func)
+multi:newTask(function: func)
+multi:newConnection()
+multi:newTimer()
+multi:newFunction(function: func)
+]]
+multi.changelog=[[Changelog starts at Version A.0.0
+New in A.0.0
+ Nothing really however a changelog will now be recorded! Feel free to remove this extra strings if space is a requriment
+ version.major.minor
+New in A.1.0
+ Changed: multi:newConnection(protect) method
+ Changed the way you are able to interact with it by adding the __call metamethod
+ Old usage:
+
+ OnUpdate=multi:newConnection()
+ OnUpdate:connect(function(...)
+ print("Updating",...)
+ end)
+ OnUpdate:Fire(1,2,3)
+
+ New usage: notice that connect is no longer needed! Both ways still work! and always will work :)
+
+ OnUpdate=multi:newConnection()
+ OnUpdate(function(...)
+ print("Updating",...)
+ end)
+ OnUpdate:Fire(1,2,3)
+]]
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.ender={}
+multi.Children={}
+multi.Paused={}
+multi.Active=true
+multi.fps=60
+multi.Id=-1
+multi.Type='mainprocess'
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+multi.clock=os.clock
+multi.time=os.time
+multi.LinkedPath=multi
+multi.queuefinal=function(self)
+ self:Destroy()
+ if self.Parent.Mainloop[#self.Parent.Mainloop] then
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ else
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+end
+--Do not change these ever...Any other number will not work (Unless you are using enablePriority2() then change can be made. Just ensure that Priority_Idle is the greatest and Priority_Core is 1!)
+multi.Priority_Core=1
+multi.Priority_High=4
+multi.Priority_Above_Normal=16
+multi.Priority_Normal=64
+multi.Priority_Below_Normal=256
+multi.Priority_Low=1024
+multi.Priority_Idle=4096
+multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
+multi.PStep=1
+--^^^^
+multi.PriorityTick=1 -- Between 1 and 4 any greater and problems arise
+multi.Priority=multi.Priority_Core
+function multi:setDomainName(name)
+ self[name]={}
+end
+function multi:linkDomain(name)
+ return self[name]
+end
+function multi:_Pause()
+ self.Active=false
+end
+function multi:setPriority(s)
+ if type(s)==number then
+ self.Priority=s
+ elseif type(s)=='string' then
+ if s:lower()=='core' or s:lower()=='c' then
+ self.Priority=self.Priority_Core
+ elseif s:lower()=='high' or s:lower()=='h' then
+ self.Priority=self.Priority_High
+ elseif s:lower()=='above' or s:lower()=='an' then
+ self.Priority=self.Priority_Above_Normal
+ elseif s:lower()=='normal' or s:lower()=='n' then
+ self.Priority=self.Priority_Normal
+ elseif s:lower()=='below' or s:lower()=='bn' then
+ self.Priority=self.Priority_Below_Normal
+ elseif s:lower()=='low' or s:lower()=='l' then
+ self.Priority=self.Priority_Low
+ elseif s:lower()=='idle' or s:lower()=='i' then
+ self.Priority=self.Priority_Idle
+ end
+ end
+end
+-- System
+function os.getOS()
+ if package.config:sub(1,1)=='\\' then
+ return 'windows'
+ else
+ return 'unix'
+ end
+end
+if os.getOS()=='windows' then
+ function os.sleep(n)
+ if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end
+ end
+else
+ function os.sleep(n)
+ os.execute('sleep ' .. tonumber(n))
+ end
+end
+function multi:getParentProcess()
+ return self.Mainloop[self.CID]
+end
+function multi:Stop()
+ self.Active=false
+end
+function multi:condition(cond)
+ if not self.CD then
+ self:Pause()
+ self.held=true
+ self.CD=cond.condition
+ elseif not(cond.condition()) then
+ self.held=false
+ self:Resume()
+ self.CD=nil
+ return false
+ end
+ self.Parent:Do_Order()
+ return true
+end
+function multi:isHeld()
+ return self.held
+end
+function multi.executeFunction(name,...)
+ if type(_G[name])=='function' then
+ _G[name](...)
+ else
+ print('Error: Not a function')
+ end
+end
+function multi:waitFor(obj)
+ self:hold(function() return obj:isActive() end)
+end
+function multi:reboot(r)
+ local before=collectgarbage('count')
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=='table' then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+ collectgarbage()
+ local after=collectgarbage('count')
+ print([[Before rebooting total Ram used was ]]..before..[[Kb
+After rebooting total Ram used is ]]..after..[[ Kb
+A total of ]]..(before-after)..[[Kb was cleaned up]])
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:getError()
+ if self.error then
+ return self.error
+ end
+end
+function multi:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:enablePriority()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>7 then
+ PS.PStep=1
+ end
+ end
+end
+function multi:enablePriority2()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PStep)%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>self.Priority_Idle then
+ PS.PStep=1
+ end
+ end
+end
+multi.disablePriority=multi.unProtect
+function multi:fromfile(path,int)
+ int=int or self
+ local test2={}
+ local test=bin.load(path)
+ local tp=test:getBlock('s')
+ if tp=='event' then
+ test2=int:newEvent(test:getBlock('f'))
+ local t=test:getBlock('t')
+ for i=1,#t do
+ test2:OnEvent(t[i])
+ end
+ elseif tp=='alarm' then
+ test2=int:newAlarm(test:getBlock('n'))
+ elseif tp=='loop' then
+ test2=int:newLoop(test:getBlock('t')[1])
+ elseif tp=='step' or tp=='tstep' then
+ local func=test:getBlock('t')
+ local funcE=test:getBlock('t')
+ local funcS=test:getBlock('t')
+ local tab=test:getBlock('t')
+ test2=int:newStep()
+ table.merge(test2,tab)
+ test2.funcE=funcE
+ test2.funcS=funcS
+ test2.func=func
+ elseif tp=='trigger' then
+ test2=int:newTrigger(test:getBlock('f'))
+ elseif tp=='connector' then
+ test2=int:newConnection()
+ test2.func=test:getBlock('t')
+ elseif tp=='timer' then
+ test2=int:newTimer()
+ test2.count=tonumber(test:getBlock('n'))
+ else
+ print('Error: The file you selected is not a valid multi file object!')
+ return false
+ end
+ return test2
+end
+function multi:benchMark(sec,p)
+ local temp=self:newLoop(function(t,self)
+ if self.clock()-self.init>self.sec then
+ print(self.c..' steps in '..self.sec..' second(s)')
+ self.tt(self.sec)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ temp.Priority=p or 1
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=self.clock()
+ temp.c=0
+ return temp
+end
+function multi:tofile(path)
+ local items=self:getChildren()
+ io.mkDir(io.getName(path))
+ for i=1,#items do
+ items[i]:tofile(io.getName(path)..'\\item'..item[i]..'.dat')
+ end
+ local int=bin.new()
+ int:addBlock('process')
+ int:addBlock(io.getName(path))
+ int:addBlock(#self.Mainloop)
+ int:addBlock(self.Active)
+ int:addBlock(self.Rest)
+ int:addBlock(self.Jobs)
+ int:tofile()
+end
+function multi.startFPSMonitior()
+ if not multi.runFPS then
+ multi.doFPS(s)
+ multi.runFPS=true
+ end
+end
+function multi.doFPS(s)
+ multi:benchMark(1):OnBench(doFPS)
+ if s then
+ multi.fps=s
+ end
+end
+--Helpers
+function multi:OnMainConnect(func)
+ table.insert(self.func,func)
+end
+function multi:protect()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ self.CID=_D
+ local status, err=pcall(Loop[_D].Act,Loop[_D])
+ if err and not(Loop[_D].error) then
+ Loop[_D].error=err
+ self.OnError:Fire(err,Loop[_D])
+ end
+ end
+ end
+ end
+end
+function multi:unProtect()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:connectFinal(func)
+ if self.Type=='event' then
+ self:OnEvent(func)
+ elseif self.Type=='alarm' then
+ self:OnRing(func)
+ elseif self.Type=='step' or self.Type=='tstep' then
+ self:OnEnd(func)
+ else
+ print("Warning!!! "..self.Type.." doesn't contain a Final Connection State! Use "..self.Type..":Break(function) to trigger it's final event!")
+ self:OnBreak(func)
+ end
+end
+function multi:Break()
+ self:Pause()
+ self.Active=nil
+ for i=1,#self.ender do
+ if self.ender[i] then
+ self.ender[i](self)
+ end
+ end
+end
+function multi:OnBreak(func)
+ table.insert(self.ender,func)
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:isActive()
+ return self.Active
+end
+function multi:getType()
+ return self.Type
+end
+function multi:Sleep(n)
+ self:hold(n)
+end
+function multi:Pause()
+ if self.Type=='mainprocess' then
+ print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()")
+ else
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:resurrect()
+ table.insert(self.Parent.Mainloop,self)
+ self.Active=true
+end
+function multi:Destroy()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ local c=self:getChildren()
+ for i=1,#c do
+ self.OnObjectDestroyed:Fire(c[i])
+ c[i]:Destroy()
+ end
+ else
+ for i=1,#self.Parent.Mainloop do
+ if self.Parent.Mainloop[i]==self then
+ self.Parent.OnObjectDestroyed:Fire(self)
+ table.remove(self.Parent.Mainloop,i)
+ break
+ end
+ end
+ self.Active=false
+ end
+end
+
+function multi:hold(task)
+ self:Pause()
+ self.held=true
+ if type(task)=='number' then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ self.held=false
+ elseif type(task)=='function' then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt.Active=false end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ self.held=false
+ else
+ print('Error Data Type!!!')
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=='mainprocess' or self.Type=='process') then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+function multi:Reset(n)
+ self:Resume()
+end
+function multi:isDone()
+ return self.Active~=true
+end
+function multi:create(ref)
+ multi.OnObjectCreated:Fire(ref)
+end
+--Constructors [CORE]
+function multi:newBase(ins)
+ if not(self.Type=='mainprocess' or self.Type=='process' or self.Type=='queue') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='process' or self.Type=='queue' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.ender={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ c.held=false
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ return c
+end
+function multi:newProcess(file)
+ if not(self.Type=='mainprocess') then error('Can only create an interface on the multi obj') return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type='process'
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ c.Jobs={}
+ c.queue={}
+ c.jobUS=2
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Pause()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ if file then
+ self.Cself=c
+ loadstring('local interface=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ self:create(c)
+ return c
+end
+function multi:newQueuer(file)
+ local c=self:newProcess()
+ c.Type='queue'
+ c.last={}
+ c.funcE={}
+ function c:OnQueueCompleted(func)
+ table.insert(self.funcE,func)
+ end
+ if file then
+ self.Cself=c
+ loadstring('local queue=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ self:create(c)
+ return c
+end
+--Constructors [ACTORS]
+function multi:newCustomObject(objRef,t)
+ local c={}
+ if t=='process' then
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ print("This Custom Object was created on a queue! Ensure that it has a way to end! All objects have a obj:Break() method!")
+ else
+ c=self:newBase()
+ end
+ if type(objRef)=='table' then
+ table.merge(c,objRef)
+ end
+ if not c.Act then
+ function c:Act()
+ -- Empty function
+ end
+ end
+ else
+ c=objRef or {}
+ end
+ if not c.Type then
+ c.Type='coustomObject'
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newEvent(task)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='event'
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.Task)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newAlarm(set)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='alarm'
+ c.Priority=self.Priority_Low
+ c.timer=self:newTimer()
+ c.set=set or 0
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.set)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.timer:Get()>=self.set then
+ self:Pause()
+ self.Active=false
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ function c:Resume()
+ self.Parent.Resume(self)
+ self.timer:Resume()
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self:Resume()
+ self.timer:Reset()
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ function c:Pause()
+ self.timer:Pause()
+ self.Parent.Pause(self)
+ end
+ if self.Type=='queue' then
+ c:Pause()
+ c:connectFinal(multi.queuefinal)
+ else
+ c.timer:Start()
+ end
+ self:create(c)
+ return c
+end
+function multi:newLoop(func)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='loop'
+ c.Start=self.clock()
+ if func then
+ c.func={func}
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ for i=1,#self.func do
+ self.func[i](self.Parent.clock()-self.Start,self)
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newUpdater(skip)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='updater'
+ c.pos=1
+ c.skip=skip or 1
+ function c:Act()
+ if self.pos>=self.skip then
+ self.pos=0
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ self.pos=self.pos+1
+ end
+ function c:setSkip(n)
+ self.skip=n
+ end
+ c.OnUpdate=self.OnMainConnect
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='step'
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ c.Reset=c.Resume
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='tstep'
+ c.Priority=self.Priority_Low
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=self.clock()
+ c.set=set or 1
+ c.funcS={}
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=self.start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=self.clock()
+ self:Resume()
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=self.clock()
+ self:Resume()
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newWatcher(namespace,name)
+ local function WatcherObj(ns,n)
+ if self.Type=='queue' then
+ print("Cannot create a watcher on a queue! Creating on 'multi' instead!")
+ self=multi
+ end
+ local c=self:newBase()
+ c.Type='watcher'
+ c.ns=ns
+ c.n=n
+ c.cv=ns[n]
+ function c:OnValueChanged(func)
+ table.insert(self.func,func)
+ end
+ function c:Act()
+ if self.cv~=self.ns[self.n] then
+ for i=1,#self.func do
+ self.func[i](self,self.cv,self.ns[self.n])
+ end
+ self.cv=self.ns[self.n]
+ end
+ end
+ self:create(c)
+ return c
+ end
+ if type(namespace)~='table' and type(namespace)=='string' then
+ return WatcherObj(_G,namespace)
+ elseif type(namespace)=='table' and (type(name)=='string' or 'number') then
+ return WatcherObj(namespace,name)
+ else
+ print('Warning, invalid arguments! Nothing returned!')
+ end
+end
+function multi:newThread(name,func)
+ local c={}
+ c.ref={}
+ c.Name=name
+ c.thread=coroutine.create(func)
+ c.sleep=1
+ c.firstRunDone=false
+ c.timer=multi.scheduler:newTimer()
+ c.ref.Globals=self:linkDomain("Globals")
+ function c.ref:send(name,val)
+ ret=coroutine.yield({Name=name,Value=val})
+ self:syncGlobals(ret)
+ end
+ function c.ref:get(name)
+ return self.Globals[name]
+ end
+ function c.ref:kill()
+ err=coroutine.yield({"_kill_"})
+ if err then
+ error("Failed to kill a thread! Exiting...")
+ end
+ end
+ function c.ref:sleep(n)
+ n = tonumber(n) or 0
+ ret=coroutine.yield({"_sleep_",n})
+ self:syncGlobals(ret)
+ end
+ function c.ref:syncGlobals(v)
+ self.Globals=v
+ end
+ table.insert(self:linkDomain("Threads"),c)
+ if not multi.scheduler:isActive() then
+ multi.scheduler:Resume()
+ end
+end
+-- Constructors [SEMI-ACTORS]
+function multi:newJob(func,name)
+ if not(self.Type=='mainprocess' or self.Type=='process') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='process' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type='job'
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+function multi:newRange()
+ selflink=self
+ local temp={
+ getN = function(self) selflink:Do_Order() self.n=self.n+self.c if self.n>self.b then self.Link.held=false self.Link:Resume() return nil end return self.n end,
+ }
+ setmetatable(temp,{
+ __call=function(self,a,b,c)
+ self.c=c or 1
+ self.n=a-self.c
+ self.a=a
+ self.b=b
+ self.Link=selflink.Parent.Mainloop[selflink.CID]
+ self.Link:Pause()
+ self.Link.held=true
+ return function() return self:getN() end
+ end
+ })
+ self:create(temp)
+ return temp
+end
+function multi:newCondition(func)
+ local c={['condition']=func}
+ self:create(c)
+ return c
+end
+-- Constructors [NON-ACTORS]
+function multi:newFunction(func)
+ local c={}
+ c.func=func
+ mt={
+ __index=multi,
+ __call=function(self,...) if self.Active then return self:func(...) end local t={...} return "PAUSED" end
+ }
+ c.Parent=self
+ function c:Pause()
+ self.Active=false
+ end
+ function c:Resume()
+ self.Active=true
+ end
+ setmetatable(c,mt)
+ self:create(c)
+ return c
+end
+function multi:newTimer()
+ local c={}
+ c.Type='timer'
+ c.time=0
+ c.count=0
+ function c:Start()
+ self.time=os.clock()
+ end
+ function c:Get()
+ return (os.clock()-self.time)+self.count
+ end
+ c.Reset=c.Start
+ function c:Pause()
+ self.time=self:Get()
+ end
+ function c:Resume()
+ self.time=os.clock()-self.time
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ self.count=self.count+self:Get()
+ m:addBlock(self.Type)
+ m:addBlock(self.count)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newTrigger(func)
+ local c={}
+ c.Type='trigger'
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.trigfunc)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newConnection(protect)
+ local c={}
+ setmetatable(c,{__call=function(self,...) self:connect(...) end})
+ c.Type='connector'
+ c.func={}
+ c.ID=0
+ c.protect=protect or true
+ function c:Fire(...)
+ local ret={}
+ for i=#self.func,1,-1 do
+ if self.protect then
+ local temp={pcall(self.func[i][1],...)}
+ if temp[1] then
+ table.remove(temp,1)
+ table.insert(ret,temp)
+ else
+ print(temp[2])
+ end
+ else
+ table.insert(ret,{self.func[i][1](...)})
+ end
+ end
+ return ret
+ end
+ function c:bind(t)
+ self.func=t
+ end
+ function c:remove()
+ self.func={}
+ end
+ function c:connect(func)
+ self.ID=self.ID+1
+ table.insert(self.func,1,{func,self.ID})
+ return {
+ Link=self.func,
+ ID=self.ID,
+ remove=function(self)
+ for i=1,#self.Link do
+ if self.Link[i][2]~=nil then
+ if self.Link[i][2]==self.ID then
+ table.remove(self.Link,i)
+ self.remove=function() end
+ self.Link=nil
+ self.ID=nil
+ return true
+ end
+ end
+ end
+ end
+ }
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:tofile(path)
+ end
+ return c
+end
+multi.OnObjectCreated=multi:newConnection()
+multi.OnObjectDestroyed=multi:newConnection()
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ rawset(self,'Start',self.clock())
+ while self.Active do
+ self:Do_Order()
+ end
+ print("Did you call multi:Stop()? This method should not be used when using multi:mainloop()! You now need to restart the multiManager, by using multi:reboot() and calling multi:mainloop() again or by using multi:uManager()")
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ rawset(self,'Start',self.clock())
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ function self:uManager(dt)
+ self:Do_Order()
+ end
+ self:Do_Order()
+ end
+end
+--Thread Setup Stuff
+multi:setDomainName("Threads")
+multi:setDomainName("Globals")
+-- Scheduler
+multi.scheduler=multi:newUpdater()
+multi.scheduler.Type="scheduler"
+function multi.scheduler:setStep(n)
+ self.skip=tonumber(n) or 24
+end
+multi.scheduler.Threads=multi:linkDomain("Threads")
+multi.scheduler.Globals=multi:linkDomain("Globals")
+multi.scheduler:OnUpdate(function(self)
+ for i=#self.Threads,1,-1 do
+ ret={}
+ if coroutine.status(self.Threads[i].thread)=="dead" then
+ table.remove(self.Threads,i)
+ else
+ if self.Threads[i].timer:Get()>=self.Threads[i].sleep then
+ if self.Threads[i].firstRunDone==false then
+ self.Threads[i].firstRunDone=true
+ self.Threads[i].timer:Start()
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Threads[i].ref)
+ else
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Globals)
+ end
+ if ret==true or ret==false then
+ print("Thread Ended!!!")
+ ret={}
+ end
+ end
+ if ret then
+ if ret[1]=="_kill_" then
+ table.remove(self.Threads,i)
+ elseif ret[1]=="_sleep_" then
+ self.Threads[i].timer:Reset()
+ self.Threads[i].sleep=ret[2]
+ elseif ret.Name then
+ self.Globals[ret.Name]=ret.Value
+ end
+ end
+ end
+ end
+end)
+multi.scheduler:setStep()
+multi.scheduler:Pause()
+multi.OnError=multi:newConnection()
diff --git a/oldversions/MultiManager(1.2.0).lua b/oldversions/MultiManager(1.2.0).lua
new file mode 100644
index 0000000..94f47e5
--- /dev/null
+++ b/oldversions/MultiManager(1.2.0).lua
@@ -0,0 +1,1434 @@
+if not bin then
+ print('Warning the \'bin\' library wasn\'t required! multi:tofile(path) and the multi:fromfile(path,int) features will not work!')
+end
+if table.unpack then
+ unpack=table.unpack
+end
+function table.merge(t1, t2)
+ for k,v in pairs(t2) do
+ if type(v) == 'table' then
+ if type(t1[k] or false) == 'table' then
+ table.merge(t1[k] or {}, t2[k] or {})
+ else
+ t1[k] = v
+ end
+ else
+ t1[k] = v
+ end
+ end
+ return t1
+end
+multi = {}
+multi.Version={'A',2,0}-- History: EventManager,EventManager+,MultiManager <-- Current After 6.3.0 Versioning scheme was altered. A.0.0
+multi.help=[[
+For a list of features do print(multi.Features)
+For a list of changes do print(multi.changelog)
+For current version do print(multi.Version)
+For current stage do print(multi.stage)
+For help do print(multi.help) :D
+]]
+multi.stage='stable'
+multi.Features='Current Version: '..multi.Version[1]..'.'..multi.Version[2]..'.'..multi.Version[3]..' '..multi.stage..[[
+MultiManager has 19 Objects: # indicates most commonly used 1-19 1 being the most used by me
++Events #7
++Alarms #2
++Loops #3
++Steps #4
++TSteps #6
++Triggers #16
++Tasks #12
++Connections #1 -- This is a rather new feature of this library, but has become the most useful for async handling. Knowing this is already 50% of this library
++Timers #14 -- this was tricky because these make up both Alarms and TSteps, but in purly using this standalone is almost non existent
++Jobs #11
++Process #10
++Conditions #15
++Ranges #8
++Threads #13
++Functions #5
++Queuers #17
++Updaters #9
++Watchers #18
++CustomObjects #19
+
+Constructors [Runners]
+---------------------- Note: multi is the main Processor Obj It cannot be paused or destroyed (kinda)
+intObj=multi:newProcess([string: FILE defualt: nil])
+intObj=multi:newQueuer([string: FILE defualt: nil])
+
+Constructors [ACTORS]
+--------------------- Note: everything is a multiObj!
+eventObj=multi:newEvent([function: TASK defualt: function() end])
+alarmObj=multi:newAlarm([number: SET defualt: 0])
+loopObj=multi:newLoop([function: FUNC])
+stepObj=multi:newStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SKIP defualt: 0])
+tstepObj=multi:newTStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SET defualt: 1])
+updaterObj=multi:newUpdater([number: SKIP defualt: 0])
+watcherObj=multi:newWatcher(table: NAMESPACE,string: NAME)
+multiObj=multi:newCustomObject([table: OBJREF],[string: T='process'])
+void=multi:newThread(string: name,function: func)
+
+Constructors [Semi-ACTORS]
+--------------------------
+multi:newJob(function: func,[string: name])
+multi:newRange(number: a,number: b,[number: c])
+multi:newCondition(func)
+
+Constructors [NON-ACTORS]
+-------------------------
+multi:newTrigger(function: func)
+multi:newTask(function: func)
+multi:newConnection()
+multi:newTimer()
+multi:newFunction(function: func)
+]]
+multi.changelog=[[Changelog starts at Version A.0.0
+New in A.0.0
+ Nothing really however a changelog will now be recorded! Feel free to remove this extra strings if space is a requriment
+ version.major.minor
+New in A.1.0
+ Changed: multi:newConnection(protect) method
+ Changed the way you are able to interact with it by adding the __call metamethod
+ Old usage:
+ OnUpdate=multi:newConnection()
+ OnUpdate:connect(function(...)
+ print("Updating",...)
+ end)
+ OnUpdate:Fire(1,2,3)
+ New usage: notice that connect is no longer needed! Both ways still work! and always will work :)
+ OnUpdate=multi:newConnection()
+ OnUpdate(function(...)
+ print("Updating",...)
+ end)
+ OnUpdate:Fire(1,2,3)
+New in A.2.0 (12/31/2016)
+ Added:
+ connectionobj.getConnection(name)
+ returns a list of an instance (or instances) of a single connect made with connectionobj:connect(func,name) or connectionobj(func,name)
+ if you can orginize data before hand you can route info to certain connections thus saving a lot of cpu time. NOTE: only one name per each connection... you can't have 2 of the same names in a dictonary... the last one will be used
+ Changed: obj=multi:newConnection()
+ obj:connect(func,name) and obj(func,name)
+ Added the name argument to allow indexing specific connection objects... Useful when creating an async library
+]]
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.ender={}
+multi.Children={}
+multi.Paused={}
+multi.Active=true
+multi.fps=60
+multi.Id=-1
+multi.Type='mainprocess'
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+multi.clock=os.clock
+multi.time=os.time
+multi.LinkedPath=multi
+multi.queuefinal=function(self)
+ self:Destroy()
+ if self.Parent.Mainloop[#self.Parent.Mainloop] then
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ else
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+end
+--Do not change these ever...Any other number will not work (Unless you are using enablePriority2() then change can be made. Just ensure that Priority_Idle is the greatest and Priority_Core is 1!)
+multi.Priority_Core=1
+multi.Priority_High=4
+multi.Priority_Above_Normal=16
+multi.Priority_Normal=64
+multi.Priority_Below_Normal=256
+multi.Priority_Low=1024
+multi.Priority_Idle=4096
+multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
+multi.PStep=1
+--^^^^
+multi.PriorityTick=1 -- Between 1 and 4 any greater and problems arise
+multi.Priority=multi.Priority_Core
+function multi:setDomainName(name)
+ self[name]={}
+end
+function multi:linkDomain(name)
+ return self[name]
+end
+function multi:_Pause()
+ self.Active=false
+end
+function multi:setPriority(s)
+ if type(s)==number then
+ self.Priority=s
+ elseif type(s)=='string' then
+ if s:lower()=='core' or s:lower()=='c' then
+ self.Priority=self.Priority_Core
+ elseif s:lower()=='high' or s:lower()=='h' then
+ self.Priority=self.Priority_High
+ elseif s:lower()=='above' or s:lower()=='an' then
+ self.Priority=self.Priority_Above_Normal
+ elseif s:lower()=='normal' or s:lower()=='n' then
+ self.Priority=self.Priority_Normal
+ elseif s:lower()=='below' or s:lower()=='bn' then
+ self.Priority=self.Priority_Below_Normal
+ elseif s:lower()=='low' or s:lower()=='l' then
+ self.Priority=self.Priority_Low
+ elseif s:lower()=='idle' or s:lower()=='i' then
+ self.Priority=self.Priority_Idle
+ end
+ end
+end
+-- System
+function os.getOS()
+ if package.config:sub(1,1)=='\\' then
+ return 'windows'
+ else
+ return 'unix'
+ end
+end
+if os.getOS()=='windows' then
+ function os.sleep(n)
+ if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end
+ end
+else
+ function os.sleep(n)
+ os.execute('sleep ' .. tonumber(n))
+ end
+end
+function multi:getParentProcess()
+ return self.Mainloop[self.CID]
+end
+function multi:Stop()
+ self.Active=false
+end
+function multi:condition(cond)
+ if not self.CD then
+ self:Pause()
+ self.held=true
+ self.CD=cond.condition
+ elseif not(cond.condition()) then
+ self.held=false
+ self:Resume()
+ self.CD=nil
+ return false
+ end
+ self.Parent:Do_Order()
+ return true
+end
+function multi:isHeld()
+ return self.held
+end
+function multi.executeFunction(name,...)
+ if type(_G[name])=='function' then
+ _G[name](...)
+ else
+ print('Error: Not a function')
+ end
+end
+function multi:waitFor(obj)
+ self:hold(function() return obj:isActive() end)
+end
+function multi:reboot(r)
+ local before=collectgarbage('count')
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=='table' then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+ collectgarbage()
+ local after=collectgarbage('count')
+ print([[Before rebooting total Ram used was ]]..before..[[Kb
+After rebooting total Ram used is ]]..after..[[ Kb
+A total of ]]..(before-after)..[[Kb was cleaned up]])
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:getError()
+ if self.error then
+ return self.error
+ end
+end
+function multi:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:enablePriority()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>7 then
+ PS.PStep=1
+ end
+ end
+end
+function multi:enablePriority2()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PStep)%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>self.Priority_Idle then
+ PS.PStep=1
+ end
+ end
+end
+multi.disablePriority=multi.unProtect
+function multi:fromfile(path,int)
+ int=int or self
+ local test2={}
+ local test=bin.load(path)
+ local tp=test:getBlock('s')
+ if tp=='event' then
+ test2=int:newEvent(test:getBlock('f'))
+ local t=test:getBlock('t')
+ for i=1,#t do
+ test2:OnEvent(t[i])
+ end
+ elseif tp=='alarm' then
+ test2=int:newAlarm(test:getBlock('n'))
+ elseif tp=='loop' then
+ test2=int:newLoop(test:getBlock('t')[1])
+ elseif tp=='step' or tp=='tstep' then
+ local func=test:getBlock('t')
+ local funcE=test:getBlock('t')
+ local funcS=test:getBlock('t')
+ local tab=test:getBlock('t')
+ test2=int:newStep()
+ table.merge(test2,tab)
+ test2.funcE=funcE
+ test2.funcS=funcS
+ test2.func=func
+ elseif tp=='trigger' then
+ test2=int:newTrigger(test:getBlock('f'))
+ elseif tp=='connector' then
+ test2=int:newConnection()
+ test2.func=test:getBlock('t')
+ elseif tp=='timer' then
+ test2=int:newTimer()
+ test2.count=tonumber(test:getBlock('n'))
+ else
+ print('Error: The file you selected is not a valid multi file object!')
+ return false
+ end
+ return test2
+end
+function multi:benchMark(sec,p)
+ local temp=self:newLoop(function(t,self)
+ if self.clock()-self.init>self.sec then
+ print(self.c..' steps in '..self.sec..' second(s)')
+ self.tt(self.sec)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ temp.Priority=p or 1
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=self.clock()
+ temp.c=0
+ return temp
+end
+function multi:tofile(path)
+ local items=self:getChildren()
+ io.mkDir(io.getName(path))
+ for i=1,#items do
+ items[i]:tofile(io.getName(path)..'\\item'..item[i]..'.dat')
+ end
+ local int=bin.new()
+ int:addBlock('process')
+ int:addBlock(io.getName(path))
+ int:addBlock(#self.Mainloop)
+ int:addBlock(self.Active)
+ int:addBlock(self.Rest)
+ int:addBlock(self.Jobs)
+ int:tofile()
+end
+function multi.startFPSMonitior()
+ if not multi.runFPS then
+ multi.doFPS(s)
+ multi.runFPS=true
+ end
+end
+function multi.doFPS(s)
+ multi:benchMark(1):OnBench(doFPS)
+ if s then
+ multi.fps=s
+ end
+end
+--Helpers
+function multi:OnMainConnect(func)
+ table.insert(self.func,func)
+end
+function multi:protect()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ self.CID=_D
+ local status, err=pcall(Loop[_D].Act,Loop[_D])
+ if err and not(Loop[_D].error) then
+ Loop[_D].error=err
+ self.OnError:Fire(err,Loop[_D])
+ end
+ end
+ end
+ end
+end
+function multi:unProtect()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:connectFinal(func)
+ if self.Type=='event' then
+ self:OnEvent(func)
+ elseif self.Type=='alarm' then
+ self:OnRing(func)
+ elseif self.Type=='step' or self.Type=='tstep' then
+ self:OnEnd(func)
+ else
+ print("Warning!!! "..self.Type.." doesn't contain a Final Connection State! Use "..self.Type..":Break(function) to trigger it's final event!")
+ self:OnBreak(func)
+ end
+end
+function multi:Break()
+ self:Pause()
+ self.Active=nil
+ for i=1,#self.ender do
+ if self.ender[i] then
+ self.ender[i](self)
+ end
+ end
+end
+function multi:OnBreak(func)
+ table.insert(self.ender,func)
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:isActive()
+ return self.Active
+end
+function multi:getType()
+ return self.Type
+end
+function multi:Sleep(n)
+ self:hold(n)
+end
+function multi:Pause()
+ if self.Type=='mainprocess' then
+ print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()")
+ else
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:resurrect()
+ table.insert(self.Parent.Mainloop,self)
+ self.Active=true
+end
+function multi:Destroy()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ local c=self:getChildren()
+ for i=1,#c do
+ self.OnObjectDestroyed:Fire(c[i])
+ c[i]:Destroy()
+ end
+ else
+ for i=1,#self.Parent.Mainloop do
+ if self.Parent.Mainloop[i]==self then
+ self.Parent.OnObjectDestroyed:Fire(self)
+ table.remove(self.Parent.Mainloop,i)
+ break
+ end
+ end
+ self.Active=false
+ end
+end
+
+function multi:hold(task)
+ self:Pause()
+ self.held=true
+ if type(task)=='number' then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ self.held=false
+ elseif type(task)=='function' then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt.Active=false end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ self.held=false
+ else
+ print('Error Data Type!!!')
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=='mainprocess' or self.Type=='process') then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+function multi:Reset(n)
+ self:Resume()
+end
+function multi:isDone()
+ return self.Active~=true
+end
+function multi:create(ref)
+ multi.OnObjectCreated:Fire(ref)
+end
+--Constructors [CORE]
+function multi:newBase(ins)
+ if not(self.Type=='mainprocess' or self.Type=='process' or self.Type=='queue') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='process' or self.Type=='queue' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.ender={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ c.held=false
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ return c
+end
+function multi:newProcess(file)
+ if not(self.Type=='mainprocess') then error('Can only create an interface on the multi obj') return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type='process'
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ c.Jobs={}
+ c.queue={}
+ c.jobUS=2
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Pause()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ if file then
+ self.Cself=c
+ loadstring('local interface=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ self:create(c)
+ return c
+end
+function multi:newQueuer(file)
+ local c=self:newProcess()
+ c.Type='queue'
+ c.last={}
+ c.funcE={}
+ function c:OnQueueCompleted(func)
+ table.insert(self.funcE,func)
+ end
+ if file then
+ self.Cself=c
+ loadstring('local queue=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ self:create(c)
+ return c
+end
+--Constructors [ACTORS]
+function multi:newCustomObject(objRef,t)
+ local c={}
+ if t=='process' then
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ print("This Custom Object was created on a queue! Ensure that it has a way to end! All objects have a obj:Break() method!")
+ else
+ c=self:newBase()
+ end
+ if type(objRef)=='table' then
+ table.merge(c,objRef)
+ end
+ if not c.Act then
+ function c:Act()
+ -- Empty function
+ end
+ end
+ else
+ c=objRef or {}
+ end
+ if not c.Type then
+ c.Type='coustomObject'
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newEvent(task)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='event'
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.Task)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newAlarm(set)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='alarm'
+ c.Priority=self.Priority_Low
+ c.timer=self:newTimer()
+ c.set=set or 0
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.set)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.timer:Get()>=self.set then
+ self:Pause()
+ self.Active=false
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ function c:Resume()
+ self.Parent.Resume(self)
+ self.timer:Resume()
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self:Resume()
+ self.timer:Reset()
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ function c:Pause()
+ self.timer:Pause()
+ self.Parent.Pause(self)
+ end
+ if self.Type=='queue' then
+ c:Pause()
+ c:connectFinal(multi.queuefinal)
+ else
+ c.timer:Start()
+ end
+ self:create(c)
+ return c
+end
+function multi:newLoop(func)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='loop'
+ c.Start=self.clock()
+ if func then
+ c.func={func}
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ for i=1,#self.func do
+ self.func[i](self.Parent.clock()-self.Start,self)
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newUpdater(skip)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='updater'
+ c.pos=1
+ c.skip=skip or 1
+ function c:Act()
+ if self.pos>=self.skip then
+ self.pos=0
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ self.pos=self.pos+1
+ end
+ function c:setSkip(n)
+ self.skip=n
+ end
+ c.OnUpdate=self.OnMainConnect
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='step'
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ c.Reset=c.Resume
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='tstep'
+ c.Priority=self.Priority_Low
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=self.clock()
+ c.set=set or 1
+ c.funcS={}
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=self.start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=self.clock()
+ self:Resume()
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=self.clock()
+ self:Resume()
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newWatcher(namespace,name)
+ local function WatcherObj(ns,n)
+ if self.Type=='queue' then
+ print("Cannot create a watcher on a queue! Creating on 'multi' instead!")
+ self=multi
+ end
+ local c=self:newBase()
+ c.Type='watcher'
+ c.ns=ns
+ c.n=n
+ c.cv=ns[n]
+ function c:OnValueChanged(func)
+ table.insert(self.func,func)
+ end
+ function c:Act()
+ if self.cv~=self.ns[self.n] then
+ for i=1,#self.func do
+ self.func[i](self,self.cv,self.ns[self.n])
+ end
+ self.cv=self.ns[self.n]
+ end
+ end
+ self:create(c)
+ return c
+ end
+ if type(namespace)~='table' and type(namespace)=='string' then
+ return WatcherObj(_G,namespace)
+ elseif type(namespace)=='table' and (type(name)=='string' or 'number') then
+ return WatcherObj(namespace,name)
+ else
+ print('Warning, invalid arguments! Nothing returned!')
+ end
+end
+function multi:newThread(name,func)
+ local c={}
+ c.ref={}
+ c.Name=name
+ c.thread=coroutine.create(func)
+ c.sleep=1
+ c.firstRunDone=false
+ c.timer=multi.scheduler:newTimer()
+ c.ref.Globals=self:linkDomain("Globals")
+ function c.ref:send(name,val)
+ ret=coroutine.yield({Name=name,Value=val})
+ self:syncGlobals(ret)
+ end
+ function c.ref:get(name)
+ return self.Globals[name]
+ end
+ function c.ref:kill()
+ err=coroutine.yield({"_kill_"})
+ if err then
+ error("Failed to kill a thread! Exiting...")
+ end
+ end
+ function c.ref:sleep(n)
+ n = tonumber(n) or 0
+ ret=coroutine.yield({"_sleep_",n})
+ self:syncGlobals(ret)
+ end
+ function c.ref:syncGlobals(v)
+ self.Globals=v
+ end
+ table.insert(self:linkDomain("Threads"),c)
+ if not multi.scheduler:isActive() then
+ multi.scheduler:Resume()
+ end
+end
+-- Constructors [SEMI-ACTORS]
+function multi:newJob(func,name)
+ if not(self.Type=='mainprocess' or self.Type=='process') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='process' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type='job'
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+function multi:newRange()
+ local selflink=self
+ local temp={
+ getN = function(self) selflink:Do_Order() self.n=self.n+self.c if self.n>self.b then self.Link.held=false self.Link:Resume() return nil end return self.n end,
+ }
+ setmetatable(temp,{
+ __call=function(self,a,b,c)
+ self.c=c or 1
+ self.n=a-self.c
+ self.a=a
+ self.b=b
+ self.Link=selflink--.Parent.Mainloop[selflink.CID] or
+ self.Link:Pause()
+ self.Link.held=true
+ return function() return self:getN() end
+ end
+ })
+ self:create(temp)
+ return temp
+end
+function multi:newCondition(func)
+ local c={['condition']=func}
+ self:create(c)
+ return c
+end
+-- Constructors [NON-ACTORS]
+function multi:newFunction(func)
+ local c={}
+ c.func=func
+ mt={
+ __index=multi,
+ __call=function(self,...) if self.Active then return self:func(...) end local t={...} return "PAUSED" end
+ }
+ c.Parent=self
+ function c:Pause()
+ self.Active=false
+ end
+ function c:Resume()
+ self.Active=true
+ end
+ setmetatable(c,mt)
+ self:create(c)
+ return c
+end
+function multi:newTimer()
+ local c={}
+ c.Type='timer'
+ c.time=0
+ c.count=0
+ function c:Start()
+ self.time=os.clock()
+ end
+ function c:Get()
+ return (os.clock()-self.time)+self.count
+ end
+ c.Reset=c.Start
+ function c:Pause()
+ self.time=self:Get()
+ end
+ function c:Resume()
+ self.time=os.clock()-self.time
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ self.count=self.count+self:Get()
+ m:addBlock(self.Type)
+ m:addBlock(self.count)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newTrigger(func)
+ local c={}
+ c.Type='trigger'
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.trigfunc)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newConnection(protect)
+ local c={}
+ setmetatable(c,{__call=function(self,...) self:connect(...) end})
+ c.Type='connector'
+ c.func={}
+ c.ID=0
+ c.protect=protect or true
+ c.connections={}
+ c.fconnections={}
+ c.FC=0
+ function c:fConnect(func)
+ local temp=self:connect(func)
+ table.insert(self.fconnections,temp)
+ self.FC=self.FC+1
+ end
+ function c:getConnection(name,ingore)
+ if ingore then
+ return self.connections[name] or {
+ Fire=function() end -- if the connection doesn't exist lets call all of them or silently ingore
+ }
+ else
+ return self.connections[name] or self
+ end
+ end
+ function c:Fire(...)
+ local ret={}
+ for i=#self.func,1,-1 do
+ if self.protect then
+ local temp={pcall(self.func[i][1],...)}
+ if temp[1] then
+ table.remove(temp,1)
+ table.insert(ret,temp)
+ else
+ print(temp[2])
+ end
+ else
+ table.insert(ret,{self.func[i][1](...)})
+ end
+ end
+ return ret
+ end
+ function c:bind(t)
+ self.func=t
+ end
+ function c:remove()
+ self.func={}
+ end
+ function c:connect(func,name)
+ self.ID=self.ID+1
+ table.insert(self.func,1,{func,self.ID})
+ local temp = {
+ Link=self.func,
+ func=func,
+ ID=self.ID,
+ Parent=self,
+ Fire=function(self,...)
+ if self.Parent.FC>0 then
+ for i=1,#self.Parent.FC do
+ self.Parent.FC[i]:Fire(...)
+ end
+ end
+ if self.Parent.protect then
+ local t=pcall(self.func,...)
+ if t then
+ return t
+ end
+ else
+ return self.func(...)
+ end
+ end,
+ remove=function(self)
+ for i=1,#self.Link do
+ if self.Link[i][2]~=nil then
+ if self.Link[i][2]==self.ID then
+ table.remove(self.Link,i)
+ self.remove=function() end
+ self.Link=nil
+ self.ID=nil
+ return true
+ end
+ end
+ end
+ end
+ }
+ if name then
+ self.connections[name]=temp
+ end
+ return temp
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:tofile(path)
+ end
+ return c
+end
+multi.OnObjectCreated=multi:newConnection()
+multi.OnObjectDestroyed=multi:newConnection()
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ rawset(self,'Start',self.clock())
+ while self.Active do
+ self:Do_Order()
+ end
+ print("Did you call multi:Stop()? This method should not be used when using multi:mainloop()! You now need to restart the multiManager, by using multi:reboot() and calling multi:mainloop() again or by using multi:uManager()")
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ rawset(self,'Start',self.clock())
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ function self:uManager(dt)
+ self:Do_Order()
+ end
+ self:Do_Order()
+ end
+end
+--Thread Setup Stuff
+multi:setDomainName("Threads")
+multi:setDomainName("Globals")
+-- Scheduler
+multi.scheduler=multi:newUpdater()
+multi.scheduler.Type="scheduler"
+function multi.scheduler:setStep(n)
+ self.skip=tonumber(n) or 24
+end
+multi.scheduler.Threads=multi:linkDomain("Threads")
+multi.scheduler.Globals=multi:linkDomain("Globals")
+multi.scheduler:OnUpdate(function(self)
+ for i=#self.Threads,1,-1 do
+ ret={}
+ if coroutine.status(self.Threads[i].thread)=="dead" then
+ table.remove(self.Threads,i)
+ else
+ if self.Threads[i].timer:Get()>=self.Threads[i].sleep then
+ if self.Threads[i].firstRunDone==false then
+ self.Threads[i].firstRunDone=true
+ self.Threads[i].timer:Start()
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Threads[i].ref)
+ else
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Globals)
+ end
+ if ret==true or ret==false then
+ print("Thread Ended!!!")
+ ret={}
+ end
+ end
+ if ret then
+ if ret[1]=="_kill_" then
+ table.remove(self.Threads,i)
+ elseif ret[1]=="_sleep_" then
+ self.Threads[i].timer:Reset()
+ self.Threads[i].sleep=ret[2]
+ elseif ret.Name then
+ self.Globals[ret.Name]=ret.Value
+ end
+ end
+ end
+ end
+end)
+multi.scheduler:setStep()
+multi.scheduler:Pause()
+multi.OnError=multi:newConnection()
diff --git a/oldversions/MultiManager(1.3.0).lua b/oldversions/MultiManager(1.3.0).lua
new file mode 100644
index 0000000..204ea05
--- /dev/null
+++ b/oldversions/MultiManager(1.3.0).lua
@@ -0,0 +1,1460 @@
+if table.unpack then
+ unpack=table.unpack
+end
+function table.merge(t1, t2)
+ for k,v in pairs(t2) do
+ if type(v) == 'table' then
+ if type(t1[k] or false) == 'table' then
+ table.merge(t1[k] or {}, t2[k] or {})
+ else
+ t1[k] = v
+ end
+ else
+ t1[k] = v
+ end
+ end
+ return t1
+end
+multi = {}
+multi.Version={'A',3,0}-- History: EventManager,EventManager+,MultiManager <-- Current After 6.3.0 Versioning scheme was altered. A.0.0
+multi.help=[[
+For a list of features do print(multi.Features)
+For a list of changes do print(multi.changelog)
+For current version do print(multi.Version)
+For current stage do print(multi.stage)
+For help do print(multi.help) :D
+]]
+multi.stage='stable'
+multi.Features='Current Version: '..multi.Version[1]..'.'..multi.Version[2]..'.'..multi.Version[3]..' '..multi.stage..[[
+MultiManager has 19 Objects: # indicates most commonly used 1-19 1 being the most used by me
++Events #7
++Alarms #2
++Loops #3
++Steps #4
++TSteps #6
++Triggers #16
++Tasks #12
++Connections #1 -- This is a rather new feature of this library, but has become the most useful for async handling. Knowing this is already 50% of this library
++Timers #14 -- this was tricky because these make up both Alarms and TSteps, but in purly using this standalone is almost non existent
++Jobs #11
++Process #10
++Conditions #15
++Ranges #8
++Threads #13
++Functions #5
++Queuers #17
++Updaters #9
++Watchers #18
++CustomObjects #19
+
+Constructors [Runners]
+---------------------- Note: multi is the main Processor Obj It cannot be paused or destroyed (kinda)
+intObj=multi:newProcess([string: FILE defualt: nil])
+intObj=multi:newQueuer([string: FILE defualt: nil])
+
+Constructors [ACTORS]
+--------------------- Note: everything is a multiObj!
+eventObj=multi:newEvent([function: TASK defualt: function() end])
+alarmObj=multi:newAlarm([number: SET defualt: 0])
+loopObj=multi:newLoop([function: FUNC])
+stepObj=multi:newStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SKIP defualt: 0])
+tstepObj=multi:newTStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SET defualt: 1])
+updaterObj=multi:newUpdater([number: SKIP defualt: 0])
+watcherObj=multi:newWatcher(table: NAMESPACE,string: NAME)
+multiObj=multi:newCustomObject([table: OBJREF],[string: T='process'])
+void=multi:newThread(string: name,function: func)
+
+Constructors [Semi-ACTORS]
+--------------------------
+multi:newJob(function: func,[string: name])
+multi:newRange(number: a,number: b,[number: c])
+multi:newCondition(func)
+
+Constructors [NON-ACTORS]
+-------------------------
+multi:newTrigger(function: func)
+multi:newTask(function: func)
+multi:newConnection()
+multi:newTimer()
+multi:newFunction(function: func)
+]]
+multi.changelog=[[Changelog starts at Version A.0.0
+New in A.0.0
+ Nothing really however a changelog will now be recorded! Feel free to remove this extra strings if space is a requriment
+ version.major.minor
+New in A.1.0
+ Changed: multi:newConnection(protect) method
+ Changed the way you are able to interact with it by adding the __call metamethod
+ Old usage:
+ OnUpdate=multi:newConnection()
+ OnUpdate:connect(function(...)
+ print("Updating",...)
+ end)
+ OnUpdate:Fire(1,2,3)
+ New usage: notice that connect is no longer needed! Both ways still work! and always will work :)
+ OnUpdate=multi:newConnection()
+ OnUpdate(function(...)
+ print("Updating",...)
+ end)
+ OnUpdate:Fire(1,2,3)
+New in A.2.0 (12/31/2016)
+ Added:
+ connectionobj.getConnection(name)
+ returns a list of an instance (or instances) of a single connect made with connectionobj:connect(func,name) or connectionobj(func,name)
+ if you can orginize data before hand you can route info to certain connections thus saving a lot of cpu time. NOTE: only one name per each connection... you can't have 2 of the same names in a dictonary... the last one will be used
+ Changed: obj=multi:newConnection()
+ obj:connect(func,name) and obj(func,name)
+ Added the name argument to allow indexing specific connection objects... Useful when creating an async library
+New in A.3.0 (1/29/2017)
+ Added:
+ Load detection!
+ multi.threshold -- minimum amount of cycles that all mObjs should be allotted before the Manager is considered burdened. Defualt: 256
+ multi.threstimed -- amount of time when counting the number of cycles, Greater gives a more accurate view of the load, but takes more time. Defualt: .001
+ multi:setThreshold(n) -- method used to set multi.threshold
+ multi:setThrestimed(n) -- method used to set multi.threstimed
+ multi:getLoad() -- returns a number between 0 and 100
+]]
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.ender={}
+multi.Children={}
+multi.Paused={}
+multi.Active=true
+multi.fps=60
+multi.Id=-1
+multi.Type='mainprocess'
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+multi.clock=os.clock
+multi.time=os.time
+multi.LinkedPath=multi
+multi.queuefinal=function(self)
+ self:Destroy()
+ if self.Parent.Mainloop[#self.Parent.Mainloop] then
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ else
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+end
+--Do not change these ever...Any other number will not work (Unless you are using enablePriority2() then change can be made. Just ensure that Priority_Idle is the greatest and Priority_Core is 1!)
+multi.Priority_Core=1
+multi.Priority_High=4
+multi.Priority_Above_Normal=16
+multi.Priority_Normal=64
+multi.Priority_Below_Normal=256
+multi.Priority_Low=1024
+multi.Priority_Idle=4096
+multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
+multi.PStep=1
+--^^^^
+multi.PriorityTick=1 -- Between 1 and 4 any greater and problems arise
+multi.Priority=multi.Priority_Core
+multi.threshold=256
+multi.threstimed=.001
+function multi:setThreshold(n)
+ self.threshold=n or 120
+end
+function multi:setThrestimed(n)
+ self.threstimed=n or .001
+end
+function multi:getLoad()
+ return multi:newFunction(function(self)
+ local sample=#multi.Mainloop
+ local FFloadtest=0
+ multi:benchMark(multi.threstimed):OnBench(function(_,l3) FFloadtest=l3*(1/multi.threstimed) end)
+ self:hold(function() return FFloadtest~=0 end)
+ local val=FFloadtest/sample
+ if val>multi.threshold then
+ return 0
+ else
+ return 100-((val/multi.threshold)*100)
+ end
+ end)()
+end
+function multi:setDomainName(name)
+ self[name]={}
+end
+function multi:linkDomain(name)
+ return self[name]
+end
+function multi:_Pause()
+ self.Active=false
+end
+function multi:setPriority(s)
+ if type(s)==number then
+ self.Priority=s
+ elseif type(s)=='string' then
+ if s:lower()=='core' or s:lower()=='c' then
+ self.Priority=self.Priority_Core
+ elseif s:lower()=='high' or s:lower()=='h' then
+ self.Priority=self.Priority_High
+ elseif s:lower()=='above' or s:lower()=='an' then
+ self.Priority=self.Priority_Above_Normal
+ elseif s:lower()=='normal' or s:lower()=='n' then
+ self.Priority=self.Priority_Normal
+ elseif s:lower()=='below' or s:lower()=='bn' then
+ self.Priority=self.Priority_Below_Normal
+ elseif s:lower()=='low' or s:lower()=='l' then
+ self.Priority=self.Priority_Low
+ elseif s:lower()=='idle' or s:lower()=='i' then
+ self.Priority=self.Priority_Idle
+ end
+ end
+end
+-- System
+function os.getOS()
+ if package.config:sub(1,1)=='\\' then
+ return 'windows'
+ else
+ return 'unix'
+ end
+end
+if os.getOS()=='windows' then
+ function os.sleep(n)
+ if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end
+ end
+else
+ function os.sleep(n)
+ os.execute('sleep ' .. tonumber(n))
+ end
+end
+function multi:getParentProcess()
+ return self.Mainloop[self.CID]
+end
+function multi:Stop()
+ self.Active=false
+end
+function multi:condition(cond)
+ if not self.CD then
+ self:Pause()
+ self.held=true
+ self.CD=cond.condition
+ elseif not(cond.condition()) then
+ self.held=false
+ self:Resume()
+ self.CD=nil
+ return false
+ end
+ self.Parent:Do_Order()
+ return true
+end
+function multi:isHeld()
+ return self.held
+end
+function multi.executeFunction(name,...)
+ if type(_G[name])=='function' then
+ _G[name](...)
+ else
+ print('Error: Not a function')
+ end
+end
+function multi:waitFor(obj)
+ self:hold(function() return obj:isActive() end)
+end
+function multi:reboot(r)
+ local before=collectgarbage('count')
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=='table' then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+ collectgarbage()
+ local after=collectgarbage('count')
+ print([[Before rebooting total Ram used was ]]..before..[[Kb
+After rebooting total Ram used is ]]..after..[[ Kb
+A total of ]]..(before-after)..[[Kb was cleaned up]])
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:getError()
+ if self.error then
+ return self.error
+ end
+end
+function multi:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:enablePriority()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>7 then
+ PS.PStep=1
+ end
+ end
+end
+function multi:enablePriority2()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PStep)%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>self.Priority_Idle then
+ PS.PStep=1
+ end
+ end
+end
+multi.disablePriority=multi.unProtect
+function multi:fromfile(path,int)
+ int=int or self
+ local test2={}
+ local test=bin.load(path)
+ local tp=test:getBlock('s')
+ if tp=='event' then
+ test2=int:newEvent(test:getBlock('f'))
+ local t=test:getBlock('t')
+ for i=1,#t do
+ test2:OnEvent(t[i])
+ end
+ elseif tp=='alarm' then
+ test2=int:newAlarm(test:getBlock('n'))
+ elseif tp=='loop' then
+ test2=int:newLoop(test:getBlock('t')[1])
+ elseif tp=='step' or tp=='tstep' then
+ local func=test:getBlock('t')
+ local funcE=test:getBlock('t')
+ local funcS=test:getBlock('t')
+ local tab=test:getBlock('t')
+ test2=int:newStep()
+ table.merge(test2,tab)
+ test2.funcE=funcE
+ test2.funcS=funcS
+ test2.func=func
+ elseif tp=='trigger' then
+ test2=int:newTrigger(test:getBlock('f'))
+ elseif tp=='connector' then
+ test2=int:newConnection()
+ test2.func=test:getBlock('t')
+ elseif tp=='timer' then
+ test2=int:newTimer()
+ test2.count=tonumber(test:getBlock('n'))
+ else
+ print('Error: The file you selected is not a valid multi file object!')
+ return false
+ end
+ return test2
+end
+function multi:benchMark(sec,p)
+ local temp=self:newLoop(function(t,self)
+ if self.clock()-self.init>self.sec then
+ self.tt(self.sec,self.c)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ temp.Priority=p or 1
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=self.clock()
+ temp.c=0
+ return temp
+end
+function multi:tofile(path)
+ local items=self:getChildren()
+ io.mkDir(io.getName(path))
+ for i=1,#items do
+ items[i]:tofile(io.getName(path)..'\\item'..item[i]..'.dat')
+ end
+ local int=bin.new()
+ int:addBlock('process')
+ int:addBlock(io.getName(path))
+ int:addBlock(#self.Mainloop)
+ int:addBlock(self.Active)
+ int:addBlock(self.Rest)
+ int:addBlock(self.Jobs)
+ int:tofile()
+end
+function multi.startFPSMonitior()
+ if not multi.runFPS then
+ multi.doFPS(s)
+ multi.runFPS=true
+ end
+end
+function multi.doFPS(s)
+ multi:benchMark(1):OnBench(doFPS)
+ if s then
+ multi.fps=s
+ end
+end
+--Helpers
+function multi:OnMainConnect(func)
+ table.insert(self.func,func)
+end
+function multi:protect()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ self.CID=_D
+ local status, err=pcall(Loop[_D].Act,Loop[_D])
+ if err and not(Loop[_D].error) then
+ Loop[_D].error=err
+ self.OnError:Fire(err,Loop[_D])
+ end
+ end
+ end
+ end
+end
+function multi:unProtect()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:connectFinal(func)
+ if self.Type=='event' then
+ self:OnEvent(func)
+ elseif self.Type=='alarm' then
+ self:OnRing(func)
+ elseif self.Type=='step' or self.Type=='tstep' then
+ self:OnEnd(func)
+ else
+ print("Warning!!! "..self.Type.." doesn't contain a Final Connection State! Use "..self.Type..":Break(function) to trigger it's final event!")
+ self:OnBreak(func)
+ end
+end
+function multi:Break()
+ self:Pause()
+ self.Active=nil
+ for i=1,#self.ender do
+ if self.ender[i] then
+ self.ender[i](self)
+ end
+ end
+end
+function multi:OnBreak(func)
+ table.insert(self.ender,func)
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:isActive()
+ return self.Active
+end
+function multi:getType()
+ return self.Type
+end
+function multi:Sleep(n)
+ self:hold(n)
+end
+function multi:Pause()
+ if self.Type=='mainprocess' then
+ print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()")
+ else
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:resurrect()
+ table.insert(self.Parent.Mainloop,self)
+ self.Active=true
+end
+function multi:Destroy()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ local c=self:getChildren()
+ for i=1,#c do
+ self.OnObjectDestroyed:Fire(c[i])
+ c[i]:Destroy()
+ end
+ else
+ for i=1,#self.Parent.Mainloop do
+ if self.Parent.Mainloop[i]==self then
+ self.Parent.OnObjectDestroyed:Fire(self)
+ table.remove(self.Parent.Mainloop,i)
+ break
+ end
+ end
+ self.Active=false
+ end
+end
+
+function multi:hold(task)
+ self:Pause()
+ self.held=true
+ if type(task)=='number' then
+ local alarm=self.Parent:newAlarm(task)
+ while alarm.Active==true do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ alarm:Destroy()
+ self:Resume()
+ self.held=false
+ elseif type(task)=='function' then
+ local env=self.Parent:newEvent(task)
+ env:OnEvent(function(envt) envt:Pause() envt.Active=false end)
+ while env.Active do
+ if love then
+ self.Parent:lManager()
+ else
+ self.Parent:Do_Order()
+ end
+ end
+ env:Destroy()
+ self:Resume()
+ self.held=false
+ else
+ print('Error Data Type!!!')
+ end
+end
+function multi:oneTime(func,...)
+ if not(self.Type=='mainprocess' or self.Type=='process') then
+ for _k=1,#self.Parent.Tasks2 do
+ if self.Parent.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Parent.Tasks2,func)
+ func(...)
+ return true
+ else
+ for _k=1,#self.Tasks2 do
+ if self.Tasks2[_k]==func then
+ return false
+ end
+ end
+ table.insert(self.Tasks2,func)
+ func(...)
+ return true
+ end
+end
+function multi:Reset(n)
+ self:Resume()
+end
+function multi:isDone()
+ return self.Active~=true
+end
+function multi:create(ref)
+ multi.OnObjectCreated:Fire(ref)
+end
+--Constructors [CORE]
+function multi:newBase(ins)
+ if not(self.Type=='mainprocess' or self.Type=='process' or self.Type=='queue') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='process' or self.Type=='queue' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.ender={}
+ c.Id=0
+ c.PId=0
+ c.Act=function() end
+ c.Parent=self
+ c.held=false
+ if ins then
+ table.insert(self.Mainloop,ins,c)
+ else
+ table.insert(self.Mainloop,c)
+ end
+ return c
+end
+function multi:newProcess(file)
+ if not(self.Type=='mainprocess') then error('Can only create an interface on the multi obj') return false end
+ local c = {}
+ setmetatable(c, self)
+ c.Parent=self
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.Type='process'
+ c.Mainloop={}
+ c.Tasks={}
+ c.Tasks2={}
+ c.Garbage={}
+ c.Children={}
+ c.Paused={}
+ c.Active=true
+ c.Id=-1
+ c.Rest=0
+ c.Jobs={}
+ c.queue={}
+ c.jobUS=2
+ function c:Start()
+ if self.l then
+ self.l:Resume()
+ else
+ self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
+ end
+ end
+ function c:Pause()
+ if self.l then
+ self.l:Pause()
+ end
+ end
+ function c:Remove()
+ self:Destroy()
+ self.l:Destroy()
+ end
+ if file then
+ self.Cself=c
+ loadstring('local interface=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ self:create(c)
+ return c
+end
+function multi:newQueuer(file)
+ local c=self:newProcess()
+ c.Type='queue'
+ c.last={}
+ c.funcE={}
+ function c:OnQueueCompleted(func)
+ table.insert(self.funcE,func)
+ end
+ if file then
+ self.Cself=c
+ loadstring('local queue=multi.Cself '..io.open(file,'rb'):read('*all'))()
+ end
+ self:create(c)
+ return c
+end
+--Constructors [ACTORS]
+function multi:newCustomObject(objRef,t)
+ local c={}
+ if t=='process' then
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ print("This Custom Object was created on a queue! Ensure that it has a way to end! All objects have a obj:Break() method!")
+ else
+ c=self:newBase()
+ end
+ if type(objRef)=='table' then
+ table.merge(c,objRef)
+ end
+ if not c.Act then
+ function c:Act()
+ -- Empty function
+ end
+ end
+ else
+ c=objRef or {}
+ end
+ if not c.Type then
+ c.Type='coustomObject'
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newEvent(task)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='event'
+ c.Task=task or function() end
+ function c:Act()
+ if self.Task(self) then
+ self:Pause()
+ for _E=1,#self.func do
+ self.func[_E](self)
+ end
+ end
+ end
+ function c:OnEvent(func)
+ table.insert(self.func,func)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.Task)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newAlarm(set)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='alarm'
+ c.Priority=self.Priority_Low
+ c.timer=self:newTimer()
+ c.set=set or 0
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.set)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.timer:Get()>=self.set then
+ self:Pause()
+ self.Active=false
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ function c:Resume()
+ self.Parent.Resume(self)
+ self.timer:Resume()
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self:Resume()
+ self.timer:Reset()
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ function c:Pause()
+ self.timer:Pause()
+ self.Parent.Pause(self)
+ end
+ if self.Type=='queue' then
+ c:Pause()
+ c:connectFinal(multi.queuefinal)
+ else
+ c.timer:Start()
+ end
+ self:create(c)
+ return c
+end
+function multi:newLoop(func)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='loop'
+ c.Start=self.clock()
+ if func then
+ c.func={func}
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ for i=1,#self.func do
+ self.func[i](self.Parent.clock()-self.Start,self)
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newUpdater(skip)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ c.Type='updater'
+ c.pos=1
+ c.skip=skip or 1
+ function c:Act()
+ if self.pos>=self.skip then
+ self.pos=0
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ self.pos=self.pos+1
+ end
+ function c:setSkip(n)
+ self.skip=n
+ end
+ c.OnUpdate=self.OnMainConnect
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='step'
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ c.Reset=c.Resume
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c={}
+ if self.Type=='queue' then
+ c=self:newBase(1)
+ self.last=c
+ else
+ c=self:newBase()
+ end
+ think=1
+ c.Type='tstep'
+ c.Priority=self.Priority_Low
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=self.clock()
+ c.set=set or 1
+ c.funcS={}
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=self.start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=self.clock()
+ self:Resume()
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=self.clock()
+ self:Resume()
+ end
+ if self.Type=='queue' then
+ if #self.Mainloop>1 then
+ c:Pause()
+ end
+ c:connectFinal(multi.queuefinal)
+ end
+ self:create(c)
+ return c
+end
+function multi:newWatcher(namespace,name)
+ local function WatcherObj(ns,n)
+ if self.Type=='queue' then
+ print("Cannot create a watcher on a queue! Creating on 'multi' instead!")
+ self=multi
+ end
+ local c=self:newBase()
+ c.Type='watcher'
+ c.ns=ns
+ c.n=n
+ c.cv=ns[n]
+ function c:OnValueChanged(func)
+ table.insert(self.func,func)
+ end
+ function c:Act()
+ if self.cv~=self.ns[self.n] then
+ for i=1,#self.func do
+ self.func[i](self,self.cv,self.ns[self.n])
+ end
+ self.cv=self.ns[self.n]
+ end
+ end
+ self:create(c)
+ return c
+ end
+ if type(namespace)~='table' and type(namespace)=='string' then
+ return WatcherObj(_G,namespace)
+ elseif type(namespace)=='table' and (type(name)=='string' or 'number') then
+ return WatcherObj(namespace,name)
+ else
+ print('Warning, invalid arguments! Nothing returned!')
+ end
+end
+function multi:newThread(name,func)
+ local c={}
+ c.ref={}
+ c.Name=name
+ c.thread=coroutine.create(func)
+ c.sleep=1
+ c.firstRunDone=false
+ c.timer=multi.scheduler:newTimer()
+ c.ref.Globals=self:linkDomain("Globals")
+ function c.ref:send(name,val)
+ ret=coroutine.yield({Name=name,Value=val})
+ self:syncGlobals(ret)
+ end
+ function c.ref:get(name)
+ return self.Globals[name]
+ end
+ function c.ref:kill()
+ err=coroutine.yield({"_kill_"})
+ if err then
+ error("Failed to kill a thread! Exiting...")
+ end
+ end
+ function c.ref:sleep(n)
+ n = tonumber(n) or 0
+ ret=coroutine.yield({"_sleep_",n})
+ self:syncGlobals(ret)
+ end
+ function c.ref:syncGlobals(v)
+ self.Globals=v
+ end
+ table.insert(self:linkDomain("Threads"),c)
+ if not multi.scheduler:isActive() then
+ multi.scheduler:Resume()
+ end
+end
+-- Constructors [SEMI-ACTORS]
+function multi:newJob(func,name)
+ if not(self.Type=='mainprocess' or self.Type=='process') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='process' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type='job'
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+function multi:newRange()
+ local selflink=self
+ local temp={
+ getN = function(self) selflink:Do_Order() self.n=self.n+self.c if self.n>self.b then self.Link.held=false self.Link:Resume() return nil end return self.n end,
+ }
+ setmetatable(temp,{
+ __call=function(self,a,b,c)
+ self.c=c or 1
+ self.n=a-self.c
+ self.a=a
+ self.b=b
+ self.Link=selflink--.Parent.Mainloop[selflink.CID] or
+ self.Link:Pause()
+ self.Link.held=true
+ return function() return self:getN() end
+ end
+ })
+ self:create(temp)
+ return temp
+end
+function multi:newCondition(func)
+ local c={['condition']=func}
+ self:create(c)
+ return c
+end
+-- Constructors [NON-ACTORS]
+function multi:newFunction(func)
+ local c={}
+ c.func=func
+ mt={
+ __index=multi,
+ __call=function(self,...) if self.Active then return self:func(...) end local t={...} return "PAUSED" end
+ }
+ c.Parent=self
+ function c:Pause()
+ self.Active=false
+ end
+ function c:Resume()
+ self.Active=true
+ end
+ setmetatable(c,mt)
+ self:create(c)
+ return c
+end
+function multi:newTimer()
+ local c={}
+ c.Type='timer'
+ c.time=0
+ c.count=0
+ function c:Start()
+ self.time=os.clock()
+ end
+ function c:Get()
+ return (os.clock()-self.time)+self.count
+ end
+ c.Reset=c.Start
+ function c:Pause()
+ self.time=self:Get()
+ end
+ function c:Resume()
+ self.time=os.clock()-self.time
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ self.count=self.count+self:Get()
+ m:addBlock(self.Type)
+ m:addBlock(self.count)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newTrigger(func)
+ local c={}
+ c.Type='trigger'
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.trigfunc)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newConnection(protect)
+ local c={}
+ setmetatable(c,{__call=function(self,...) self:connect(...) end})
+ c.Type='connector'
+ c.func={}
+ c.ID=0
+ c.protect=protect or true
+ c.connections={}
+ c.fconnections={}
+ c.FC=0
+ function c:fConnect(func)
+ local temp=self:connect(func)
+ table.insert(self.fconnections,temp)
+ self.FC=self.FC+1
+ end
+ function c:getConnection(name,ingore)
+ if ingore then
+ return self.connections[name] or {
+ Fire=function() end -- if the connection doesn't exist lets call all of them or silently ingore
+ }
+ else
+ return self.connections[name] or self
+ end
+ end
+ function c:Fire(...)
+ local ret={}
+ for i=#self.func,1,-1 do
+ if self.protect then
+ local temp={pcall(self.func[i][1],...)}
+ if temp[1] then
+ table.remove(temp,1)
+ table.insert(ret,temp)
+ else
+ print(temp[2])
+ end
+ else
+ table.insert(ret,{self.func[i][1](...)})
+ end
+ end
+ return ret
+ end
+ function c:bind(t)
+ self.func=t
+ end
+ function c:remove()
+ self.func={}
+ end
+ function c:connect(func,name)
+ self.ID=self.ID+1
+ table.insert(self.func,1,{func,self.ID})
+ local temp = {
+ Link=self.func,
+ func=func,
+ ID=self.ID,
+ Parent=self,
+ Fire=function(self,...)
+ if self.Parent.FC>0 then
+ for i=1,#self.Parent.FC do
+ self.Parent.FC[i]:Fire(...)
+ end
+ end
+ if self.Parent.protect then
+ local t=pcall(self.func,...)
+ if t then
+ return t
+ end
+ else
+ return self.func(...)
+ end
+ end,
+ remove=function(self)
+ for i=1,#self.Link do
+ if self.Link[i][2]~=nil then
+ if self.Link[i][2]==self.ID then
+ table.remove(self.Link,i)
+ self.remove=function() end
+ self.Link=nil
+ self.ID=nil
+ return true
+ end
+ end
+ end
+ end
+ }
+ if name then
+ self.connections[name]=temp
+ end
+ return temp
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:tofile(path)
+ end
+ return c
+end
+multi.OnObjectCreated=multi:newConnection()
+multi.OnObjectDestroyed=multi:newConnection()
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ rawset(self,'Start',self.clock())
+ while self.Active do
+ self:Do_Order()
+ end
+ print("Did you call multi:Stop()? This method should not be used when using multi:mainloop()! You now need to restart the multiManager, by using multi:reboot() and calling multi:mainloop() again or by using multi:uManager()")
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ rawset(self,'Start',self.clock())
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ function self:uManager(dt)
+ self:Do_Order()
+ end
+ self:Do_Order()
+ end
+end
+--Thread Setup Stuff
+multi:setDomainName("Threads")
+multi:setDomainName("Globals")
+-- Scheduler
+multi.scheduler=multi:newUpdater()
+multi.scheduler.Type="scheduler"
+function multi.scheduler:setStep(n)
+ self.skip=tonumber(n) or 24
+end
+multi.scheduler.Threads=multi:linkDomain("Threads")
+multi.scheduler.Globals=multi:linkDomain("Globals")
+multi.scheduler:OnUpdate(function(self)
+ for i=#self.Threads,1,-1 do
+ ret={}
+ if coroutine.status(self.Threads[i].thread)=="dead" then
+ table.remove(self.Threads,i)
+ else
+ if self.Threads[i].timer:Get()>=self.Threads[i].sleep then
+ if self.Threads[i].firstRunDone==false then
+ self.Threads[i].firstRunDone=true
+ self.Threads[i].timer:Start()
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Threads[i].ref)
+ else
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Globals)
+ end
+ if ret==true or ret==false then
+ print("Thread Ended!!!")
+ ret={}
+ end
+ end
+ if ret then
+ if ret[1]=="_kill_" then
+ table.remove(self.Threads,i)
+ elseif ret[1]=="_sleep_" then
+ self.Threads[i].timer:Reset()
+ self.Threads[i].sleep=ret[2]
+ elseif ret.Name then
+ self.Globals[ret.Name]=ret.Value
+ end
+ end
+ end
+ end
+end)
+multi.scheduler:setStep()
+multi.scheduler:Pause()
+multi.OnError=multi:newConnection()
diff --git a/oldversions/MultiManager(1.4.1).lua b/oldversions/MultiManager(1.4.1).lua
new file mode 100644
index 0000000..b370e19
--- /dev/null
+++ b/oldversions/MultiManager(1.4.1).lua
@@ -0,0 +1,1518 @@
+if table.unpack then
+ unpack=table.unpack
+end
+function table.merge(t1, t2)
+ for k,v in pairs(t2) do
+ if type(v) == 'table' then
+ if type(t1[k] or false) == 'table' then
+ table.merge(t1[k] or {}, t2[k] or {})
+ else
+ t1[k] = v
+ end
+ else
+ t1[k] = v
+ end
+ end
+ return t1
+end
+_print=print
+function print(...)
+ if not __SUPPRESSPRINTS then
+ _print(...)
+ end
+end
+multi = {}
+multi.Version={'A',4,1}-- History: EventManager,EventManager+,MultiManager <-- Current After 6.3.0 Versioning scheme was altered. A.0.0
+multi.help=[[
+For a list of features do print(multi.Features)
+For a list of changes do print(multi.changelog)
+For current version do print(multi.Version)
+For current stage do print(multi.stage)
+For help do print(multi.help) :D
+]]
+multi.stage='stable'
+multi.Features='Current Version: '..multi.Version[1]..'.'..multi.Version[2]..'.'..multi.Version[3]..' '..multi.stage..[[
+MultiManager has 19 Objects: # indicates most commonly used 1-19 1 being the most used by me
++Events #7
++Alarms #2
++Loops #3
++Steps #4
++TSteps #6
++Triggers #16
++Tasks #12
++Connections #1 -- This is a rather new feature of this library, but has become the most useful for async handling. Knowing this is already 50% of this library
++Timers #14 -- this was tricky because these make up both Alarms and TSteps, but in purly using this standalone is almost non existent
++Jobs #11
++Process #10
++Conditions #15
++Ranges #8
++Threads #13
++Functions #5
++Queuers #17
++Updaters #9
++Watchers #18
++CustomObjects #19
+
+Constructors [Runners]
+---------------------- Note: multi is the main Processor Obj It cannot be paused or destroyed (kinda)
+ProcessObj=multi:newProcess([string: FILE defualt: nil])
+ProcessObj=multi:newQueuer([string: FILE defualt: nil])
+
+NOTE: The multi namespace is also a ProcessObj
+
+
+Constructors [ACTORS]
+--------------------- Note: everything is a multiObj!
+eventObj=multi:newEvent([function: TASK defualt: function() end])
+alarmObj=multi:newAlarm([number: SET defualt: 0])
+loopObj=multi:newLoop([function: FUNC])
+stepObj=multi:newStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SKIP defualt: 0])
+tstepObj=multi:newTStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SET defualt: 1])
+updaterObj=multi:newUpdater([number: SKIP defualt: 0])
+watcherObj=multi:newWatcher(table: NAMESPACE,string: NAME)
+multiObj=multi:newCustomObject([table: OBJREF],[string: T='process'])
+
+Constructors [Semi-ACTORS]
+--------------------------
+multi:newJob(function: func,[string: name])
+multi:newRange(number: a,number: b,[number: c])
+multi:newCondition(func)
+void=multi:newThread(string: name,function: func)
+
+Constructors [NON-ACTORS]
+-------------------------
+multi:newTrigger(function: func)
+multi:newTask(function: func)
+multi:newConnection()
+multi:newTimer()
+multi:newFunction(function: func)
+]]
+multi.changelog=[[Changelog starts at Version A.0.0
+New in A.0.0
+ Nothing really however a changelog will now be recorded! Feel free to remove this extra strings if space is a requirement
+ version.major.minor
+New in A.1.0
+ Changed: multi:newConnection(protect) method
+ Changed the way you are able to interact with it by adding the __call metamethod
+ Old usage:
+ OnUpdate=multi:newConnection()
+ OnUpdate:connect(function(...)
+ print("Updating",...)
+ end)
+ OnUpdate:Fire(1,2,3)
+ New usage: notice that connect is no longer needed! Both ways still work! and always will work :)
+ OnUpdate=multi:newConnection()
+ OnUpdate(function(...)
+ print("Updating",...)
+ end)
+ OnUpdate:Fire(1,2,3)
+New in A.2.0 (12/31/2016)
+ Added:
+ connectionobj.getConnection(name)
+ returns a list of an instance (or instances) of a single connect made with connectionobj:connect(func,name) or connectionobj(func,name)
+ if you can orginize data before hand you can route info to certain connections thus saving a lot of cpu time. NOTE: only one name per each connection... you can't have 2 of the same names in a dictonary... the last one will be used
+ Changed: obj=multi:newConnection()
+ obj:connect(func,name) and obj(func,name)
+ Added the name argument to allow indexing specific connection objects... Useful when creating an async library
+New in A.3.0 (1/29/2017)
+ Added:
+ Load detection!
+ multi.threshold -- minimum amount of cycles that all mObjs should be allotted before the Manager is considered burdened. Defualt: 256
+ multi.threstimed -- amount of time when counting the number of cycles, Greater gives a more accurate view of the load, but takes more time. Defualt: .001
+ multi:setThreshold(n) -- method used to set multi.threshold
+ multi:setThrestimed(n) -- method used to set multi.threstimed
+ multi:getLoad() -- returns a number between 0 and 100
+New in A.4.0 (3/20/2017)
+ Added:
+ multiobj:reallocate(ProcessObj) -- changes the parent process of an object
+ ProcessObj:getController() -- returns the mThread so you can opperate on it like a multiobj
+ Example1:
+ require("multimanager") -- require the library
+ int1=multi:newProcess() -- create a process
+ int1.NAME="int1" -- give it a name for example purposes
+ int2=multi:newProcess() -- create another process to reallocate
+ int2.NAME="int2" -- name this a different name
+ step=int1:newTStep(1,10) -- create a TStep so we can slowly see what is going on
+ step:OnStep(function(p,s) -- connect to the onstep event
+ print(p,s.Parent.NAME) -- print the position and process name
+ end)
+ step:OnEnd(function(s) -- when the step ends lets reallocate it to the other process
+ if s.Parent.NAME=="int1" then -- lets only do this if it is in the int1 process
+ s:reallocate(int2) -- send it to int2
+ s:Reset() -- reset the object
+ else
+ print("We are done!")
+ os.exit() -- end the program when int2 did its thing
+ end
+ end)
+ int1:Start() -- start process 1
+ int2:Start() -- start process 2
+ multi:mainloop() -- start the main loop
+ Fixed/Updated:
+ queuer=multi:newQueuer([string: file])
+ Alarms now preform as they should on a queuer
+ Example2:
+ int=multi:newQueuer()
+ step=int:newTStep(1,10,1,.5)
+ alarm=int:newAlarm(2)
+ step2=int:newTStep(1,5,1,.5)
+ step:OnStep(function(p,s)
+ print(p)
+ end)
+ step2:OnStep(function(p,s)
+ print(p,"!")
+ end)
+ alarm:OnRing(function(a)
+ print("Ring1!!!")
+ end)
+ int:OnQueueCompleted(function(s)
+ s:Pause()
+ print("Done!")
+ os.exit()
+ end)
+ int:Start()
+ multi:mainloop()
+New in A.4.1 (4/10/2017)
+ Change:
+ small change to the hold method to make it a bit more lightweight
+ Using a timer instead of an alarm object!
+ Limits to hold:
+ cannot hold more than 1 object at a time, and doing so could cause a deadlock!
+ Upcomming:
+ Threaded objects wrapped in corutines, so you can hold/sleep without problems!
+]]
+multi.__index = multi
+multi.Mainloop={}
+multi.Tasks={}
+multi.Tasks2={}
+multi.Garbage={}
+multi.ender={}
+multi.Children={}
+multi.Paused={}
+multi.Active=true
+multi.fps=60
+multi.Id=-1
+multi.Type='mainprocess'
+multi.Rest=0
+multi._type=type
+multi.Jobs={}
+multi.queue={}
+multi.jobUS=2
+multi.clock=os.clock
+multi.time=os.time
+multi.LinkedPath=multi
+multi.queuefinal=function(self)
+ self:Destroy()
+ if self.Parent.Mainloop[#self.Parent.Mainloop] then
+ if self.Parent.Mainloop[#self.Parent.Mainloop].Type=="alarm" then
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Reset()
+ self.Parent.Mainloop[#self.Parent.Mainloop].Active=true
+ else
+ self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
+ end
+ else
+ for i=1,#self.Parent.funcE do
+ self.Parent.funcE[i](self)
+ end
+ self.Parent:Remove()
+ end
+end
+--Do not change these ever...Any other number will not work (Unless you are using enablePriority2() then change can be made. Just ensure that Priority_Idle is the greatest and Priority_Core is 1!)
+multi.Priority_Core=1
+multi.Priority_High=4
+multi.Priority_Above_Normal=16
+multi.Priority_Normal=64
+multi.Priority_Below_Normal=256
+multi.Priority_Low=1024
+multi.Priority_Idle=4096
+multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
+multi.PStep=1
+--^^^^
+multi.PriorityTick=1 -- Between 1 and 4 any greater and problems arise
+multi.Priority=multi.Priority_Core
+multi.threshold=256
+multi.threstimed=.001
+function multi:setThreshold(n)
+ self.threshold=n or 120
+end
+function multi:setThrestimed(n)
+ self.threstimed=n or .001
+end
+function multi:getLoad()
+ return multi:newFunction(function(self)
+ local sample=#multi.Mainloop
+ local FFloadtest=0
+ multi:benchMark(multi.threstimed):OnBench(function(_,l3) FFloadtest=l3*(1/multi.threstimed) end)
+ self:hold(function() return FFloadtest~=0 end)
+ local val=FFloadtest/sample
+ if val>multi.threshold then
+ return 0
+ else
+ return 100-((val/multi.threshold)*100)
+ end
+ end)()
+end
+function multi:setDomainName(name)
+ self[name]={}
+end
+function multi:linkDomain(name)
+ return self[name]
+end
+function multi:_Pause()
+ self.Active=false
+end
+function multi:setPriority(s)
+ if type(s)==number then
+ self.Priority=s
+ elseif type(s)=='string' then
+ if s:lower()=='core' or s:lower()=='c' then
+ self.Priority=self.Priority_Core
+ elseif s:lower()=='high' or s:lower()=='h' then
+ self.Priority=self.Priority_High
+ elseif s:lower()=='above' or s:lower()=='an' then
+ self.Priority=self.Priority_Above_Normal
+ elseif s:lower()=='normal' or s:lower()=='n' then
+ self.Priority=self.Priority_Normal
+ elseif s:lower()=='below' or s:lower()=='bn' then
+ self.Priority=self.Priority_Below_Normal
+ elseif s:lower()=='low' or s:lower()=='l' then
+ self.Priority=self.Priority_Low
+ elseif s:lower()=='idle' or s:lower()=='i' then
+ self.Priority=self.Priority_Idle
+ end
+ end
+end
+-- System
+function os.getOS()
+ if package.config:sub(1,1)=='\\' then
+ return 'windows'
+ else
+ return 'unix'
+ end
+end
+if os.getOS()=='windows' then
+ function os.sleep(n)
+ if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end
+ end
+else
+ function os.sleep(n)
+ os.execute('sleep ' .. tonumber(n))
+ end
+end
+function multi:getParentProcess()
+ return self.Mainloop[self.CID]
+end
+function multi:Stop()
+ self.Active=false
+end
+function multi:condition(cond)
+ if not self.CD then
+ self:Pause()
+ self.held=true
+ self.CD=cond.condition
+ elseif not(cond.condition()) then
+ self.held=false
+ self:Resume()
+ self.CD=nil
+ return false
+ end
+ self.Parent:Do_Order()
+ return true
+end
+function multi:isHeld()
+ return self.held
+end
+function multi.executeFunction(name,...)
+ if type(_G[name])=='function' then
+ _G[name](...)
+ else
+ print('Error: Not a function')
+ end
+end
+function multi:waitFor(obj)
+ local value=false
+ self.__waiting=function()
+ value=true
+ end
+ obj:connectFinal(self.__waiting)
+ self:hold(function() return value end)
+end
+function multi:reboot(r)
+ local before=collectgarbage('count')
+ self.Mainloop={}
+ self.Tasks={}
+ self.Tasks2={}
+ self.Garbage={}
+ self.Children={}
+ self.Paused={}
+ self.Active=true
+ self.Id=-1
+ if r then
+ for i,v in pairs(_G) do
+ if type(i)=='table' then
+ if i.Parent and i.Id and i.Act then
+ i={}
+ end
+ end
+ end
+ end
+ collectgarbage()
+ local after=collectgarbage('count')
+ print([[Before rebooting total Ram used was ]]..before..[[Kb
+After rebooting total Ram used is ]]..after..[[ Kb
+A total of ]]..(before-after)..[[Kb was cleaned up]])
+end
+function multi:getChildren()
+ return self.Mainloop
+end
+--Processor
+function multi:getError()
+ if self.error then
+ return self.error
+ end
+end
+function multi:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:enablePriority()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>7 then
+ PS.PStep=1
+ end
+ end
+end
+function multi:enablePriority2()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ _G.ID=0
+ local PS=self
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if (PS.PStep)%Loop[_D].Priority==0 then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+ end
+ PS.PStep=PS.PStep+1
+ if PS.PStep>self.Priority_Idle then
+ PS.PStep=1
+ end
+ end
+end
+multi.disablePriority=multi.unProtect
+function multi:fromfile(path,int)
+ int=int or self
+ local test2={}
+ local test=bin.load(path)
+ local tp=test:getBlock('s')
+ if tp=='event' then
+ test2=int:newEvent(test:getBlock('f'))
+ local t=test:getBlock('t')
+ for i=1,#t do
+ test2:OnEvent(t[i])
+ end
+ elseif tp=='alarm' then
+ test2=int:newAlarm(test:getBlock('n'))
+ elseif tp=='loop' then
+ test2=int:newLoop(test:getBlock('t')[1])
+ elseif tp=='step' or tp=='tstep' then
+ local func=test:getBlock('t')
+ local funcE=test:getBlock('t')
+ local funcS=test:getBlock('t')
+ local tab=test:getBlock('t')
+ test2=int:newStep()
+ table.merge(test2,tab)
+ test2.funcE=funcE
+ test2.funcS=funcS
+ test2.func=func
+ elseif tp=='trigger' then
+ test2=int:newTrigger(test:getBlock('f'))
+ elseif tp=='connector' then
+ test2=int:newConnection()
+ test2.func=test:getBlock('t')
+ elseif tp=='timer' then
+ test2=int:newTimer()
+ test2.count=tonumber(test:getBlock('n'))
+ else
+ print('Error: The file you selected is not a valid multi file object!')
+ return false
+ end
+ return test2
+end
+function multi:benchMark(sec,p)
+ local temp=self:newLoop(function(t,self)
+ if self.clock()-self.init>self.sec then
+ self.tt(self.sec,self.c)
+ self:Destroy()
+ else
+ self.c=self.c+1
+ end
+ end)
+ temp.Priority=p or 1
+ function temp:OnBench(func)
+ self.tt=func
+ end
+ self.tt=function() end
+ temp.sec=sec
+ temp.init=self.clock()
+ temp.c=0
+ return temp
+end
+function multi:tofile(path)
+ local items=self:getChildren()
+ io.mkDir(io.getName(path))
+ for i=1,#items do
+ items[i]:tofile(io.getName(path)..'\\item'..item[i]..'.dat')
+ end
+ local int=bin.new()
+ int:addBlock('process')
+ int:addBlock(io.getName(path))
+ int:addBlock(#self.Mainloop)
+ int:addBlock(self.Active)
+ int:addBlock(self.Rest)
+ int:addBlock(self.Jobs)
+ int:tofile()
+end
+function multi.startFPSMonitior()
+ if not multi.runFPS then
+ multi.doFPS(s)
+ multi.runFPS=true
+ end
+end
+function multi.doFPS(s)
+ multi:benchMark(1):OnBench(doFPS)
+ if s then
+ multi.fps=s
+ end
+end
+--Helpers
+function multi:isAnActor()
+ return ({watcher=true,tstep=true,step=true,updater=true,loop=true,alarm=true,event=true})[self.Type]
+end
+function multi:OnMainConnect(func)
+ table.insert(self.func,func)
+end
+function multi:protect()
+ function self:Do_Order()
+ local Loop=self.Mainloop
+ for _D=#Loop,1,-1 do
+ if Loop[_D]~=nil then
+ Loop[_D].Id=_D
+ self.CID=_D
+ local status, err=pcall(Loop[_D].Act,Loop[_D])
+ if err and not(Loop[_D].error) then
+ Loop[_D].error=err
+ self.OnError:Fire(err,Loop[_D])
+ end
+ end
+ end
+ end
+end
+function multi:unProtect()
+ local Loop=self.Mainloop
+ _G.ID=0
+ for _D=#Loop,1,-1 do
+ if Loop[_D] then
+ if Loop[_D].Active then
+ Loop[_D].Id=_D
+ self.CID=_D
+ Loop[_D]:Act()
+ end
+ end
+ end
+end
+function multi:reallocate(o,n)
+ n=n or #o.Mainloop+1
+ local int=self.Parent
+ self:Destroy()
+ self.Parent=o
+ table.insert(o.Mainloop,n,self)
+ self.Active=true
+end
+function multi:setJobSpeed(n)
+ self.jobUS=n
+end
+function multi:hasJobs()
+ return #self.Jobs>0,#self.Jobs
+end
+function multi:getJobs()
+ return #self.Jobs
+end
+function multi:removeJob(name)
+ for i=#self.Jobs,1,-1 do
+ if self.Jobs[i][2]==name then
+ table.remove(self.Jobs,i)
+ end
+ end
+end
+function multi:FreeMainEvent()
+ self.func={}
+end
+function multi:connectFinal(func)
+ if self.Type=='event' then
+ self:OnEvent(func)
+ elseif self.Type=='alarm' then
+ self:OnRing(func)
+ elseif self.Type=='step' or self.Type=='tstep' then
+ self:OnEnd(func)
+ else
+ print("Warning!!! "..self.Type.." doesn't contain a Final Connection State! Use "..self.Type..":Break(function) to trigger it's final event!")
+ self:OnBreak(func)
+ end
+end
+function multi:Break()
+ self:Pause()
+ self.Active=nil
+ for i=1,#self.ender do
+ if self.ender[i] then
+ self.ender[i](self)
+ end
+ end
+end
+function multi:OnBreak(func)
+ table.insert(self.ender,func)
+end
+function multi:isPaused()
+ return not(self.Active)
+end
+function multi:isActive()
+ return self.Active
+end
+function multi:getType()
+ return self.Type
+end
+function multi:Sleep(n)
+ self:hold(n)
+end
+function multi:Pause()
+ if self.Type=='mainprocess' then
+ print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()")
+ else
+ self.Active=false
+ if self.Parent.Mainloop[self.Id]~=nil then
+ table.remove(self.Parent.Mainloop,self.Id)
+ table.insert(self.Parent.Paused,self)
+ self.PId=#self.Parent.Paused
+ end
+ end
+end
+function multi:Resume()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ self.Active=true
+ local c=self:getChildren()
+ for i=1,#c do
+ c[i]:Resume()
+ end
+ else
+ if self:isPaused() then
+ table.remove(self.Parent.Paused,self.PId)
+ table.insert(self.Parent.Mainloop,self)
+ self.Id=#self.Parent.Mainloop
+ self.Active=true
+ end
+ end
+end
+function multi:resurrect()
+ table.insert(self.Parent.Mainloop,self)
+ self.Active=true
+end
+function multi:Destroy()
+ if self.Type=='process' or self.Type=='mainprocess' then
+ local c=self:getChildren()
+ for i=1,#c do
+ self.OnObjectDestroyed:Fire(c[i])
+ c[i]:Destroy()
+ end
+ else
+ for i=1,#self.Parent.Mainloop do
+ if self.Parent.Mainloop[i]==self then
+ self.Parent.OnObjectDestroyed:Fire(self)
+ table.remove(self.Parent.Mainloop,i)
+ break
+ end
+ end
+ self.Active=false
+ end
+end
+
+function multi:hold(task)
+ self:Pause()
+ self.held=true
+ if type(task)=='number' then
+ local timer=multi:newTimer()
+ timer:Start()
+ while timer:Get()=self.set then
+ self:Pause()
+ self.Active=false
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ end
+ function c:Resume()
+ self.Parent.Resume(self)
+ self.timer:Resume()
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self:Resume()
+ self.timer:Reset()
+ end
+ function c:OnRing(func)
+ table.insert(self.func,func)
+ end
+ function c:Pause()
+ self.timer:Pause()
+ self.Parent.Pause(self)
+ end
+ self:create(c)
+ return c
+end
+function multi:newLoop(func)
+ local c=self:newBase()
+ c.Type='loop'
+ c.Start=self.clock()
+ if func then
+ c.func={func}
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ for i=1,#self.func do
+ self.func[i](self.Parent.clock()-self.Start,self)
+ end
+ end
+ function c:OnLoop(func)
+ table.insert(self.func,func)
+ end
+ self:create(c)
+ return c
+end
+function multi:newUpdater(skip)
+ local c=self:newBase()
+ c.Type='updater'
+ c.pos=1
+ c.skip=skip or 1
+ function c:Act()
+ if self.pos>=self.skip then
+ self.pos=0
+ for i=1,#self.func do
+ self.func[i](self)
+ end
+ end
+ self.pos=self.pos+1
+ end
+ function c:setSkip(n)
+ self.skip=n
+ end
+ c.OnUpdate=self.OnMainConnect
+ self:create(c)
+ return c
+end
+function multi:newStep(start,reset,count,skip)
+ local c=self:newBase()
+ think=1
+ c.Type='step'
+ c.pos=start or 1
+ c.endAt=reset or math.huge
+ c.skip=skip or 0
+ c.spos=0
+ c.count=count or 1*think
+ c.funcE={}
+ c.funcS={}
+ c.start=start or 1
+ if start~=nil and reset~=nil then
+ if start>reset then
+ think=-1
+ end
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self~=nil then
+ if self.spos==0 then
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ self.spos=self.spos+1
+ if self.spos>=self.skip then
+ self.spos=0
+ end
+ end
+ c.Reset=c.Resume
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,1,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Update(start,reset,count,skip)
+ self.start=start or self.start
+ self.endAt=reset or self.endAt
+ self.skip=skip or self.skip
+ self.count=count or self.count
+ self:Resume()
+ end
+ self:create(c)
+ return c
+end
+function multi:newTStep(start,reset,count,set)
+ local c=self:newBase()
+ think=1
+ c.Type='tstep'
+ c.Priority=self.Priority_Low
+ c.start=start or 1
+ local reset = reset or math.huge
+ c.endAt=reset
+ c.pos=start or 1
+ c.skip=skip or 0
+ c.count=count or 1*think
+ c.funcE={}
+ c.timer=self.clock()
+ c.set=set or 1
+ c.funcS={}
+ function c:Update(start,reset,count,set)
+ self.start=start or self.start
+ self.pos=self.start
+ self.endAt=reset or self.endAt
+ self.set=set or self.set
+ self.count=count or self.count or 1
+ self.timer=self.clock()
+ self:Resume()
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:addBlock(self.funcE)
+ m:addBlock(self.funcS)
+ m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
+ m:addBlock(self.Active)
+ m:tofile(path)
+ end
+ function c:Act()
+ if self.clock()-self.timer>=self.set then
+ self:Reset()
+ if self.pos==self.start then
+ for fe=1,#self.funcS do
+ self.funcS[fe](self)
+ end
+ end
+ for i=1,#self.func do
+ self.func[i](self.pos,self)
+ end
+ self.pos=self.pos+self.count
+ if self.pos-self.count==self.endAt then
+ self:Pause()
+ for fe=1,#self.funcE do
+ self.funcE[fe](self)
+ end
+ self.pos=self.start
+ end
+ end
+ end
+ function c:OnStart(func)
+ table.insert(self.funcS,func)
+ end
+ function c:OnStep(func)
+ table.insert(self.func,func)
+ end
+ function c:OnEnd(func)
+ table.insert(self.funcE,func)
+ end
+ function c:Break()
+ self.Active=nil
+ end
+ function c:Reset(n)
+ if n then self.set=n end
+ self.timer=self.clock()
+ self:Resume()
+ end
+ self:create(c)
+ return c
+end
+function multi:newWatcher(namespace,name)
+ local function WatcherObj(ns,n)
+ if self.Type=='queue' then
+ print("Cannot create a watcher on a queue! Creating on 'multi' instead!")
+ self=multi
+ end
+ local c=self:newBase()
+ c.Type='watcher'
+ c.ns=ns
+ c.n=n
+ c.cv=ns[n]
+ function c:OnValueChanged(func)
+ table.insert(self.func,func)
+ end
+ function c:Act()
+ if self.cv~=self.ns[self.n] then
+ for i=1,#self.func do
+ self.func[i](self,self.cv,self.ns[self.n])
+ end
+ self.cv=self.ns[self.n]
+ end
+ end
+ self:create(c)
+ return c
+ end
+ if type(namespace)~='table' and type(namespace)=='string' then
+ return WatcherObj(_G,namespace)
+ elseif type(namespace)=='table' and (type(name)=='string' or 'number') then
+ return WatcherObj(namespace,name)
+ else
+ print('Warning, invalid arguments! Nothing returned!')
+ end
+end
+-- Constructors [SEMI-ACTORS]
+function multi:newThread(name,func)
+ local c={}
+ c.ref={}
+ c.Name=name
+ c.thread=coroutine.create(func)
+ c.sleep=1
+ c.firstRunDone=false
+ c.timer=multi.scheduler:newTimer()
+ c.ref.Globals=self:linkDomain("Globals")
+ function c.ref:send(name,val)
+ ret=coroutine.yield({Name=name,Value=val})
+ self:syncGlobals(ret)
+ end
+ function c.ref:get(name)
+ return self.Globals[name]
+ end
+ function c.ref:kill()
+ err=coroutine.yield({"_kill_"})
+ if err then
+ error("Failed to kill a thread! Exiting...")
+ end
+ end
+ function c.ref:sleep(n)
+ if type(n)=="function" then
+ ret=coroutine.yield({"_hold_",n})
+ self:syncGlobals(ret)
+ elseif type(n)=="number" then
+ n = tonumber(n) or 0
+ ret=coroutine.yield({"_sleep_",n})
+ self:syncGlobals(ret)
+ else
+ error("Invalid Type for sleep!")
+ end
+ end
+ function c.ref:syncGlobals(v)
+ self.Globals=v
+ end
+ table.insert(self:linkDomain("Threads"),c)
+ if not multi.scheduler:isActive() then
+ multi.scheduler:Resume()
+ end
+end
+function multi:newJob(func,name)
+ if not(self.Type=='mainprocess' or self.Type=='process') then error('Can only create an object on multi or an interface obj') return false end
+ local c = {}
+ if self.Type=='process' then
+ setmetatable(c, self.Parent)
+ else
+ setmetatable(c, self)
+ end
+ c.Active=true
+ c.func={}
+ c.Id=0
+ c.PId=0
+ c.Parent=self
+ c.Type='job'
+ c.trigfunc=func or function() end
+ function c:Act()
+ self:trigfunc(self)
+ end
+ table.insert(self.Jobs,{c,name})
+ if self.JobRunner==nil then
+ self.JobRunner=self:newAlarm(self.jobUS)
+ self.JobRunner:OnRing(function(self)
+ if #self.Parent.Jobs>0 then
+ if self.Parent.Jobs[1] then
+ self.Parent.Jobs[1][1]:Act()
+ table.remove(self.Parent.Jobs,1)
+ end
+ end
+ self:Reset(self.Parent.jobUS)
+ end)
+ end
+end
+function multi:newRange()
+ local selflink=self
+ local temp={
+ getN = function(self) selflink:Do_Order() self.n=self.n+self.c if self.n>self.b then self.Link.held=false self.Link:Resume() return nil end return self.n end,
+ }
+ setmetatable(temp,{
+ __call=function(self,a,b,c)
+ self.c=c or 1
+ self.n=a-self.c
+ self.a=a
+ self.b=b
+ self.Link=selflink--.Parent.Mainloop[selflink.CID] or
+ self.Link:Pause()
+ self.Link.held=true
+ return function() return self:getN() end
+ end
+ })
+ self:create(temp)
+ return temp
+end
+function multi:newCondition(func)
+ local c={['condition']=func}
+ self:create(c)
+ return c
+end
+-- Constructors [NON-ACTORS]
+function multi:newFunction(func)
+ local c={}
+ c.func=func
+ mt={
+ __index=multi,
+ __call=function(self,...) if self.Active then return self:func(...) end local t={...} return "PAUSED" end
+ }
+ c.Parent=self
+ function c:Pause()
+ self.Active=false
+ end
+ function c:Resume()
+ self.Active=true
+ end
+ setmetatable(c,mt)
+ self:create(c)
+ return c
+end
+function multi:newTimer()
+ local c={}
+ c.Type='timer'
+ c.time=0
+ c.count=0
+ function c:Start()
+ self.time=os.clock()
+ end
+ function c:Get()
+ return (os.clock()-self.time)+self.count
+ end
+ c.Reset=c.Start
+ function c:Pause()
+ self.time=self:Get()
+ end
+ function c:Resume()
+ self.time=os.clock()-self.time
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ self.count=self.count+self:Get()
+ m:addBlock(self.Type)
+ m:addBlock(self.count)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newTask(func)
+ table.insert(self.Tasks,func)
+end
+function multi:newTrigger(func)
+ local c={}
+ c.Type='trigger'
+ c.trigfunc=func or function() end
+ function c:Fire(...)
+ self:trigfunc(self,...)
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.trigfunc)
+ m:tofile(path)
+ end
+ self:create(c)
+ return c
+end
+function multi:newConnection(protect)
+ local c={}
+ setmetatable(c,{__call=function(self,...) self:connect(...) end})
+ c.Type='connector'
+ c.func={}
+ c.ID=0
+ c.protect=protect or true
+ c.connections={}
+ c.fconnections={}
+ c.FC=0
+ function c:fConnect(func)
+ local temp=self:connect(func)
+ table.insert(self.fconnections,temp)
+ self.FC=self.FC+1
+ end
+ function c:getConnection(name,ingore)
+ if ingore then
+ return self.connections[name] or {
+ Fire=function() end -- if the connection doesn't exist lets call all of them or silently ingore
+ }
+ else
+ return self.connections[name] or self
+ end
+ end
+ function c:Fire(...)
+ local ret={}
+ for i=#self.func,1,-1 do
+ if self.protect then
+ local temp={pcall(self.func[i][1],...)}
+ if temp[1] then
+ table.remove(temp,1)
+ table.insert(ret,temp)
+ else
+ print(temp[2])
+ end
+ else
+ table.insert(ret,{self.func[i][1](...)})
+ end
+ end
+ return ret
+ end
+ function c:bind(t)
+ self.func=t
+ end
+ function c:remove()
+ self.func={}
+ end
+ function c:connect(func,name)
+ self.ID=self.ID+1
+ table.insert(self.func,1,{func,self.ID})
+ local temp = {
+ Link=self.func,
+ func=func,
+ ID=self.ID,
+ Parent=self,
+ Fire=function(self,...)
+--~ if self.Parent.FC>0 then
+--~ for i=1,#self.Parent.FC do
+--~ self.Parent.FC[i]:Fire(...)
+--~ end
+--~ end
+ if self.Parent.protect then
+ local t=pcall(self.func,...)
+ if t then
+ return t
+ end
+ else
+ return self.func(...)
+ end
+ end,
+ remove=function(self)
+ for i=1,#self.Link do
+ if self.Link[i][2]~=nil then
+ if self.Link[i][2]==self.ID then
+ table.remove(self.Link,i)
+ self.remove=function() end
+ self.Link=nil
+ self.ID=nil
+ return true
+ end
+ end
+ end
+ end
+ }
+ if name then
+ self.connections[name]=temp
+ end
+ return temp
+ end
+ function c:tofile(path)
+ local m=bin.new()
+ m:addBlock(self.Type)
+ m:addBlock(self.func)
+ m:tofile(path)
+ end
+ return c
+end
+multi.OnObjectCreated=multi:newConnection()
+multi.OnObjectDestroyed=multi:newConnection()
+--Managers
+function multi:mainloop()
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ rawset(self,'Start',self.clock())
+ while self.Active do
+ self:Do_Order()
+ end
+ print("Did you call multi:Stop()? This method should not be used when using multi:mainloop()! You now need to restart the multiManager, by using multi:reboot() and calling multi:mainloop() again or by using multi:uManager()")
+end
+function multi._tFunc(self,dt)
+ for i=1,#self.Tasks do
+ self.Tasks[i](self)
+ end
+ if dt then
+ self.pump=true
+ end
+ self.pumpvar=dt
+ rawset(self,'Start',self.clock())
+end
+function multi:uManager(dt)
+ if self.Active then
+ self:oneTime(self._tFunc,self,dt)
+ function self:uManager(dt)
+ self:Do_Order()
+ end
+ self:Do_Order()
+ end
+end
+--Thread Setup Stuff
+multi:setDomainName("Threads")
+multi:setDomainName("Globals")
+-- Scheduler
+multi.scheduler=multi:newUpdater()
+multi.scheduler.Type="scheduler"
+function multi.scheduler:setStep(n)
+ self.skip=tonumber(n) or 24
+end
+multi.scheduler.Threads=multi:linkDomain("Threads")
+multi.scheduler.Globals=multi:linkDomain("Globals")
+multi.scheduler:OnUpdate(function(self)
+ for i=#self.Threads,1,-1 do
+ ret={}
+ if coroutine.status(self.Threads[i].thread)=="dead" then
+ table.remove(self.Threads,i)
+ else
+ if self.Threads[i].timer:Get()>=self.Threads[i].sleep then
+ if self.Threads[i].firstRunDone==false then
+ self.Threads[i].firstRunDone=true
+ self.Threads[i].timer:Start()
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Threads[i].ref)
+ else
+ _,ret=coroutine.resume(self.Threads[i].thread,self.Globals)
+ end
+ if ret==true or ret==false then
+ print("Thread Ended!!!")
+ ret={}
+ end
+ end
+ if ret then
+ if ret[1]=="_kill_" then
+ table.remove(self.Threads,i)
+ elseif ret[1]=="_sleep_" then
+ self.Threads[i].timer:Reset()
+ self.Threads[i].sleep=ret[2]
+ elseif ret[1]=="_hold_" then
+ self.Threads[i].timer:Reset()
+ self.Threads[i].sleep=math.huge
+ local event=multi:newEvent(ret[2])
+ event.link=self.Threads[i]
+ event:OnEvent(function(evnt)
+ evnt.link.sleep=0
+ end)
+ elseif ret.Name then
+ self.Globals[ret.Name]=ret.Value
+ end
+ end
+ end
+ end
+end)
+multi.scheduler:setStep()
+multi.scheduler:Pause()
+multi.OnError=multi:newConnection()
+---------TESTS
+multi:newThread("test",function(ref)
+ while true do
+ print(">!")
+ ref:sleep(1)
+ end
+end)
+multi:newThread("test",function(ref)
+ while true do
+ print("!<")
+ ref:sleep(1)
+ end
+end)
+multi:mainloop()
diff --git a/rockspecs/multi-1.8-6.rockspec b/rockspecs/multi-1.8-6.rockspec
new file mode 100644
index 0000000..1c64eda
--- /dev/null
+++ b/rockspecs/multi-1.8-6.rockspec
@@ -0,0 +1,30 @@
+package = "multi"
+version = "1.8-6"
+source = {
+ url = "git://github.com/rayaman/multi.git",
+ tag = "v1.8.6",
+}
+description = {
+ summary = "Lua Multi tasking library",
+ detailed = [[
+ This library contains many methods for multi tasking. From simple side by side code using multiobjs, to using coroutine based Threads and System threads(When you have lua lanes installed or are using love2d. Optional) The core of the library works on lua 5.1+ however the systemthreading features are limited to 5.1 due to love2d and lua lanes being lua 5.1 only!
+ ]],
+ homepage = "https://github.com/rayaman/multi",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1, < 5.2"
+}
+build = {
+ type = "builtin",
+ modules = {
+ -- Note the required Lua syntax when listing submodules as keys
+ ["multi.init"] = "multi/init.lua",
+ ["multi.all"] = "multi/all.lua",
+ ["multi.compat.backwards[1,5,0]"] = "multi/compat/backwards[1,5,0].lua",
+ ["multi.compat.love2d"] = "multi/compat/love2d.lua",
+ ["multi.integration.lanesManager"] = "multi/integration/lanesManager.lua",
+ ["multi.integration.loveManager"] = "multi/integration/loveManager.lua",
+ ["multi.integration.shared"] = "multi/integration/shared.lua"
+ }
+}
\ No newline at end of file