November 28, 2020, 11:00:58 AM

Author Topic: [bmx] Method Call Scheduler by USNavyFish [ 1+ years ago ]  (Read 607 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bmx] Method Call Scheduler by USNavyFish [ 1+ years ago ]
« on: June 29, 2017, 12:28:43 AM »
Title : Method Call Scheduler
Author : USNavyFish
Posted : 1+ years ago

Description : This code allows you to 'schedule' object's methods to be called at some specified time later on.  An ideal usage is for scheduling AI routines for large numbers of entities.

The code has been designed to operate with minimum CPU overhead.  No sorting or searching is required when scheduling calls and reading from the schedule, resulting in a very efficient system.


Code :
Code: BlitzMax
  1. Rem
  2. --------------------------------------------------------------------------------------------------------------
  3.  
  4. Event Scheduling Program
  5.         Bryan Fishman (USNavyFish), AUG 2008
  6.  
  7.  
  8. This program was designed to provide an easy means of scheduling the execution of events within a game
  9. or simulation.  The system was designed for minimal overhead.  It is not designed for extremely high
  10. time sensitivity, and use of a time resolution less than one hundredth of a second is not recomended.
  11.  
  12. Essentially, the system provides an array where each cell represents one 'moment' of time.  When events
  13. are scheduled, this system places them in the appropriate cell which represents the moment of execution
  14. for that event.   The system then simply checks one cell per 'moment' and executes any event stored there.
  15. In this manner, the system can support an extremely large number of concurrent and overlapping events, without
  16. any performance loss, as the program is not required to loop through all scheduled events during every cycle.  
  17.  
  18.  
  19. This program provides two Custom Types:
  20.  
  21.          A"TFutureEvent" type with the following functions, methods, and fields:
  22.                 || Field obj_:Object    The targe objet whose method will be called
  23.                 || Field method_:TMethod This is the specific method which will be called
  24.                 || Field args_:Object[] An object array containing the arguments to be passed
  25.                 ||
  26.                 || Function  Create:TFutureEvent( obj:Object,methodName:String,args:Object[] )
  27.                 ||              -This function creates and returns the FutureEvent.
  28.                 ||              -'methodName:String' is the exact name of the method that will be called
  29.                 ||
  30.                 || Function invoke:object() executes the FutureEvent.
  31.  
  32.  
  33.         A "TScheduler" type with the following functions and Globals  (There are no Methods or locals)
  34.  
  35.                 || Global TimeArray_Length:Int                          Size of the TimeArray (# of cells)
  36.                 || Global TimeArray_StepDuration:Float          Duration of time represented by each cell
  37.                
  38.                 ||              - Note that (Length * Duration) yields the furthest schedulable time
  39.                 ||              - i.e. 3600 cells of 1 second duration each allows events to be scheduled
  40.                 ||                      up to one hour (inclusive) in advance.
  41.                 ||
  42.                 || Global TimeArray:TList[]             Each cell stores a list of scheduled TFutureEvents
  43.                 || Global CurrentIndex:Int              Current Index of the Time Array
  44.                 || Global ScheduleTimer:TTimer          System Timer for Scheduler object
  45.                 || Global IsPaused:byte                 System Timer is paused if 1, is not paused if 0
  46.                 ||
  47.                 || Function Initialize(Length:Int = 3600 , Seconds:Float = 1)
  48.                 ||              - Call this once at the beginning of your program
  49.                 ||              - For a schedule that can store events up to 24 hours (inclusive) into the future,
  50.                 ||                      and that has a schedule resolution of 0.1 seconds, use the following parameters:  
  51.                 ||                      Length = 3600 * 24 * 10
  52.                 ||                      Seconds = 0.1
  53.                 ||              - Each Index specified by Length requires 4 bytes of memory. The above example requires
  54.                 ||                      a total of ~3.3 MB of memory at runtime.
  55.                 ||
  56.                 || Function Begin()
  57.                 ||              - Activates the system timer
  58.                 ||              - Call this once you wish to actually begin schedule execution.
  59.                 ||              - Events may be scheduled both prior to and during the schedule's execution
  60.                 ||
  61.                 || Function ScheduleTimerHook:Object(id:Int, data:Object, context:Object)
  62.                 ||              - Internal funciton, intercepts system timer hook (returns null if intercepted)
  63.                 ||              - Calls the ScheduleAdvance and ScheduleExecute functions
  64.                 ||
  65.                 || Function ScheduleAdvance()
  66.                 ||              - Internal function, advances current Schedule Index
  67.                 ||
  68.                 || Function ScheduleExecute(index:Int)
  69.                 ||              - Internal Function, executes all events scheduled for current time index.
  70.                 ||              - This function removes all references to the scheduled events once executed
  71.                 ||
  72.                 || Function ScheduleEvent(event:TFutureEvent, SecondsDelay:Float)
  73.                 ||              - Call this function to schedule an event which will execute once in the future,
  74.                 ||                      after the number of seconds specified by SecondsDelay has passed.
  75.                 ||              - For example, when called with SecondsDelay = 20, the passed event will execute
  76.                 ||                      approximately 20 seconds after the "ScheduleEvent" function is called
  77.                 ||              - Scheduling accuracy reduces as "SecondsDelay" approaches the TimeArray_StepDuration
  78.                 ||                      For best results, use a TimeArray_StepDuration value at least twice as short as
  79.                 ||                      your quickest-scheduled events.   For example, a program that regularly schedules
  80.                 ||                      events at intervals as short as 1 second apart should use a StepDuration value of
  81.                 ||                      at most 0.5 seconds. A value of 0.1 seconds wil provide much better accuracy.
  82.                 ||                     
  83.                 || Function ScheduleSetPause(command:byte)
  84.                 ||              This function sets the Scheduler's "IsPaused" flag.
  85.                 ||              When "IsPaused" = 1, normal execution occurs
  86.                 ||              When "IsPaused" = 0, the scheduler 'ignores' the schedule timer's tick event.
  87.                
  88.                
  89.  
  90. Example usages of the scheduler function:
  91.  
  92.  
  93. TScheduler.ScheduleEvent(TFutureEvent.Create(obj1 , "textoutput" , ["You Called Me!"]) , 2)
  94. ||
  95. ||This calls obj1's "textoutput" method, with the input parameter "You Called Me!", in two seconds from this call.
  96.  
  97.  
  98. TScheduler.ScheduleEvent(TFutureEvent.Create(obj1 , "add" , [String(1)]) , 4)
  99. ||
  100. ||This calls obj1's "add" method, with the input parameter of 1.  Note the floating point value must be converted
  101. ||into a string to be accepted by the function. This event will execute in four seconds.
  102.  
  103.  
  104. TScheduler.ScheduleEvent(TFutureEvent.Create(obj1 , "multiparam" , [String(4.3),String(17),"TEXT"]) , 20)
  105. ||
  106. ||This calls obj1's "multiparam" method, which accepts a float, an int, and a string as inputs to the method.
  107. ||Note how any non-string parameter inputs must be converted to strings using the String() function.  This
  108. ||event will be executed in 20 seconds.
  109.  
  110.        
  111. --------------------------------------------------------------------------------------------------------------
  112. End Rem
  113.  
  114. SuperStrict
  115.  
  116.  
  117. Type TFutureEvent
  118.        
  119.         Field obj_:Object
  120.         Field method_:TMethod
  121.         Field args_:Object[]
  122.        
  123.         Function Create:TFutureEvent( obj:Object,methodName:String,args:Object[] )
  124.                 Local temp:TFutureEvent=New TFutureEvent
  125.                 temp.obj_ = obj
  126.                 temp.method_ = TTypeId.ForObject(obj).findMethod( methodName )
  127.                 temp.args_ = args
  128.                
  129.                 Return temp
  130.         End Function
  131.  
  132.         Method Invoke:Object()
  133.                 Return method_.Invoke( obj_,args_ )
  134.         End Method
  135.        
  136. End Type
  137.  
  138.  
  139.  
  140. Type TScheduler
  141.         Global TimeArray_Length:Int
  142.         Global TimeArray_StepDuration:Float
  143.         Global TimeArray:TList[]
  144.         Global CurrentIndex:Int
  145.         Global ScheduleTimer:TTimer    
  146.         Global IsPaused:Byte
  147.        
  148.        
  149.         Function Initialize(Length:Int = 3600 , Seconds:Float = 1)
  150.                
  151.                 DebugLog "Master Schedule Initialized"
  152.                 DebugLog "Schedule Outlook:    " + Length / Seconds + " Seconds"
  153.                 DebugLog "Schedule Resolution: " + Seconds + " Seconds"
  154.                
  155.                 TimeArray_Length = Length + 1           'One is added so total duration is inclusive
  156.                 TimeArray_StepDuration = Seconds
  157.                 TimeArray = New TList[TimeArray_Length]
  158.                 CurrentIndex = -1
  159.                
  160.         End Function
  161.  
  162.  
  163.        
  164.         Function Begin()
  165.                 AddHook EmitEventHook , ScheduleTimerHook
  166.                 ScheduleTimer = CreateTimer(1 / TimeArray_StepDuration)
  167.                 DebugLog "Schedule Execution Commenced at System Time: " + CurrentTime()
  168.         End Function
  169.                        
  170.        
  171.        
  172.         Function ScheduleTimerHook:Object(id:Int, data:Object, context:Object)
  173.                
  174.                 Local ev:TEvent = TEvent(data)
  175.                
  176.                 If ev = Null Then Return Null
  177.                
  178.                 If ev.id = EVENT_TIMERTICK
  179.                         If ev.source = ScheduleTimer
  180.                                
  181.                                 If IsPaused = 0
  182.                                
  183.                                 ScheduleAdvance()
  184.                                 DebugLog "ScheduleTimer Fires. Executing Index["+CurrentIndex+"]"
  185.                                 ScheduleExecute(CurrentIndex)
  186.                                
  187.                                 EndIf  
  188.                                
  189.                                 Return Null
  190.                        
  191.                         EndIf
  192.                 EndIf
  193.                
  194.                 Return data
  195.         End Function
  196.        
  197.        
  198.        
  199.         Function ScheduleAdvance()
  200.                 CurrentIndex = (CurrentIndex + 1)       Mod TimeArray_Length
  201.         End Function
  202.        
  203.        
  204.        
  205.        
  206.         Function ScheduleExecute(index:Int)
  207.                 If TimeArray[index]
  208.                         For Local event:TFutureEvent = EachIn TimeArray[index]
  209.                                 If event.obj_
  210.                                         event.invoke
  211.                                 Else
  212.                                         DebugLog "Object " + event.obj_.tostring() + " No longer Exists!"
  213.                                 EndIf
  214.                         Next
  215.                        
  216.                         TimeArray[index] = Null 'Removes all references to TList and stored TFutureEvents
  217.                 EndIf
  218.  
  219.         End Function
  220.        
  221.        
  222.        
  223.         Function ScheduleEvent(event:TFutureEvent, SecondsDelay:Float)
  224.                 Local index:Int
  225.                 index = Ceil(SecondsDelay / TimeArray_StepDuration)
  226.                        
  227.                 If index > TimeArray_Length
  228.                         DebugLog "Critical Error!~nObject:~t" + event.obj_.tostring()
  229.                         DebugLog "Scheduled Time (" + SecondsDelay+") converts to " + index + " future cells"
  230.                         DebugLog "This exceeds the length of schedulable time (" + TimeArray_Length + " cells)"
  231.                        
  232.                         End
  233.                 EndIf
  234.                                        
  235.                 index :+ CurrentIndex + 1      
  236.                 index :Mod TimeArray_Length
  237.                                
  238.                
  239.                 If TimeArray[index] = Null Then TimeArray[index] = CreateList()
  240.                
  241.                 ListAddLast TimeArray[index] , event
  242.                
  243.                 DebugLog "Event Scheduled for object $" + event.obj_.tostring() + " in " + SecondsDelay + " seconds."
  244.  
  245.         End Function
  246.        
  247.        
  248.         Function ScheduleSetPause(command:Byte)
  249.                 IsPaused = command
  250.         End Function
  251.                
  252.        
  253. End Type
  254.  
  255.  
  256.  
  257.  
  258.  
  259. Type TTestType
  260.         Field Value_:Float
  261.         Field name_:String
  262.        
  263.         Function Create:TTestType(objname:String)
  264.                 Local temp:TTestType = New TTestType
  265.                 temp.name_= objname
  266.                 temp.value_ = 0
  267.                 Print temp.name_ + " Created: " + temp.value_
  268.                 Return temp
  269.         End Function
  270.        
  271.         Method add:Float(num:Float)
  272.                 value_:+ num
  273.                 Print name_ +"'s Counter increased to "+value_
  274.         End Method
  275.        
  276.         Method textoutput:String(output:String)
  277.                 Print name_ +" Says: "+output
  278.         End Method     
  279.        
  280.        
  281. End Type
  282.  
  283.  
  284.  
  285. Function KeyHook:Object(id:Int , data:Object , context:Object)
  286.         Local ev:TEvent = TEvent(data)
  287.        
  288.         If ev = Null Then Return Null
  289.        
  290.         Select ev.id
  291.                 Case EVENT_KEYDOWN
  292.                 Print "KEYDOWN~t" + ev.data
  293.                
  294.                         Select ev.data
  295.                
  296.                                 Case 49
  297.                                 TScheduler.ScheduleEvent(TFutureEvent.Create(obj1 , "textoutput" , ["You Called Me!"]) , 1)
  298.                                 TScheduler.ScheduleEvent(TFutureEvent.Create(obj1 , "add" , [String(1)]) , 1)
  299.                                
  300.                                 Case 50
  301.                                 TScheduler.ScheduleEvent(TFutureEvent.Create(obj1 , "textoutput" , ["You Called Me!"]) , 2)
  302.                                 TScheduler.ScheduleEvent(TFutureEvent.Create(obj1 , "add" , [String(1)]) , 2)
  303.                                
  304.                                 Case 51
  305.                                 TScheduler.ScheduleEvent(TFutureEvent.Create(obj1 , "textoutput" , ["You Called Me!"]) , 4)
  306.                                 TScheduler.ScheduleEvent(TFutureEvent.Create(obj1 , "add" , [String(1)]) , 4)
  307.                                
  308.                                 Case 80
  309.                                 If TScheduler.IsPaused
  310.                                         TScheduler.ScheduleSetPause(0)
  311.                                 Else
  312.                                         TScheduler.ScheduleSetPause(1)
  313.                                 EndIf
  314.                                
  315.                                        
  316.                         End Select
  317.                                
  318.                 Case EVENT_KEYUP
  319.                 'Print "KEYUP~t"+ev.data
  320.                
  321.         End Select
  322.  
  323.        
  324.         Return data
  325.        
  326. End Function           
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335. Graphics 640 , 480
  336.  
  337. AddHook EmitEventHook , Keyhook
  338.  
  339.  
  340. TScheduler.Initialize(3600*24*4,0.25)
  341.  
  342. Global obj1:TTestType = TTestType.Create("Object1")
  343.  
  344. GCCollect
  345. Print GCMemAlloced() + " Bytes Allocated"
  346.  
  347. Cls
  348. Print "Press any key to begin!  Make all key presses to the graphics window."
  349. DrawText "Press any key to begin!  Watch the console window.",0,0
  350. Flip
  351. WaitKey()
  352.  
  353. TScheduler.Begin()
  354.  
  355. Repeat
  356.  
  357. Cls    
  358. DrawText "Press 1, 2, or 3 to schedule an event for 1, 2, or 4 seconds in the future" , 0 , 0
  359. DrawText "Watch the Console for output." , 0 , 30
  360. DrawText "Observe the TimeArray cells advancing once every " + TScheduler.TimeArray_StepDuration + " seconds." , 0 , 60
  361. DrawText "Now Press a key, wait the appropriate amount of time,",0,90
  362. DrawText "And watch for the event response in the console!" , 20 , 110
  363.  
  364. Flip
  365.  
  366. Until KeyHit(key_escape)
  367.  
  368.  
  369. End


Comments : none...

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal