1
Modification Help / [Resource] Simple Task Manager
« on: May 28, 2015, 01:45:26 PM »
A simple task manager that was built into the original TGE FPS kit. I recreated it because I figured it would be really useful to have around. I recreated it from the documentation, and tested it using the given examples (and also a bunch of other tests).
As documented here on pages 367 to 377.
In short, lets you queue up functions to be called in a specified order, with optional delays.
As documented here on pages 367 to 377.
In short, lets you queue up functions to be called in a specified order, with optional delays.
Code: [Select]
////Simple Task Manager
//As documented http://www-rohan.sdsu.edu/~stewart/GPGT/Appendix%20A%20-%20Quick%20References.pdf
// on pages 367 to 377
function newTaskManager(%target) {
%mgr = new ScriptGroup() {
class = SimpleTaskMgr;
target = isObject(%target) ? %target.getID() : 0;
useTarget = isObject(%target);
selfExecution = 0;
defaultTaskDelay = -1; //Defaults to instant
useDefaultDelay = 0;
};
return %mgr;
}
function SimpleTaskMgr::setTarget(%mgr, %target) {
%mgr.target = isObject(%target) ? %target.getID() : 0;
%mgr.useTarget = isObject(%target);
}
function SimpleTaskMgr::clearTarget(%mgr) {
%mgr.target = 0;
%mgr.useTarget = 0;
}
function SimpleTaskMgr::getTarget(%mgr) {
return %mgr.useTarget ? (isObject(%mgr.target) ? %mgr.target : 0) : 0;
}
function SimpleTaskMgr::setDefaultTaskDelay(%mgr, %delay) {
%mgr.defaultTaskDelay = %delay;
}
function SimpleTaskMgr::selfExecuteTasks(%mgr, %useDefaultDelay) {
%mgr.selfExecution = 1;
if(%useDefaultDelay !$= "") {
%mgr.useDefaultDelay = %useDefaultDelay ? 1 : 0;
}
if(%mgr.getCount() <= 0)
return;
%task = %mgr.getObject(0);
if(!isEventPending(%mgr.tickSch)) {
%time = %mgr.useDefaultDelay ? %mgr.defaultTaskDelay : %task.delay;
if(%time == -1) {
%mgr.executeNextTask(); //Instant execution
} else {
%mgr.tickSch = %mgr.schedule(%time, executeNextTask);
}
}
}
function SimpleTaskMgr::stopSelfExecution(%mgr) {
//Doesnt cancel the next function call
//Stops after the next function execution
%mgr.selfExecution = 0;
}
function SimpleTaskMgr::addTask(%mgr, %task, %recycleCount, %preempt, %taskDelay) {
%recycleCount = mFloor(%recycleCount); //Convert to int, just incase
if(%recycleCount == 0) //0 recycles (or left blank) executes once
%recycleCount = 1;
if(%taskDelay $= "") //Undefined time executes instantly
%taskDelay = -1;
%taskObj = new ScriptObject() {
class = EGTask; //I have no idea why its EGTask, just following the documentation
task = %task;
recycleCount = %recycleCount;
preempt = %preempt;
delay = %taskDelay;
};
%mgr.add(%taskObj);
if(%mgr.selfExecution && !isEventPending(%mgr.tickSch)) {
//Start the schedule again
%firstTask = %mgr.getObject(0);
if(!isEventPending(%mgr.tickSch)) {
%time = %mgr.useDefaultDelay ? %mgr.defaultTaskDelay : %firstTask.delay;
if(%time == -1) {
%mgr.executeNextTask(); //Instant execution
} else {
%mgr.tickSch = %mgr.schedule(%time, executeNextTask);
}
}
}
return %taskObj;
}
function SimpleTaskMgr::addTaskFront(%mgr, %task, %recycleCount, %preempt, %taskDelay) {
%task = %mgr.addTask(%task, %recycleCount, %preempt, %taskDelay); //Slightly less efficient, however less code duplication
%mgr.bringToFront(%task);
return %task;
}
function SimpleTaskMgr::clearTasks(%mgr) {
//Delete all tasks
while(%mgr.getCount() > 0) {
%mgr.getObject(0).delete();
}
}
function SimpleTaskMgr::executeNextTask(%mgr) {
if(%mgr.getCount() <= 0)
return "";
%task = %mgr.getObject(0);
%result = %task.execute();
if(!isObject(%mgr)) //If the manager was deleted during execution (eg with TERMINATE# token)
return "";
//If the LOCK# token is in the task, dont store the return value for current task
if(strPos(%task.task, "LOCK#") == -1)
%mgr.lastReturnVal = %result;
if(%task.recycleCount == -1 || %task.recycleCount-- > 0) {
if(%task.preempt) {
//Dont push to back, leave at front
} else {
%mgr.pushToBack(%task);
}
} else {
%mgr.pushToBack(%task); //This is to make sure the set keeps its order
%task.delete();
}
if(%mgr.selfExecution && %mgr.getCount() > 0) {
//Start the schedule for the next execution
%task = %mgr.getObject(0);
if(!isEventPending(%mgr.tickSch)) {
%time = %mgr.useDefaultDelay ? %mgr.defaultTaskDelay : %task.delay;
if(%time == -1) {
%mgr.executeNextTask(); //Instant execution
} else {
%mgr.tickSch = %mgr.schedule(%time, executeNextTask);
}
}
}
return %result;
}
function EGTask::execute(%task) {
%mgr = %task.getGroup();
%eval = %task.task;
//LOCK# is handled in SimpleTaskMgr::executeNextTask, but we still need to remove it
%eval = strReplace(%eval, "LOCK#", "");
%eval = strReplace(%eval, "LASTRET#", %task.getGroup() @ ".lastReturnVal"); //Replace with last return value
%eval = strReplace(%eval, "TASKMGR#", %task.getGroup()); //Replace with %mgr
%eval = strReplace(%eval, "TASK#", %task.getID()); //Replace with task.getID();
%eval = strReplace(%eval, "%this", %mgr.getID()); //Allows for "func(%this.val)"
switch$(%eval) {
case "TERMINATE#": //Delete mgr
%mgr.delete();
//echo("Terminate");
return "";
case "NULL#": //Empty task, used for delays
//echo("Null");
return "";
default:
//Need to use eval (unfortunately) to keep to documentation
if(%mgr.useTarget && strPos(%eval, "STMT#") == -1) {
if(isObject(%target = %mgr.target)) {
%result = eval(%mgr.target @ "." @ %eval);
//echo("eval(\"" @ %mgr.target @ "." @ %eval @ "\");");
}
} else {
//Execute as a stand alone function, not a method
%result = eval(strReplace(%eval, "STMT#", ""));
//echo("eval(\"" @ strReplace(%eval, "STMT#", "") @ "\");");
}
return %result;
}
}
function EGTask::setTaskDelay(%task, %delay) {
%task.delay = %delay;
}
task = %task;
recycleCount = %recycleCount;
preempt = %preempt;
delay = %taskDelay;
};
%mgr.add(%task);
if(%mgr.selfExecution && !isEventPending(%mgr.tickSch)) {
//Start the schedule again
%firstTask = %mgr.getObject(0);
if(!isEventPending(%mgr.tickSch)) {
%time = %mgr.useDefaultDelay ? %mgr.defaultTaskDelay : %firstTask.delay;
if(%time == -1) {
%mgr.executeNextTask(); //Instant execution
} else {
%mgr.tickSch = %mgr.schedule(%time, executeNextTask);
}
}
}
return %task;
}
function SimpleTaskMgr::addTaskFront(%mgr, %task, %recycleCount, %preempt, %taskDelay) {
%task = %mgr.addTask(%task, %recycleCount, %preempt, %taskDelay); //Slightly less efficient, however less code duplication
%mgr.bringToFront(%task);
return %task;
}
function SimpleTaskMgr::clearTasks(%mgr) {
//Delete all tasks
while(%mgr.getCount() > 0) {
%mgr.getObject(0).delete();
}
}
function SimpleTaskMgr::executeNextTask(%mgr) {
if(%mgr.getCount() <= 0)
return "";
%task = %mgr.getObject(0);
%result = %task.execute();
//If the LOCK# token is in the task, dont store the return value for current task
if(strPos(%task.task, "LOCK#") == -1)
%mgr.lastReturnVal = %result;
if(%task.recycleCount == -1 || %task.recycleCount-- > 0) {
if(%task.preempt) {
//Dont push to back, leave at front
} else {
%mgr.pushToBack(%task);
}
} else {
%mgr.pushToBack(%task); //This is to make sure the set keeps its order
%task.delete();
}
if(%mgr.selfExecution && %mgr.getCount() > 0) {
//Start the schedule for the next execution
%task = %mgr.getObject(0);
if(!isEventPending(%mgr.tickSch)) {
%time = %mgr.useDefaultDelay ? %mgr.defaultTaskDelay : %task.delay;
if(%time == -1) {
%mgr.executeNextTask(); //Instant execution
} else {
%mgr.tickSch = %mgr.schedule(%time, executeNextTask);
}
}
}
return %result;
}
function EGTask::execute(%task) {
%mgr = %task.getGroup();
//LOCK# is handled in SimpleTaskMgr::executeNextTask
%task.task = strReplace(%task.task, "LASTRET#", %task.getGroup() @ ".lastReturnVal;"); //Replace with last return value
%task.task = strReplace(%task.task, "TASKMGR#", %task.getGroup()); //Replace with %mgr
%task.task = strReplace(%task.task, "TASK#", %task.getID()); //Replace with task.getID();
%task.task = strReplace(%task.task, "%this.", %mgr.getID() @ "."); //Allows for "func(%this.val)"
switch$(%task.task) {
case "TERMINATE#": //Delete mgr
%mgr.delete();
return "";
case "NULL#": //Empty task, used for delays
return "";
default:
//Need to use eval (unfortunately) to keep to documentation
if(%mgr.useTarget && strPos(%task.task, "STMT#") == -1) {
if(isObject(%target = %mgr.target)) {
%result = eval(%mgr.target @ "." @ %task.task);
//echo("eval(\"" @ %mgr.target @ "." @ %task.task @ "\");");
}
} else {
//Execute as a stand alone function, not a method
%result = eval(strReplace(%task.task, "STMT#", ""));
//echo("eval(\"" @ strReplace(%task.task, "STMT#", "") @ "\");");
}
return %result;
}
}
function EGTask::setTaskDelay(%task, %delay) {
%task.delay = %delay;
}