From 544aa78d70ce227ae96fd01a1b389394b1aa79e5 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Fri, 24 Dec 2021 22:47:38 -0500 Subject: [PATCH] Updated code --- changes.md | 169 ++++++++++----- multi/init.lua | 541 ++++++++++++++++++++++--------------------------- 2 files changed, 355 insertions(+), 355 deletions(-) diff --git a/changes.md b/changes.md index bc444c4..0d035fe 100644 --- a/changes.md +++ b/changes.md @@ -3,6 +3,97 @@ Table of contents --- [Update 15.1.0 - Hold the thread!](#update-1510---hold-the-thread)
[Update 15.0.0 - The art of faking it](#update-1500---the-art-of-faking-it)
[Update 14.2.0 - Bloatware Removed](#update-1420---bloatware-removed)
[Update 14.1.0 - A whole new world of possibilities](#update-1410---a-whole-new-world-of-possibilities)
[Update 14.0.0 - Consistency, Additions and Stability](#update-1400---consistency-additions-and-stability)
[Update 13.1.0 - Bug fixes and features added](#update-1310---bug-fixes-and-features-added)
[Update 13.0.0 - Added some documentation, and some new features too check it out!](#update-1300---added-some-documentation-and-some-new-features-too-check-it-out)
[Update 12.2.2 - Time for some more bug fixes!](#update-1222---time-for-some-more-bug-fixes)
[Update 12.2.1 - Time for some bug fixes!](#update-1221---time-for-some-bug-fixes)
[Update 12.2.0 - The chains of binding](#update-1220---the-chains-of-binding)
[Update 12.1.0 - Threads just can't hold on anymore](#update-1210---threads-just-cant-hold-on-anymore)
[Update: 12.0.0 - Big update (Lots of additions some changes)](#update-1200---big-update-lots-of-additions-some-changes)
[Update: 1.11.1 - Small Clarification on Love](#update-1111---small-clarification-on-love)
[Update: 1.11.0](#update-1110)
[Update: 1.10.0](#update-1100)
[Update: 1.9.2](#update-192)
[Update: 1.9.1 - Threads can now argue](#update-191---threads-can-now-argue)
[Update: 1.9.0](#update-190)
[Update: 1.8.7](#update-187)
[Update: 1.8.6](#update-186)
[Update: 1.8.5](#update-185)
[Update: 1.8.4](#update-184)
[Update: 1.8.3 - Mainloop recieves some needed overhauling](#update-183---mainloop-recieves-some-needed-overhauling)
[Update: 1.8.2](#update-182)
[Update: 1.8.1](#update-181)
[Update: 1.7.6](#update-176)
[Update: 1.7.5](#update-175)
[Update: 1.7.4](#update-174)
[Update: 1.7.3](#update-173)
[Update: 1.7.2](#update-172)
[Update: 1.7.1 - Bug Fixes Only](#update-171---bug-fixes-only)
[Update: 1.7.0 - Threading the systems](#update-170---threading-the-systems)
[Update: 1.6.0](#update-160)
[Update: 1.5.0](#update-150)
[Update: 1.4.1 (4/10/2017) - First Public release of the library](#update-141-4102017---first-public-release-of-the-library)
[Update: 1.4.0 (3/20/2017)](#update-140-3202017)
[Update: 1.3.0 (1/29/2017)](#update-130-1292017)
[Update: 1.2.0 (12.31.2016)](#update-120-12312016)
[Update: 1.1.0](#update-110)
[Update: 1.0.0](#update-100)
[Update: 0.6.3](#update-063)
[Update: 0.6.2](#update-062)
[Update: 0.6.1-6](#update-061-6)
[Update: 0.5.1-6](#update-051-6)
[Update: 0.4.1](#update-041)
[Update: 0.3.0 - The update that started it all](#update-030---the-update-that-started-it-all)
[Update: EventManager 2.0.0](#update-eventmanager-200)
[Update: EventManager 1.2.0](#update-eventmanager-120)
[Update: EventManager 1.1.0](#update-eventmanager-110)
[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)
[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different) +# Update 15.2.0 - Upgrade Complete + +Full Update Showcase + +```lua + +``` + +Added: +--- + +- multi:newTLoop() member functions + - `Loop:Set(set)` - Sets the time to wait for the TLoop + +- multi:newStep() member functions + - `Step:Count(count)` - Sets the amount a step should count by + +- multi:newTStep() member functions + - `TStep:Set(set)` - Sets the time to wait for the TStep + + +Changed: +--- + +- Connection Objects now pass on the parent object if created on a multiobj. This was to allow chaining to work properly with the new update + + ```lua + package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path + multi,thread = require("multi"):init() + + loop = multi:newTLoop() + + function loop:testing() + print("testing haha") + end + + + loop:Set(1) + t = loop:OnLoop(function() + print("Looping...") + end):testing() + + multi:mainloop() + + --[[Returns as expected: + + testing haha + Looping... + Looping... + Looping... + ... + Looping... + Looping... + Looping... + ]] + ``` + + While chaining on the OnSomeEventMethod() wasn't really a used feature, I still wanted to keep it just incase someone was relying on this working. And it does have it uses + +- All Multi Objects now use Connection objects + + `multiobj:OnSomeEvent(func)` or `multiobj.OnSomeEvent(func)` + +- Connection Objects no longer Fire with syntax sugar when attached to an object: + + `multiobj:OnSomeEvent(arg1,arg2.arg3)` No longer triggers the Fire event. As part of the update to make all objects use connections internally this little used feature had to be scrapped! + +- multi:newTStep now derives it's functionality from multi:newStep (Cut's down on code length a bit) + +- + +### Developer Note: + + +Connections are some of the most complex objects that this library has outside of some of the system threaded stuff. I tend to add features to connection objects quite often. Just last update connections can be "added" together creating a temp connection that only triggers when all of the added connections got triggered as well. Thinking about the possibilities this could give developers using the library I had to changed the base classes to use connections. + +The best part about this is that connections allow for greater control over an object's events. You can add and remove events that have been connected to as well as a lot of other things. Reference the documentation [here](./Documentation.md#non-actor-connections) + + +Removed: +--- + +Fixed: +--- +- [Issue](https://github.com/rayaman/multi/issues/30) with Lanes crashing the lua state. Fixed it with pcall +- [Issue](https://github.com/rayaman/multi/issues/29) where System threaded functions not up to date with threaded functions + +ToDo: +--- + + # Update 15.1.0 - Hold the thread! Full Update Showcase @@ -98,9 +189,11 @@ multi:mainloop() Added: --- -## multi:newSystemThreadedJobQueue(n) isEmpty() - -- returns true if the queue is empty, false if there are items in the queue. +- multi:newSystemThreadedJobQueue(n) + + `queue:isEmpty()` + + Returns true if the queue is empty, false if there are items in the queue. **Note:** a queue might be empty, but the job may still be running and not finished yet! Also if a registered function is called directly instead of pushed, it will not reflect inside the queue until the next cycle! @@ -413,6 +506,7 @@ multi:mainloop() Note: --- This was supposed to be released over a year ago, but work and other things got in my way. Pesudo Threading now works. The goal of this is so you can write modules that can be scaled up to utilize threading features when available. + Added: --- - multi:newISOThread(name,func,env) @@ -790,15 +884,18 @@ Added: -- If the created function encounters an error, it will return nil, the error message! - special variable multi.NIL was added to allow error handling in threaded functions. -- multi.NIL can be used in to force a nil value when using thread.hold() -- All functions created in the root of a thread are now converted to threaded functions, which allow for wait and connect features. **Note:** these functions are local to the function! And are only converted if they aren't set as local! Otherwise the function +- All functions created in the root of a thread are now converted to threaded functions, which allow for wait and connect features. + + **Note:** these functions are local to the function! And are only converted if they aren't set as local! Otherwise the function is converted into a threaded function + - lanes threads can now have their priority set using: sThread.priority = --- thread.Priority_Core --- thread.Priority_High --- thread.Priority_Above_Normal --- thread.Priority_Normal --- thread.Priority_Below_Normal --- thread.Priority_Low --- thread.Priority_Idle + - thread.Priority_Core + - thread.Priority_High + - thread.Priority_Above_Normal + - thread.Priority_Normal + - thread.Priority_Below_Normal + - thread.Priority_Low + - thread.Priority_Idle - thread.hold() and multi.hold() now accept connections as an argument. See example below ```lua @@ -1203,7 +1300,7 @@ L: 6543 I: 1635 ~n=n*4 ``` -P3 Ignores using a basic funceion and instead bases its processing time on the amount of cpu time is there. If cpu-time is low and a process is set at a lower priority it will get its time reduced. There is no formula, at idle almost all process work at the same speed! +P3 Ignores using a basic function and instead bases its processing time on the amount of cpu time is there. If cpu-time is low and a process is set at a lower priority it will get its time reduced. There is no formula, at idle almost all process work at the same speed! ``` C: 2120906 H: 2120906 @@ -1218,10 +1315,10 @@ Auto Priority works by seeing what should be set high or low. Due to lua not hav **Improved:** - Performance at the base level has been doubled! On my machine benchmark went from ~9mil to ~20 mil steps/s. -Note: If you write slow code this library's improbements wont make much of a difference. +Note: If you write slow code this library's improvements wont make much of a difference. - Loops have been optimised as well! Being the most used objects I felt they needed to be made as fast as possible -I usually give an example of the changes made, but this time I have an explantion for multi.nextStep(). It's not an entirely new feature since multi:newJob() does something like this, but is completely different. nextStep addes a function that is executed first on the next step. If multiple things are added to next step, then they will be executed in the order that they were added. +I usually give an example of the changes made, but this time I have an explantion for `multi.nextStep()`. It's not an entirely new feature since multi:newJob() does something like this, but is completely different. nextStep adds a function that is executed first on the next step. If multiple things are added to next step, then they will be executed in the order that they were added. Note: The upper limit of this libraries performance on my machine is ~39mil. This is simply a while loop counting up from 0 and stops after 1 second. The 20mil that I am currently getting is probably as fast as it can get since its half of the max performance possible, and each layer I have noticed that it doubles complexity. Throughout the years with this library I have seen massive improvements in speed. In the beginning we had only ~2000 steps per second. Fast right? then after some tweaks we went to about 300000 steps per second, then 600000. Some more tweaks brought me to ~1mil steps per second, then to ~4 mil then ~9 mil and now finally ~20 mil... the doubling effect that i have now been seeing means that odds are I have reach the limit. I will aim to add more features and optimize individule objects. If its possible to make the library even faster then I will go for it. @@ -1235,7 +1332,7 @@ Fixed: Changed: --- - thread.hold() now returns the arguments that were pass by the event function -- event objexts now contain a copy of what returns were made by the function that called it in a table called returns that exist inside of the object +- event objects now contain a copy of what returns were made by the function that called it in a table called returns that exist inside of the object ```lua package.path="?/init.lua;?.lua;"..package.path @@ -1935,41 +2032,6 @@ GLOBAL,sThread=require("multi.integration.loveManager").init() -- load the love2 -- Also, each thread has a .1 second delay! This is used to generate a random value for each thread! require("core.GuiManager") gui.ff.Color=Color.Black -function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a channel on both ends - local c={} - c.name=name - if love then - if love.thread then - function c:init() - self.chan=love.thread.getChannel(self.name) - function self:push(v) - self.chan:push(v) - end - function self:pop() - return self.chan:pop() - end - GLOBAL[self.name]=self - return self - end - return c - else - error("Make sure you required the love.thread module!") - end - else - c.linda=lanes.linda() - function c:push(v) - self.linda:send("Q",v) - end - function c:pop() - return ({self.linda:receive(0,"Q")})[2] - end - function c:init() - return self - end - GLOBAL[name]=c - end - return c -end queue=multi:newSystemThreadedQueue("QUEUE"):init() queue:push("This is a test") queue:push("This is a test2") @@ -2251,7 +2313,7 @@ Change: Upcomming: --- -- Threaded objects wrapped in corutines, so you can hold/sleep without problems! +- Threaded objects wrapped in coroutines, so you can hold/sleep without problems! # Update: 1.4.0 (3/20/2017) Added: @@ -2325,8 +2387,10 @@ Added: # Update: 1.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. +- 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 organize 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: --- - Started keeping track of dates @@ -2385,6 +2449,7 @@ Changed: Changed: --- - Everything, complete restructuring of the library from function based to object based. Resembles the modern version of the library + Added: --- - Love2d support basic diff --git a/multi/init.lua b/multi/init.lua index f5bfa3d..3fc6ee8 100644 --- a/multi/init.lua +++ b/multi/init.lua @@ -198,214 +198,7 @@ function multi:getTasksDetails(t) end --Helpers - --- Used with ISO Threads -local function isolateFunction(func,env) - local dmp = string.dump(func) - local env = env or {} - if setfenv then - local f = loadstring(dmp,"IsolatedThread_PesudoThreading") - setfenv(f,env) - return f - else - return load(dmp,"IsolatedThread_PesudoThreading","bt",env) - 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 - --- Advance Timer stuff -function multi:SetTime(n) - if not n then n=3 end - local c=self:newBase() - c.Type='timemaster' - c.timer=self:newTimer() - c.timer:Start() - c.set=n - c.link=self - self._timer=c.timer - function c:Act() - if self.timer:Get()>=self.set then - self.link:Pause() - for i=1,#self.link.funcTM do - self.link.funcTM[i](self.link) - end - - self:Destroy() - end - end - return self -end - -function multi:ResolveTimer(...) - self._timer:Pause() - for i=1,#self.funcTMR do - self.funcTMR[i](self,...) - end - self:Pause() - return self -end - -function multi:OnTimedOut(func) - self.funcTM[#self.funcTM+1]=func - return self -end - -function multi:OnTimerResolved(func) - self.funcTMR[#self.funcTMR+1]=func - return self -end - --- Timer stuff done -multi.PausedObjects = {} -function multi:Pause() - if self.Type=='rootprocess' then - multi.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 - local loop = self.Parent.Mainloop - for i=1,#loop do - if loop[i] == self then - multi.PausedObjects[self] = true - table.remove(loop,i) - break - end - end - end - return self -end - -function multi:Resume() - if self.Type=='process' or self.Type=='rootprocess' then - self.Active=true - local c=self:getChildren() - for i=1,#c do - c[i]:Resume() - end - else - if self.Active==false then - table.insert(self.Parent.Mainloop,self) - multi.PausedObjects[self] = nil - self.Active=true - end - end - return self -end - -function multi:Destroy() - if self.Type=='process' or self.Type=='rootprocess' then - local c=self:getChildren() - for i=1,#c do - self.OnObjectDestroyed:Fire(c[i]) - c[i]:Destroy() - end - local new = {} - for th,proc in pairs(globalThreads) do - if proc == self then - th:Destroy() - table.remove(globalThreads,th) - else - new[th]=proc - end - end - globalThreads = new - multi.setType(self,multi.DestroyedObj) - 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) - self.Destroyed = true - break - end - end - multi.setType(self,multi.DestroyedObj) - end - return self -end - -function multi:Reset(n) - self:Resume() - return self -end - -function multi:isDone() - return self.Active~=true -end - -function multi:create(ref) - multi.OnObjectCreated:Fire(ref,self) - return self -end - -function multi:setName(name) - self.Name = name - return self -end - ---Constructors [CORE] -local _tid = 0 -function multi:newBase(ins) - if not(self.Type=='rootprocess' or self.Type=='process' or self.Type=='queue' or self.Type == 'sandbox') 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' or self.Type=='sandbox' then - setmetatable(c, {__index = multi}) - else - setmetatable(c, {__index = multi}) - end - c.Active=true - c.func={} - c.funcTM={} - c.funcTMR={} - c.ender={} - c.TID = _tid - c.Act=function() end - c.Parent=self - c.creationTime = os.clock() - if ins then - table.insert(self.Mainloop,ins,c) - else - table.insert(self.Mainloop,c) - end - _tid = _tid + 1 - return c -end - -function multi:newConnector() - local c = {Type = "connector"} - return c -end - -local CRef = { - Fire = function() end -} - local ignoreconn = true - function multi:newConnection(protect,func,kill) local c={} c.callback = func @@ -416,7 +209,9 @@ function multi:newConnection(protect,func,kill) if type(t)=="table" then for i,v in pairs(t) do if v==self then - return self:Fire(select(2,...)) + local ref = self:connect(select(2,...)) + ref.root_link = select(1,...) + return ref end end return self:connect(...) @@ -535,9 +330,23 @@ function multi:newConnection(protect,func,kill) return self:connect(...) end } - setmetatable(temp,{__call=function(s,...) - return self:connect(...) - end}) + setmetatable(temp,{ + __call=function(s,...) + return self:connect(...) + end, + __index = function(t,k) + if rawget(t,"root_link") then + return t["root_link"][k] + end + return nil + end, + __newindex = function(t,k,v) + if rawget(t,"root_link") then + t["root_link"][k] = v + end + rawset(t,k,v) + end, + }) function temp:Fire(...) if self.Parent.lock then return end if self.Parent.protect then @@ -597,6 +406,190 @@ function multi:newConnection(protect,func,kill) return c end +-- Used with ISO Threads +local function isolateFunction(func,env) + local dmp = string.dump(func) + local env = env or {} + if setfenv then + local f = loadstring(dmp,"IsolatedThread_PesudoThreading") + setfenv(f,env) + return f + else + return load(dmp,"IsolatedThread_PesudoThreading","bt",env) + end +end + +function multi:Break() + self:Pause() + self.Active=nil + self.OnBreak:Fire(self) +end + +function multi:isPaused() + return not(self.Active) +end + +function multi:isActive() + return self.Active +end + +function multi:getType() + return self.Type +end + +-- Advance Timer stuff +function multi:SetTime(n) + if not n then n=3 end + local c=self:newBase() + c.Type='timemaster' + c.timer=self:newTimer() + c.timer:Start() + c.set=n + c.link=self + c.OnTimedOut = multi:newConnection() + c.OnTimerResolved = multi:newConnection() + self._timer=c.timer + function c:Act() + if self.timer:Get()>=self.set then + self.link:Pause() + self.OnTimedOut:Fire(self.link) + self:Destroy() + end + end + return self +end + +function multi:ResolveTimer(...) + self._timer:Pause() + self.OnTimerResolved:Fire(self,...) + self:Pause() + return self +end + +-- Timer stuff done +multi.PausedObjects = {} +function multi:Pause() + if self.Type=='rootprocess' then + multi.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 + local loop = self.Parent.Mainloop + for i=1,#loop do + if loop[i] == self then + multi.PausedObjects[self] = true + table.remove(loop,i) + break + end + end + end + return self +end + +function multi:Resume() + if self.Type=='process' or self.Type=='rootprocess' then + self.Active=true + local c=self:getChildren() + for i=1,#c do + c[i]:Resume() + end + else + if self.Active==false then + table.insert(self.Parent.Mainloop,self) + multi.PausedObjects[self] = nil + self.Active=true + end + end + return self +end + +function multi:Destroy() + if self.Type=='process' or self.Type=='rootprocess' then + local c=self:getChildren() + for i=1,#c do + self.OnObjectDestroyed:Fire(c[i]) + c[i]:Destroy() + end + local new = {} + for th,proc in pairs(globalThreads) do + if proc == self then + th:Destroy() + table.remove(globalThreads,th) + else + new[th]=proc + end + end + globalThreads = new + multi.setType(self,multi.DestroyedObj) + 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) + self.Destroyed = true + break + end + end + multi.setType(self,multi.DestroyedObj) + end + return self +end + +function multi:Reset(n) + self:Resume() + return self +end + +function multi:isDone() + return self.Active~=true +end + +function multi:create(ref) + self.OnObjectCreated:Fire(ref,self) + return self +end + +function multi:setName(name) + self.Name = name + return self +end + +--Constructors [CORE] +local _tid = 0 +function multi:newBase(ins) + if not(self.Type=='rootprocess' or self.Type=='process' or self.Type=='queue' or self.Type == 'sandbox') 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' or self.Type=='sandbox' then + setmetatable(c, {__index = multi}) + else + setmetatable(c, {__index = multi}) + end + c.Active=true + c.func={} + c.funcTM={} + c.funcTMR={} + c.OnBreak = multi:newConnection() + c.TID = _tid + c.Act=function() end + c.Parent=self + c.creationTime = os.clock() + if ins then + table.insert(self.Mainloop,ins,c) + else + table.insert(self.Mainloop,c) + end + _tid = _tid + 1 + return c +end + +function multi:newConnector() + local c = {Type = "connector"} + return c +end + +local CRef = { + Fire = function() end +} + multi.OnObjectCreated=multi:newConnection() multi.OnObjectDestroyed=multi:newConnection() multi.OnLoad = multi:newConnection(nil,nil,true) @@ -643,19 +636,14 @@ function multi:newEvent(task) if t[1] then self:Pause() self.returns = t - for _E=1,#self.func do - self.func[_E](self) - end + c.OnEvent:Fire(self) end end function c:SetTask(func) self.Task=func return self end - function c:OnEvent(func) - table.insert(self.func,func) - return self - end + c.OnEvent = self:newConnection() self:setPriority("core") multi:create(c) return c @@ -668,9 +656,7 @@ function multi:newUpdater(skip) function c:Act() if self.pos>=self.skip then self.pos=0 - for i=1,#self.func do - self.func[i](self) - end + self.OnUpdate:Fire(self) end self.pos=self.pos+1 end @@ -678,7 +664,7 @@ function multi:newUpdater(skip) self.skip=n return self end - c.OnUpdate=self.OnMainConnect + c.OnUpdate=self:newConnection() multi:create(c) return c end @@ -693,9 +679,7 @@ function multi:newAlarm(set) if clock()-t>=self.set then self:Pause() self.Active=false - for i=1,#self.func do - self.func[i](self) - end + self.OnRing:Fire(self) t = clock() end end @@ -710,10 +694,7 @@ function multi:newAlarm(set) t = clock() return self end - function c:OnRing(func) - table.insert(self.func,func) - return self - end + c.OnRing = self:newConnection() function c:Pause() count = clock() self.Parent.Pause(self) @@ -726,18 +707,12 @@ function multi:newLoop(func) local c=self:newBase() c.Type='loop' local start=clock() - local funcs = {} - if func then - funcs={func} - end function c:Act() - for i=1,#funcs do - funcs[i](self,clock()-start) - end + self.OnLoop:Fire(self,clock()-start) end - function c:OnLoop(func) - table.insert(funcs,func) - return self + c.OnLoop = self:newConnection() + if func then + c.OnLoop(func) end multi:create(c) return c @@ -768,6 +743,7 @@ function multi:newFunction(func) multi:create(c) return c end + function multi:newStep(start,reset,count,skip) local c=self:newBase() think=1 @@ -789,19 +765,13 @@ function multi:newStep(start,reset,count,skip) 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,self.pos) + self.OnStart:Fire(self) end + self.OnStep:Fire(self,self.pos) 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.OnEnd:Fire(self) self.pos=self.start end end @@ -812,22 +782,16 @@ function multi:newStep(start,reset,count,skip) end end c.Reset=c.Resume - function c:OnStart(func) - table.insert(self.funcS,func) - return self - end - function c:OnStep(func) - table.insert(self.func,1,func) - return self - end - function c:OnEnd(func) - table.insert(self.funcE,func) - return self - end + c.OnStart = self:newConnection() + c.OnStep = self:newConnection() + c.OnEnd = self:newConnection() function c:Break() self.Active=nil return self end + function c:Count(count) + self.count = count + end function c:Update(start,reset,count,skip) self.start=start or self.start self.endAt=reset or self.endAt @@ -846,19 +810,16 @@ function multi:newTLoop(func,set) c.timer=self:newTimer() c.life=0 c:setPriority("Low") - if func then - c.func={func} - end function c:Act() if self.timer:Get()>=self.set then - print("Acting...") self.life=self.life+1 self.timer:Reset() - for i=1,#self.func do - self.func[i](self,self.life) - end + self.OnLoop:Fire(self,self.life) end end + function c:Set(set) + self.set = set + end function c:Resume() self.Parent.Resume(self) self.timer:Resume() @@ -869,9 +830,9 @@ function multi:newTLoop(func,set) self.Parent.Pause(self) return self end - function c:OnLoop(func) - table.insert(self.func,func) - return self + c.OnLoop = self:newConnection() + if func then + c.OnLoop(func) end multi:create(c) return c @@ -880,20 +841,12 @@ function multi:setTimeout(func,t) multi:newThread(function() thread.sleep(t) func() end) end function multi:newTStep(start,reset,count,set) - local c=self:newBase() - think=1 + local c=self:newStep(start,reset,count) c.Type='tstep' c:setPriority("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=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 @@ -908,38 +861,19 @@ function multi:newTStep(start,reset,count,set) if 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,self.pos) + self.OnStart:Fire(self) end + self.OnStep:Fire(self,self.pos) 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.OnEnd:Fire(self) self.pos=self.start end end end - function c:OnStart(func) - table.insert(self.funcS,func) - return self - end - function c:OnStep(func) - table.insert(self.func,func) - return self - end - function c:OnEnd(func) - table.insert(self.funcE,func) - return self - end - function c:Break() - self.Active=nil - return self + function c:Set(set) + self.set = set end function c:Reset(n) if n then self.set=n end @@ -950,6 +884,7 @@ function multi:newTStep(start,reset,count,set) multi:create(c) return c end + local scheduledjobs = {} local sthread function multi:scheduleJob(time,func)