Created
September 29, 2017 03:03
-
-
Save jdoleary/b6bb8236dd3ee384bccdb337b18a5cab to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import _ from 'lodash'; | |
import uid from 'uuid/v4'; | |
export default function(){ | |
return { | |
// Current time in millis | |
time:0, | |
// one 'day' occurs every x milliseconds: | |
millisPerDay: 60000, | |
events:[], | |
//recurringEvents:{}, | |
now(){ | |
return this.time; | |
}, | |
// set the time | |
setTime(millis){ | |
if(!_.isNumber(millis)){ | |
console.log(`Error: Attempting to set time equal to ${millis} which is not a number.`); | |
} | |
this.time = millis; | |
// Manage recurring events during the time jump: | |
// Remove all recurring events: | |
let recurringEvents = _.remove(this.events, (o) => o.recur); | |
// Add in sigular events for each recurring event in the past before the fast forward: | |
recurringEvents.forEach((o) => { | |
if(o.recurInterval > 0){ | |
while(o.time <= this.time){ | |
// Add a singular, non-recurring event with the recurring event's callback | |
this.addEventAtAbsolute(o.callback,o.time,o.owner); | |
// Increment time to check the next occurence: | |
o.time += o.recurInterval; | |
} | |
// Push the recurring event back in where it belongs in the future: | |
this.events.push(o); | |
} | |
}); | |
// Fire events that happened during the time jump: | |
this.fireEvents(); | |
}, | |
// fast forward time | |
fastForward(millis){ | |
this.setTime(this.time + millis); | |
}, | |
fastForwardOneDay(){ | |
this.fastForward(this.millisPerDay); | |
}, | |
removeEvent(id){ | |
// If a loop is active, remove it at the end of the loop | |
if(this.loopActive){ | |
let e = _.find(this.events, (o)=>o.id === id); | |
e.flagForRemoval = true; | |
}else{ | |
// if not, remove immediately: | |
_.remove(this.events, (o)=>o.id === id); | |
} | |
}, | |
removeEventsFromOwner(owner){ | |
let events = _.filter(this.events,(o)=>o.owner && o.owner.id == owner.id); | |
events.forEach((e)=>{ | |
//console.log('event removed from ' + e.owner.name + ' ' + e.id); | |
this.removeEvent(e.id); | |
}); | |
}, | |
// Adds an event to be fired at a time "recurInterval" milliseconds from the current time | |
// and to repeat every "recurInterval" milliseconds. | |
addEventRecurring(callback,recurInterval,owner){ | |
if(!_.isNumber(recurInterval)){ | |
console.log(`Error: Attempting to set event time to ${recurInterval}, which is not a number.`); | |
} | |
let id = uid(); | |
let e = { | |
time:this.now()+recurInterval, // time that event will be fired | |
callback:callback, // callback fired when time is passed | |
recur:true, // bool, if event should repeat | |
recurInterval:recurInterval, // interval of millis that event should repeat | |
id:id, // used for removing event | |
owner | |
}; | |
this.events.push(e); | |
return id; | |
}, | |
// Adds an event to be fired at a time "absoluteTime" | |
addEventAtAbsolute(callback,absoluteTime,owner){ | |
if(!_.isNumber(absoluteTime)){ | |
console.log(`Error: Attempting to set event time to ${absoluteTime}, which is not a number.`); | |
} | |
let e = { | |
id:uid(), | |
time:absoluteTime, // time that event will be fired | |
callback:callback, // callback fired when time is passed | |
owner | |
}; | |
this.events.push(e); | |
}, | |
// Adds an event to be fired at a time "MillisFromNow" milliseconds from the current time | |
addEvent(callback,MillisFromNow,owner){ | |
if(!_.isNumber(MillisFromNow)){ | |
console.log(`Error: Attempting to set event time with ${MillisFromNow}, which is not a number.`); | |
} | |
let e = { | |
id:uid(), | |
time:this.now()+MillisFromNow, // time that event will be fired | |
callback:callback, // callback fired when time is passed | |
owner | |
}; | |
this.events.push(e); | |
}, | |
fireEvents(){ | |
// Sort events by time for efficient firing | |
// (Ordered by descending because list is iterated upside down) | |
this.events = _.orderBy(this.events,'time',['desc']); | |
let i = this.events.length; | |
// Prevents event removal from occuring inside of loop: | |
this.loopActive = true; | |
while (i--) { | |
let e = this.events[i]; | |
if(e.flagForRemoval){ | |
// Do not call events that are flaggedForRemoval: | |
continue; | |
} | |
if(this.now() >= e.time){ | |
// Fire event callback and remove event: | |
if(e.callback){ | |
// If the event doesn't have an owner, or it does but the | |
// owner is not destroyed, then call the callback, otherwise | |
// ignore the callback. | |
if(!e.owner || (e.owner && !e.owner.destroyed)){ | |
e.callback(); | |
} | |
} | |
e.flagForRemoval = true; | |
}else{ | |
// All subsequent events are in the future so break | |
// we know this because the events are sorted by time | |
break; | |
} | |
} | |
i = this.events.length; | |
while(i--){ | |
if(this.events[i].flagForRemoval){ | |
this.events.splice(i, 1); | |
} | |
} | |
this.loopActive = false; | |
}, | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment