This repository has been archived on 2021-07-14. You can view files and clone it, but cannot push or open issues or pull requests.
scriptcraft/src/main/js/modules/at.js
2015-03-01 13:52:23 +00:00

156 lines
4.1 KiB
JavaScript

'use strict';
/*global events, module, require, __plugin, setInterval, clearInterval, setTimeout, addUnloadHandler*/
var utils = require('utils');
/************************************************************************
## The at Module
The at module provides a single function `at()` which can be used to schedule
repeating (or non-repeating) tasks to be done at a particular time.
### at() function
The utils.at() function will perform a given task at a given time in the
(minecraft) day.
#### Parameters
* time24hr : The time in 24hr form - e.g. 9:30 in the morning is '09:30' while
9:30 pm is '21:30', midnight is '00:00' and midday is '12:00'
* callback : A javascript function which will be invoked at the given time.
* worlds : (optional) An array of worlds. Each world has its own clock. If no array of worlds is specified, all the server's worlds are used.
* repeat : (optional) true or false, default is true (repeat the task every day)
#### Example
To warn players when night is approaching:
```javascript
var utils = require('utils'),
at = require('at');
function warning(){
utils.players(function( player ) {
echo( player, 'The night is dark and full of terrors!' );
});
}
at('19:00', warning);
```
To run a task only once at the next given time:
```javascript
var utils = require('utils'),
at = require('at');
function wakeup(){
utils.players(function( player ) {
echo( player, "Wake Up Folks!" );
});
}
at('06:00', wakeup, null, false);
```
***/
var SECOND = 1000;
var POLLING_INTERVAL = 3 * SECOND; // this is probably precise enough
function at(time24hr, callback, pWorlds, repeat) {
if (arguments.length === 0){
// TODO: Document this behaviour
console.log(tasksToString());
return;
}
var timeParts = time24hr.split( ':' );
var timeMins = (timeParts[0] * 60) + (timeParts[1] * 1);
if (!pWorlds || pWorlds === undefined ) {
pWorlds = utils.worlds();
}
if (repeat === undefined){
repeat = true;
}
utils.foreach( pWorlds, function ( world ) {
atAddTask( timeMins, callback, world, repeat);
});
};
var atTasks = {};
function tasksToString(){
var result = '';
for (var world in atTasks){
result += 'world: ' + world +'\n';
for (var time in atTasks[world]){
var scheduledFuncs = atTasks[world][time];
for (var i = 0;i < scheduledFuncs.length; i++){
result += ' ' + time + ': ' + scheduledFuncs[i].constructor + '\n';
}
}
result += '(current world time: ' + utils.time24(world) + ')\n';
}
return result;
}
/*
constructs a function which will be called every x ticks to
track the schedule for a given world
*/
function atMonitorFactory(world){
var worldName = ''+ world.name;
var lastRun = null;
return function atMonitorForWorld(){
var timeMins = utils.time24(world);
if (timeMins === lastRun){
return;
}
if (lastRun === null ){
lastRun = timeMins - 1;
}else {
lastRun = lastRun % 1440;
}
var worldSchedule = atTasks[worldName];
if (!worldSchedule){
return;
}
while ( lastRun > timeMins ? (lastRun <= 1440) : ( lastRun < timeMins ) ){
var tasks = worldSchedule[lastRun++];
if (!tasks){
continue;
}
utils.foreach(tasks, function(task, i){
if (!task){
return;
}
setTimeout(task.callback.bind(null, timeMins, world), 1);
if (!task.repeat){
tasks[i] = null;
}
});
}
};
}
function atAddTask( timeMins, callback, world, repeat){
var worldName = ''+world.name;
if (!atTasks[worldName]){
atTasks[worldName] = {};
}
if (!atTasks[worldName][timeMins]){
atTasks[worldName][timeMins] = [];
}
atTasks[worldName][timeMins].push({callback: callback, repeat: repeat});
}
var atMonitors = [];
function onLoadStartMonitor(event){
var monitor = setInterval( atMonitorFactory(event.world), POLLING_INTERVAL);
atMonitors.push( monitor );
}
if (__plugin.canary){
events.loadWorld( onLoadStartMonitor );
}
if (__plugin.bukkit){
events.worldLoad( onLoadStartMonitor );
}
addUnloadHandler(function(){
utils.foreach(atMonitors, function(atInterval){
clearInterval(atInterval);
});
});
module.exports = at;