207 lines
6.8 KiB
C++
207 lines
6.8 KiB
C++
// Filename: asyncTaskSequence.cxx
|
|
// Created by: drose (04Oct08)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "asyncTaskSequence.h"
|
|
|
|
TypeHandle AsyncTaskSequence::_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AsyncTaskSequence::Constructor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
AsyncTaskSequence::
|
|
AsyncTaskSequence(const string &name) :
|
|
AsyncTask(name),
|
|
_repeat_count(0),
|
|
_task_index(0)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AsyncTaskSequence::Destructor
|
|
// Access: Published, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
AsyncTaskSequence::
|
|
~AsyncTaskSequence() {
|
|
set_current_task(NULL, true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AsyncTaskSequence::is_runnable
|
|
// Access: Protected, Virtual
|
|
// Description: 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);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AsyncTaskSequence::do_task
|
|
// Access: Protected, Virtual
|
|
// Description: 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(NULL, 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 != (AsyncTask *)NULL, 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:
|
|
// Just return these results through.
|
|
return result;
|
|
}
|
|
|
|
// Shouldn't get here.
|
|
nassertr(false, DS_exit);
|
|
return DS_exit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AsyncTaskSequence::upon_birth
|
|
// Access: Protected, Virtual
|
|
// Description: 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(NULL, true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AsyncTaskSequence::upon_death
|
|
// Access: Protected, Virtual
|
|
// Description: 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(NULL, clean_exit);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: AsyncTaskSequence::set_current_task
|
|
// Access: Private
|
|
// Description: 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 != (AsyncTask *)NULL) {
|
|
nassertv(_current_task->_state == S_active_nested);
|
|
nassertv(_current_task->_manager == _manager || _manager == NULL);
|
|
_current_task->_state = S_inactive;
|
|
_current_task->_manager = NULL;
|
|
_current_task->upon_death(_manager, clean_exit);
|
|
}
|
|
|
|
_current_task = task;
|
|
|
|
if (_current_task != (AsyncTask *)NULL) {
|
|
nassertv(_current_task->_state == S_inactive);
|
|
nassertv(_current_task->_manager == NULL);
|
|
_current_task->upon_birth(_manager);
|
|
nassertv(_current_task->_state == S_inactive);
|
|
nassertv(_current_task->_manager == NULL);
|
|
_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();
|
|
}
|
|
}
|