1 /** 2 * Defines methods for scheduling tasks with different conditions for executing. 3 * 4 */ 5 module dash.utility.tasks; 6 import dash.utility.time, dash.utility.output, dash.utility.math; 7 8 import core.time; 9 import std.algorithm: min; 10 import std.parallelism: parallel; 11 import std.uuid: UUID, randomUUID; 12 import std.typecons; 13 14 public: 15 /** 16 * Schedule a task to be executed until it returns true. 17 * 18 * Params: 19 * dg = The task to execute. 20 * 21 * Returns: The ID of the task. 22 */ 23 UUID scheduleTask( bool delegate() dg ) 24 { 25 auto id = randomUUID(); 26 scheduledTasks ~= tuple( dg, id ); 27 return id; 28 } 29 30 /** 31 * Schedule a task to interpolate a value over a period of time. 32 * 33 * Params: 34 * T = The type to interpolate, either vector or quaternion. 35 * val = [ref] The value to interpolate. 36 * start = The starting value for interpolation. 37 * end = The target value for interpolation. 38 * interpFunc = [default=lerp] The function to use for interpolation. 39 * 40 * Returns: The ID of the task. 41 * 42 * Example: 43 * --- 44 * scheduleInterpolateTask( position, startNode, endNode, 100.msecs ); 45 * --- 46 */ 47 UUID scheduleInterpolateTask(T)( ref T val, T start, T end, Duration duration, T function( T, T, float ) interpFunc = &lerp!( T ) )// if( is_vector!T || is_quaternion!T ) 48 { 49 return scheduleTimedTask( duration, ( elapsed ) 50 { 51 val = interpFunc( start, end, elapsed / duration.toSeconds ); 52 } ); 53 } 54 /// 55 unittest 56 { 57 import std.stdio; 58 59 writeln( "Dash Tasks scheduleInterpolateTask unittest 1" ); 60 61 vec3f interpVec = vec3f( 0, 0, 0 ); 62 vec3f start = vec3f( 0, 1, 0 ); 63 vec3f end = vec3f( 0, 1, 1 ); 64 scheduleInterpolateTask( interpVec, start, end, 100.msecs ); 65 66 while( scheduledTasks.length ) 67 { 68 Time.update(); 69 executeTasks(); 70 } 71 72 assert( interpVec == end ); 73 } 74 75 /** 76 * Schedule a task to interpolate a property over a period of time. 77 * 78 * Params: 79 * prop = The name of the property being interpolated. 80 * T = The type to interpolate, either vector or quaternion. 81 * Owner = The type that owns the property interpolating. 82 * own = [ref] The owner of the property. 83 * start = The starting value for interpolation. 84 * end = The target value for interpolation. 85 * interpFunc = [default=lerp] The function to use for interpolation. 86 * 87 * Returns: The ID of the task. 88 * 89 * Example: 90 * --- 91 * scheduleInterpolateTask!q{position}( transform, startNode, endNode, 100.msecs ); 92 * --- 93 */ 94 UUID scheduleInterpolateTask( string prop, T, Owner )( ref Owner own, T start, T end, Duration duration, T function( T, T, float ) interpFunc = &lerp!( T ) ) 95 if( __traits( compiles, mixin( "own." ~ prop ) ) ) 96 { 97 auto startTime = Time.totalTime; 98 return scheduleTimedTask( duration, ( elapsed ) 99 { 100 mixin( "own." ~ prop ~ " = interpFunc( start, end, elapsed / duration.toSeconds );" ); 101 } ); 102 } 103 /// 104 unittest 105 { 106 import std.stdio; 107 108 writeln( "Dash Tasks scheduleInterpolateTask unittest 2" ); 109 110 auto testClass = new TestPropertyInterpolate; 111 testClass.vector = vec3f( 0, 0, 0 ); 112 vec3f start = vec3f( 0, 1, 0 ); 113 vec3f end = vec3f( 0, 1, 1 ); 114 scheduleInterpolateTask!q{vector}( testClass, start, end, 100.msecs ); 115 116 while( scheduledTasks.length ) 117 { 118 executeTasks(); 119 Time.update(); 120 } 121 122 assert( testClass.vector == end ); 123 } 124 version( unittest ) 125 class TestPropertyInterpolate 126 { 127 import dash.utility.math; 128 129 private vec3f _vector; 130 public @property vec3f vector() { return _vector; } 131 public @property void vector( vec3f newVal ) { _vector = newVal; } 132 } 133 134 /** 135 * Schedule a task to be executed until the duration expires. 136 * 137 * Params: 138 * duration = The duration to execute the task for. 139 * dg = The task to execute. 140 * 141 * Returns: The ID of the task. 142 */ 143 UUID scheduleTimedTask( Duration duration, void delegate() dg ) 144 { 145 auto startTime = Time.totalTime; 146 return scheduleTask( { 147 dg(); 148 return Time.totalTime >= startTime + duration.toSeconds; 149 } ); 150 } 151 152 /// ditto 153 UUID scheduleTimedTask( Duration duration, void delegate( float ) dg ) 154 { 155 auto startTime = Time.totalTime; 156 return scheduleTask( { 157 dg( min( Time.totalTime - startTime, duration.toSeconds ) ); 158 return Time.totalTime >= startTime + duration.toSeconds; 159 } ); 160 } 161 162 /// ditto 163 UUID scheduleTimedTask( Duration duration, void delegate( float, float ) dg ) 164 { 165 auto startTime = Time.totalTime; 166 return scheduleTask( { 167 dg( min( Time.totalTime - startTime, duration.toSeconds ), duration.toSeconds ); 168 return Time.totalTime >= startTime + duration.toSeconds; 169 } ); 170 } 171 172 /// ditto 173 UUID scheduleTimedTask( Duration duration, bool delegate() dg ) 174 { 175 auto startTime = Time.totalTime; 176 return scheduleTask( { 177 if( dg() ) 178 return true; 179 else 180 return Time.totalTime >= startTime + duration.toSeconds; 181 } ); 182 } 183 184 /// ditto 185 UUID scheduleTimedTask( Duration duration, bool delegate( float ) dg ) 186 { 187 auto startTime = Time.totalTime; 188 return scheduleTask( { 189 if( dg( min( Time.totalTime - startTime, duration.toSeconds ) ) ) 190 return true; 191 else 192 return Time.totalTime >= startTime + duration.toSeconds; 193 } ); 194 } 195 196 /// ditto 197 UUID scheduleTimedTask( Duration duration, bool delegate( float, float ) dg ) 198 { 199 auto startTime = Time.totalTime; 200 return scheduleTask( { 201 if( dg( min( Time.totalTime - startTime, duration.toSeconds ), duration.toSeconds ) ) 202 return true; 203 else 204 return Time.totalTime >= startTime + duration.toSeconds; 205 } ); 206 } 207 208 /** 209 * Schedule a task to be execuated after the specified amount of time. 210 * 211 * Params: 212 * delay = The ammount of time to wait before executing. 213 * dg = The task to execute. 214 * 215 * Returns: The ID of the task. 216 */ 217 UUID scheduleDelayedTask( Duration delay, void delegate() dg ) 218 { 219 auto startTime = Time.totalTime; 220 return scheduleTask( { 221 if( Time.totalTime - startTime >= delay.toSeconds ) 222 { 223 dg(); 224 return true; 225 } 226 else 227 { 228 return false; 229 } 230 } ); 231 } 232 233 /** 234 * Schedule a task to be executed on an interval, until the task returns true. 235 * 236 * Params: 237 * interval = The interval on which to call this task. 238 * dg = The task to execute. 239 * 240 * Returns: The ID of the task. 241 */ 242 UUID scheduleIntervaledTask( Duration interval, bool delegate() dg ) 243 { 244 auto timeTilExe = interval.toSeconds; 245 return scheduleTask( { 246 timeTilExe -= Time.deltaTime; 247 if( timeTilExe <= 0 ) 248 { 249 if( dg() ) 250 return true; 251 252 timeTilExe = interval.toSeconds; 253 } 254 255 return false; 256 } ); 257 } 258 259 /** 260 * Schedule a task to be executed on an interval a given number of times. 261 * 262 * Params: 263 * interval = The interval on which to call this task. 264 * numExecutions = The number of time to execute the task. 265 * dg = The task to execute. 266 * 267 * Returns: The ID of the task. 268 */ 269 UUID scheduleIntervaledTask( Duration interval, uint numExecutions, void delegate() dg ) 270 { 271 auto timeTilExe = interval.toSeconds; 272 uint executedTimes = 0; 273 return scheduleTask( { 274 timeTilExe -= Time.deltaTime; 275 if( timeTilExe <= 0 ) 276 { 277 dg(); 278 279 ++executedTimes; 280 timeTilExe = interval.toSeconds; 281 } 282 283 return executedTimes == numExecutions; 284 } ); 285 } 286 287 /** 288 * Schedule a task to be executed on an interval a given number of times, or until the event returns true. 289 * 290 * Params: 291 * interval = The interval on which to call this task. 292 * numExecutions = The number of time to execute the task. 293 * dg = The task to execute. 294 * 295 * Returns: The ID of the task. 296 */ 297 UUID scheduleIntervaledTask( Duration interval, uint numExecutions, bool delegate() dg ) 298 { 299 auto timeTilExe = interval.toSeconds; 300 uint executedTimes = 0; 301 return scheduleTask( { 302 timeTilExe -= Time.deltaTime; 303 if( timeTilExe <= 0 ) 304 { 305 if( dg() ) 306 return true; 307 308 ++executedTimes; 309 timeTilExe = interval.toSeconds; 310 } 311 312 return executedTimes == numExecutions; 313 } ); 314 } 315 316 /** 317 * Executes all scheduled tasks. 318 */ 319 void executeTasks() 320 { 321 size_t[] toRemove; 322 foreach( i, task; scheduledTasks/*.parallel*/ ) 323 { 324 if( task[ 0 ]() ) 325 synchronized toRemove ~= i; 326 } 327 foreach_reverse( i; toRemove ) 328 { 329 // Get tasks after one being removed 330 auto end = scheduledTasks[ i+1..$ ]; 331 // Get tasks before one being removed 332 scheduledTasks = scheduledTasks[ 0..i ]; 333 // Add end back 334 scheduledTasks ~= end; 335 } 336 } 337 338 /** 339 * Cancels the given task from executing. 340 * 341 * Params: 342 * id = The id of the task to cancel. 343 */ 344 void cancelTask( UUID id ) 345 { 346 import std.algorithm; 347 348 auto i = scheduledTasks.countUntil!( tup => tup[ 1 ] == id ); 349 350 // Get tasks after one being removed.s 351 auto end = scheduledTasks[ i+1..$ ]; 352 // Get tasks before one being removed. 353 scheduledTasks = scheduledTasks[ 0..i ]; 354 // Add end back. 355 scheduledTasks ~= end; 356 } 357 358 /** 359 * Cancels all running tasks. 360 */ 361 void resetTasks() 362 { 363 scheduledTasks = []; 364 } 365 366 private: 367 /// The tasks that have been scheduled 368 Tuple!( bool delegate(), UUID )[] scheduledTasks;