186 lines
4.8 KiB
C++
186 lines
4.8 KiB
C++
/**
|
|
* PANDA 3D SOFTWARE
|
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
*
|
|
* All use of this software is subject to the terms of the revised BSD
|
|
* license. You should have received a copy of this license along
|
|
* with this source code in a file named "LICENSE."
|
|
*
|
|
* @file asyncTaskSequence.cxx
|
|
* @author drose
|
|
* @date 2008-10-04
|
|
*/
|
|
|
|
#include "asyncTaskSequence.h"
|
|
#include "asyncTaskManager.h"
|
|
|
|
TypeHandle AsyncTaskSequence::_type_handle;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
AsyncTaskSequence::
|
|
AsyncTaskSequence(const std::string &name) :
|
|
AsyncTask(name),
|
|
_repeat_count(0),
|
|
_task_index(0)
|
|
{
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
AsyncTaskSequence::
|
|
~AsyncTaskSequence() {
|
|
set_current_task(nullptr, true);
|
|
}
|
|
|
|
/**
|
|
* Override this function to return true if the task can be successfully
|
|
* executed, false if it cannot. Mainly intended as a sanity check when
|
|
* attempting to add the task to a task manager.
|
|
*
|
|
* This function is called with the lock held.
|
|
*/
|
|
bool AsyncTaskSequence::
|
|
is_runnable() {
|
|
return (get_num_tasks() > 0);
|
|
}
|
|
|
|
/**
|
|
* Override this function to do something useful for the task.
|
|
*
|
|
* This function is called with the lock *not* held.
|
|
*/
|
|
AsyncTask::DoneStatus AsyncTaskSequence::
|
|
do_task() {
|
|
// Clear the delay that might have been set from a previous wait.
|
|
_delay = 0.0;
|
|
_has_delay = false;
|
|
|
|
if (_task_index >= get_num_tasks()) {
|
|
// Ran off the end of the task list.
|
|
set_current_task(nullptr, true);
|
|
_task_index = 0;
|
|
if (_task_index >= get_num_tasks()) {
|
|
return DS_done;
|
|
}
|
|
if (_repeat_count > 0) {
|
|
--_repeat_count;
|
|
}
|
|
if (_repeat_count != 0) {
|
|
return DS_cont;
|
|
}
|
|
return DS_done;
|
|
}
|
|
|
|
AsyncTask *task = get_task(_task_index);
|
|
set_current_task(task, true);
|
|
nassertr(_current_task != nullptr, DS_exit);
|
|
|
|
DoneStatus result = _current_task->do_task();
|
|
switch (result) {
|
|
case DS_again:
|
|
case DS_pause:
|
|
// The task wants to sleep for a period of time.
|
|
{
|
|
double now = _manager->_clock->get_frame_time();
|
|
_current_task->_start_time = now + _current_task->_delay;
|
|
|
|
_delay = _current_task->_delay;
|
|
_has_delay = _current_task->_has_delay;
|
|
|
|
if (result == DS_pause) {
|
|
// When it wakes up, move on to the next task.
|
|
++_task_index;
|
|
}
|
|
}
|
|
return DS_again;
|
|
|
|
case DS_done:
|
|
// Go on to the next task.
|
|
++_task_index;
|
|
return DS_cont;
|
|
|
|
case DS_cont:
|
|
case DS_pickup:
|
|
case DS_exit:
|
|
case DS_interrupt:
|
|
case DS_await:
|
|
// Just return these results through.
|
|
return result;
|
|
}
|
|
|
|
// Shouldn't get here.
|
|
nassertr(false, DS_exit);
|
|
return DS_exit;
|
|
}
|
|
|
|
/**
|
|
* Override this function to do something useful when the task has been added
|
|
* to the active queue.
|
|
*
|
|
* This function is called with the lock held. You may temporarily release if
|
|
* it necessary, but be sure to return with it held.
|
|
*/
|
|
void AsyncTaskSequence::
|
|
upon_birth(AsyncTaskManager *manager) {
|
|
AsyncTask::upon_birth(manager);
|
|
_task_index = 0;
|
|
set_current_task(nullptr, true);
|
|
}
|
|
|
|
/**
|
|
* Override this function to do something useful when the task has been
|
|
* removed from the active queue. The parameter clean_exit is true if the
|
|
* task has been removed because it exited normally (returning DS_done), or
|
|
* false if it was removed for some other reason (e.g.
|
|
* AsyncTaskManager::remove()). By the time this method is called, _manager
|
|
* has been cleared, so the parameter manager indicates the original
|
|
* AsyncTaskManager that owned this task.
|
|
*
|
|
* The normal behavior is to throw the done_event only if clean_exit is true.
|
|
*
|
|
* This function is called with the lock held. You may temporarily release if
|
|
* it necessary, but be sure to return with it held.
|
|
*/
|
|
void AsyncTaskSequence::
|
|
upon_death(AsyncTaskManager *manager, bool clean_exit) {
|
|
AsyncTask::upon_death(manager, clean_exit);
|
|
set_current_task(nullptr, clean_exit);
|
|
}
|
|
|
|
/**
|
|
* Sets the current executing task. If NULL, sets the current task to NULL.
|
|
*/
|
|
void AsyncTaskSequence::
|
|
set_current_task(AsyncTask *task, bool clean_exit) {
|
|
if (_current_task == task) {
|
|
return;
|
|
}
|
|
|
|
if (_current_task != nullptr) {
|
|
nassertv(_current_task->_state == S_active_nested);
|
|
nassertv(_current_task->_manager == _manager || _manager == nullptr);
|
|
_current_task->_state = S_inactive;
|
|
_current_task->_manager = nullptr;
|
|
_current_task->upon_death(_manager, clean_exit);
|
|
}
|
|
|
|
_current_task = task;
|
|
|
|
if (_current_task != nullptr) {
|
|
nassertv(_current_task->_state == S_inactive);
|
|
nassertv(_current_task->_manager == nullptr);
|
|
_current_task->upon_birth(_manager);
|
|
nassertv(_current_task->_state == S_inactive);
|
|
nassertv(_current_task->_manager == nullptr);
|
|
_current_task->_manager = _manager;
|
|
_current_task->_state = S_active_nested;
|
|
|
|
double now = _manager->_clock->get_frame_time();
|
|
task->_start_time = now;
|
|
task->_start_frame = _manager->_clock->get_frame_count();
|
|
}
|
|
}
|