diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua index 22edffbd7..ebbfb67dd 100644 --- a/Moose Development/Moose/Core/Base.lua +++ b/Moose Development/Moose/Core/Base.lua @@ -124,11 +124,15 @@ end function BASE:_Destructor() --self:E("_Destructor") - self:EventRemoveAll() + --self:EventRemoveAll() end function BASE:_SetDestructor() + -- TODO: Okay, this is really technical... + -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak... + -- Therefore, I am parking this logic until I've properly discussed all this with the community. + --[[ local proxy = newproxy(true) local proxyMeta = getmetatable(proxy) @@ -143,7 +147,7 @@ function BASE:_SetDestructor() -- table is about to be garbage-collected - then the __gc hook -- will be invoked and the destructor called rawset( self, '__proxy', proxy ) - + --]] end --- This is the worker method to inherit from a parent class. diff --git a/Moose Development/Moose/Core/Scheduler.lua b/Moose Development/Moose/Core/Scheduler.lua index d8b9a0805..ce54f70d8 100644 --- a/Moose Development/Moose/Core/Scheduler.lua +++ b/Moose Development/Moose/Core/Scheduler.lua @@ -42,6 +42,7 @@ -- @extends Core.Base#BASE SCHEDULER = { ClassName = "SCHEDULER", + Schedules = {}, } --- SCHEDULER constructor. @@ -58,26 +59,88 @@ function SCHEDULER:New( TimeEventObject, TimeEventFunction, TimeEventFunctionArg local self = BASE:Inherit( self, BASE:New() ) self:F2( { StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds } ) - self.TimeEventObject = TimeEventObject - self.TimeEventFunction = TimeEventFunction - self.TimeEventFunctionArguments = TimeEventFunctionArguments - self.StartSeconds = StartSeconds - self.Repeat = false - self.RepeatSecondsInterval = RepeatSecondsInterval or 0 - self.RandomizationFactor = RandomizationFactor or 0 - self.StopSeconds = StopSeconds - - self.StartTime = timer.getTime() - - self.CallID = _TIMERDISPATCHER:AddSchedule( self ) + self:Schedule( TimeEventObject, TimeEventFunction, TimeEventFunctionArguments, StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds ) return self end -function SCHEDULER:_Destructor() - --self:E("_Destructor") +--function SCHEDULER:_Destructor() +-- --self:E("_Destructor") +-- +-- _TIMERDISPATCHER:RemoveSchedule( self.CallID ) +--end - _TIMERDISPATCHER:RemoveSchedule( self.CallID ) +--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also. +-- @param #SCHEDULER self +-- @param #table TimeEventObject Specified for which Moose object the timer is setup. If a value of nil is provided, a scheduler will be setup without an object reference. +-- @param #function TimeEventFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in TimeEventFunctionArguments. +-- @param #table TimeEventFunctionArguments Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }. +-- @param #number StartSeconds Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called. +-- @param #number RepeatSecondsInterval Specifies the interval in seconds when the scheduler will call the event function. +-- @param #number RandomizationFactor Specifies a randomization factor between 0 and 1 to randomize the RepeatSecondsInterval. +-- @param #number StopSeconds Specifies the amount of seconds when the scheduler will be stopped. +-- @return #SCHEDULER self +function SCHEDULER:Schedule( TimeEventObject, TimeEventFunction, TimeEventFunctionArguments, StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds ) + self:F2( { StartSeconds, RepeatSecondsInterval, RandomizationFactor, StopSeconds } ) + self:T3( { TimeEventFunctionArguments } ) + + + self.TimeEventObject = TimeEventObject + + self.Schedules[#self.Schedules+1] = _TIMERDISPATCHER:AddSchedule( + self, + TimeEventFunction, + TimeEventFunctionArguments, + StartSeconds, + RepeatSecondsInterval, + RandomizationFactor, + StopSeconds + ) + + return self +end + +--- (Re-)Starts the scheduler. +-- @param #SCHEDULER self +-- @return #SCHEDULER self +function SCHEDULER:Start() + self:F2() + + if self.RepeatSecondsInterval ~= 0 then + self.Repeat = true + end + + if self.StartSeconds then + self:T( { self.StartSeconds } ) + self.Schedules[#self.Schedules+1] = _TIMERDISPATCHER:AddSchedule( + self, + self.TimeEventObject, + self.TimeEventFunction, + self.TimeEventFunctionArguments, + self.StartSeconds, + self.RepeatSecondsInterval, + self.RandomizationFactor, + self.StopSeconds + ) + end + + return self +end + +--- Stops the scheduler. +-- @param #SCHEDULER self +-- @return #SCHEDULER self +function SCHEDULER:Stop() + self:F2( self.TimeEventObject ) + + self.Repeat = false + if self.ScheduleID then + self:E( "Stop Schedule" ) + timer.removeFunction( self.ScheduleID ) + end + self.ScheduleID = nil + + return self end @@ -94,4 +157,3 @@ end - diff --git a/Moose Development/Moose/Core/Timer.lua b/Moose Development/Moose/Core/Timer.lua index 174f6f674..be26757ff 100644 --- a/Moose Development/Moose/Core/Timer.lua +++ b/Moose Development/Moose/Core/Timer.lua @@ -32,26 +32,30 @@ end -- Nothing of this code should be modified without testing it thoroughly. -- @param #TIMER self -- @param Core.Scheduler#SCHEDULER Scheduler -function TIMER:AddSchedule( Scheduler ) - self:F3( { Scheduler } ) +function TIMER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop ) + self:F( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } ) + + self.CallID = self.CallID + 1 -- Initialize the Functions array, which is a weakly coupled table. -- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array. - self.Schedulers = self.Schedulers or setmetatable( {}, { __mode = "v" } ) - - self.CallID = self.CallID + 1 - self.Schedulers[self.CallID] = Scheduler + self.Calls = self.Calls or setmetatable( {}, { __mode = "v" } ) + self.Calls[self.CallID] = Scheduler + Scheduler:E( { self.CallID, self.Calls[self.CallID] } ) - Scheduler:E( { self.CallID, self.Schedulers[self.CallID] } ) + self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } ) + self.Schedule[Scheduler] = {} + self.Schedule[Scheduler][self.CallID] = {} + self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction + self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments + self.Schedule[Scheduler][self.CallID].Start = Start + .001 + self.Schedule[Scheduler][self.CallID].Repeat = Repeat + self.Schedule[Scheduler][self.CallID].Randomize = Randomize + self.Schedule[Scheduler][self.CallID].Stop = Stop - self.Schedule = self.Schedule or setmetatable( {}, { __mode = "v" } ) - self.Schedule[self.CallID] = {} - self.Schedule[self.CallID].ScheduleStart = Scheduler.StartSeconds + .001 - self.Schedule[self.CallID].ScheduleStart = Scheduler.StartSeconds + .001 + self:E( self.Schedule[Scheduler][self.CallID] ) - self:E( self.Schedule[self.CallID] ) - - self.Schedule[self.CallID].ScheduleCallHandler = function( CallID ) + self.Schedule[Scheduler][self.CallID].CallHandler = function( CallID ) self:E( CallID ) local ErrorHandler = function( errmsg ) @@ -61,43 +65,90 @@ function TIMER:AddSchedule( Scheduler ) end return errmsg end - - local ScheduleFunction = self.Schedulers[CallID].TimeEventFunction - local ScheduleArguments = self.Schedulers[CallID].TimeEventFunctionArguments - local ScheduleObject = self.Schedulers[CallID].TimeEventObject - local Status, Result - if ScheduleObject then - local function Timer() - return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) ) + local Scheduler = self.Calls[CallID] + + self:E( { Scheduler = Scheduler } ) + + if self.Calls[CallID] then + + local Schedule = self.Schedule[Scheduler][CallID] + + self:E( { Schedule = Schedule } ) + + local ScheduleObject = Scheduler.TimeEventObject + local ScheduleFunction = Schedule.Function + local ScheduleArguments = Schedule.Arguments + local Start = Schedule.Start + local Repeat = Schedule.Repeat + local Randomize = Schedule.Randomize + local Stop = Schedule.Stop + local ScheduleID = Schedule.ScheduleID + + local Status, Result + if ScheduleObject then + local function Timer() + return ScheduleFunction( ScheduleObject, unpack( ScheduleArguments ) ) + end + Status, Result = xpcall( Timer, ErrorHandler ) + else + local function Timer() + return ScheduleFunction( unpack( ScheduleArguments ) ) + end + Status, Result = xpcall( Timer, ErrorHandler ) + end + + local CurrentTime = timer.getTime() + local StartTime = CurrentTime + Start + + if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then + if Repeat and Repeat ~= 0 and ( not Stop ) or ( Stop and CurrentTime <= StartTime + Stop ) then + local ScheduleTime = + CurrentTime + + Repeat + + math.random( + - ( Randomize * Repeat / 2 ), + ( Randomize * Repeat / 2 ) + ) + + 0.01 + self:T( { ScheduleArguments, "Repeat:", CurrentTime, ScheduleTime } ) + return ScheduleTime -- returns the next time the function needs to be called. + else + timer.removeFunction( ScheduleID ) + ScheduleID = nil + end + else + timer.removeFunction( ScheduleID ) + ScheduleID = nil end - Status, Result = xpcall( Timer, ErrorHandler ) else - local function Timer() - return ScheduleFunction( unpack( ScheduleArguments ) ) - end - Status, Result = xpcall( Timer, ErrorHandler ) + self:E( "Scheduled obscolete call ..." ) end + + return nil end - timer.scheduleFunction( - self.Schedule[self.CallID].ScheduleCallHandler, + + self.Schedule[Scheduler][self.CallID].ScheduleID = timer.scheduleFunction( + self.Schedule[Scheduler][self.CallID].CallHandler, self.CallID, - timer.getTime() + 1 + timer.getTime() + self.Schedule[Scheduler][self.CallID].Start ) - --[[ - - self:T( Schedule.FunctionID ) - --]] - return self.CallID end function TIMER:RemoveSchedule( CallID ) - self:F( CallID ) - self.Schedulers[CallID] = nil + + local Schedule = self.Calls[CallID] + + if Schedule then + local ScheduleID = Schedule.ScheduleID + timer.removeFunction( ScheduleID ) + ScheduleID = nil + Schedule = nil + end end