![]() |
VR-Forces 4.3 Class Documentation
|
To execute a DtPlan, its tick() function must be called.
DtPlans are ticked by the DtVrfObjectPlanManager that owns them. When the DtCgf is ticked, it ticks the DtVrfObjectManager, which ticks each DtVrfObject. DtVrfObject::tick() ticks the DtVrfObjectPlanManager. The remainder of this section discusses the details of how a DtPlan advances through its statements during execution.
A plan's current statement is returned by the DtPlan::currentStmt() member function and is actually just the top entry on its execution stack (myExecutionStack). The execution stack is a list of DtStmtIndex (stmtIndex.h) objects. (DtStmntIndex is a type of smart pointer used to reference DtSimStatements.) If the execution stack is empty, currentStmt() returns an empty statement index. This is the initial state of a plan prior to execution.
Execution of a plan begins when the DtSimTaskManager accesses the plan for an object through its DtVrfObjectPlanManager and calls awaitingTask() on it. This starts the following process:
Each derived type of DtSimStatement implements execute() differently. The DtSimTask and DtSetDataRequestStmts execute() functions send DtTask and DtSetDataRequest statements to the entity, respectively. DtWhenStmts register themselves as triggers in the DtPlan when they are executed. As a trigger, the conditional expression in a When statement gets evaluated every tick by the DtPlan. When the condition evaluates to true, then it executes its block of statements. Triggers are discussed in more detail in 13.6.5 Triggers (or When Statements) and 13.9 - Triggers.
The continuePlan() member function continues the execution cycle. The first time through it is called as a result of the executeBlock() member function being called on the plan’s main block. (For details, please see 13.6.2 Starting the Plan.) The protected DtPlan::continuePlan() member function continues the plan execution cycle until either the myTaskRequestPending flag is cleared, or the myIsComplete flag gets set. The execution cycle consists of alternating calls to DtPlan::stepStatement() to step the current statement pointer to the next statement, and DtPlan::executeStatement() to execute it. The loop begins with a step because the plan's current statement actually indicates the last statement executed - the one that sent the entity its previous task.
In continuePlan(), the execution cycle proceeds as follows:
When an entity requests a task from its plan, the plan sets its internal myTaskRequestPending flag, which remains true until a statement is executed that causes a task to be sent back to the entity. The task pending flag is used to decide when to halt the execution cycle in the member function DtPlan::continuePlan().
When an entity reaches the end of its plan, the plan's myIsComplete flag is set to true. This halts further execution of the plan's statements. However, pending triggers are still tested and can still fire, causing execution to resume at the start of the trigger block.
When statements are special kinds of statements, known as triggers. When a When statement gets executed (DtWhen::execute() is called), it creates a DtSimTrigger object and registers it with the plan as a pending trigger by calling DtPlan::addTrigger(). Each plan keeps a list of pending triggers (myPendingTriggers). In its tick() function, it periodically checks their associated conditions to determine if they should be fired. If a trigger fires, the plan must keep track of which statement was interrupted so that after the trigger block completes, execution can resume with the statement following the interrupted statement. It does so using a stack of statement index objects (myExecutionStack), stored in a DtList.
You can have an entity abandon execution of its plan by accessing its DtPlan through its DtVrfObjectPlanManager and calling abandonPlan() on it.This results in the plan setting its status to complete.
[<< Examining and Changing Plans] [Home] [Top of Page] [Statements >>]