![]() |
VR-Forces 4.0.4 Class Documentation
|
The Add Task example adds a new kind of task - retreat - to the list of entity tasks. The method of doing so is to add a new task and controller which will receive and implement the new DtRetreatTask. The example is intened to demonstrate the following:
If you want to derive a new task from DtSimTask, you have to complete the following general steps:
The first step in creating a new task type is to create a new task class derived from DtSimTask. You need to assign it a unique integer type to identify the task (task type names are defined in radioMsgTypes.h). The entity's controllers use the task type to determine how to handle an incoming task.
The DtSimTask class has the following pure virtual member functions that you must override in the derived task:
To make your new DtSimTask capable of being sent over the network, as part of a DtTaskMessage or as part of a DtIfPlan message, you must override the following member functions in your derived task:
Once you have defined a new task and have registered the task with the factory, add a new controller to the entity to carry out the action described by the task. To do this, you must derive a new controller from DtTaskControllerComponent. (For details, please see "Controller Components," in section 5.2.7 of the VRF Back-End Developers Guide). The new controller must have a unique string type and must be registered with the corresponding component factory.
In your new task controller component, you must override registerTaskMsgCallbacks() to register your callback function for handling the new task. Once it is registered, your callback function will be called when a message of the new derived type is received on its radio net. In your callback (actually, in a virtual member function of your controller, called from the static callback), extract the necessary data from the task message parameters and start executing the task.
In the addTask example, the creator functions for both the controller (DtRetreatController) and the task (DtRetreatTask) are registered with their factories in the DtInitializeVrfPlugin module of plugin.cxx:
DT_VRF_DLL_PLUGIN bool DtInitializeVrfPlugin(DtCgf* cgf) { //Register the creator function for the controller cgf->factoryManager()->componentFactory()->addCreatorFcn( TestRetreatControllerType, DtRetreatController::creator); //Register the creator function for the task cgf->factoryManager()->taskFactory()->addCreatorFcn( DtRetreatTaskTypeString, DtRetreatTaskType, DtRetreatTask::creator); return true; }
You need to add a new controller to an entity to carry out the task contained by the DtUserTask. Since the retreat behavior is just a variation on behaviors already present in DtGroundAutoControllerComponent, we derive the new controller from DtGroundAutoControllerComponent, and register for a DtUserTask message. To do this, override registerTaskMsgCallbacks() to register an interest in incoming DtUserTask messages.
To uniquely identify the new controller, the type() member function must be overridden to provide a unique string name for the new component. In our example, we used the const TestRetreatControllerType and the string "retreat-controller." Default component names in VR Forces are defined in compTypes.h.
DtString DtRetreatController::type() const { //Defined in retreatCtlr.h return TestRetreatControllerType; }
This code shows how to register for the DtUserTask message on our radio net, providing a callback function for handling DtUserTask messages.
void DtRetreatController::registerTaskMsgCallbacks() { //Register for any task messsages required by the base class DtSingleTaskControllerComponent::registerTaskMsgCallbacks(); //Specify the task type, the callback function, and user data. addTaskProcessorCallback(DtUserTaskType, userTaskCallback, (void *) this); //Specify the task type, the callback function, and user data. addTaskProcessorCallback(DtRetreatTaskType, retreatTaskCallback, (void *) this); } void DtRetreatController::retreatTaskCallback(DtSimMessage * msg, void * usrData) { DtRetreatController * controller = (DtRetreatController *) usrData; if (controller) { //Call processRetreatTask to handle the incoming retreat task message. controller->processRetreatTask(msg); } } void DtRetreatController::userTaskCallback(DtSimMessage * msg, void * usrData) { DtRetreatController * controller = (DtRetreatController *) usrData; if (controller) { //Call processUserTask to handle the incoming user task message. controller->processUserTask(msg); } }
In the callback processing function, some additional checking is required to see if the message contained inside the DtUserTask is actually the task we are looking for. The DtUserTask message can be used for any number of different user-defined tasks, so we need to check the userTaskName() in the callback to determine if the message is really the kind we are looking for.
void DtRetreatController::processRetreatTask(DtSimMessage * msg) { if (msg) { //Retrieve the task from the task message. DtTaskMessage * tm = (DtTaskMessage *) msg; DtRetreatTask * retreatTask = (DtRetreatTask *) tm->task(); //Check to see if the task is a user-defined retreat task. This //is the string that is matched against the User Task dialog. if(retreatTask->retreatKind() == "hold-ground") { myHoldGround = true; }; } } void DtRetreatController::processUserTask(DtSimMessage * msg) { if (msg) { //Retrieve the task from the task message. DtTaskMessage * tm = (DtTaskMessage *) msg; DtUserTask * userTask = (DtUserTask *) tm->task(); //Check to see if the task is a user-defined retreat task. This //is the string that is matched against the User Task dialog. if(userTask->userTaskName() != "retreat") { taskComplete(false); return; } //Extract parameters from arguments if (userTask->arg1Text() == "hold ground") { myHoldGround = true; }; } }
If you define a tick() member function for your component, it gets placed on a tick list for the entity, and is called periodically. You can use this member function to update the control values for the retreat task here. Check the ‘tasked’ state (myTasked member variable) to see if the controller is currently being tasked to determine if updates need to be made.
For examples of how the tick() member function works in controllers, please see "Controller Components," in section 5.2.7 of the VRF Back-End Developers Guide.
Since this example is loaded as a plugin, it can be used in conjunction with the released VR-Forces application
In order for the new controller to be created for a given entity type, it must be added to the movement system for that entity. The addTask example comes with a SMS which is located in .sms. In this SMS, the retreat controller is added to the M1A2. In data\simulationModelSets\developer_toolkit_examples\addTask\vrfSim\systems\movement\ground-tracked-default.sysdef the system is defined as:
(retreat
(component-descriptor-type "component-descriptor")
(component-type "retreat-controller")
(min-tick-period -1.000000)
(min-tick-period-variance -1.000000)
(process-state-repository-name "")
(process-state-repository-type "")
)
Select Settings, Plugins... and on the Plugins Editor page, use the combo box at the top of the page to select the plug-in. Then enable the Load Plugin checkbox and re-start VR-Forces.
To view the new behavior, load the scenario data\scenarios\developer_toolkit_examples\addTask\retreat.scn Entities tasked to "retreat immediately" will move at full speed in the opposite direction from enemy entities Entities tasked to "hold ground" will stay still until they determine themselves to be "under fire," at which point they will retreat at full speed in the opposite direction from enemy entities
If the retreat command is to be enabled in any scenario, the addTask.sms file must be added to the scenario configuration. In the "New Scenario" window, under Simulation Model Sets, click the "..." button to open the Simulation Model Set Files dialog. Add the sms file .sms
| DtRetreatTask | The subclass of DtSimTask that is used to communicate the new task request. |
| DtRetreatController | The subclass of DtGroundAutoControllerComponent implements the DtRetreatTask command. |
/*******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
*******************************************************************************/
#include "vrfcgf/vrfPluginExtension.h"
#include "retreatCtrl.h"
#include "retreatTask.h"
#include "vrfcgf/cgf.h"
#include "vrfcgf/factoryMgr.h"
#include "vrfobjcore/compTypes.h"
extern "C" {
DT_VRF_DLL_PLUGIN void DtPluginInformation(DtVrfPluginInformation& info)
{
info.pluginName = "Add TaskSim";
info.pluginVersion = "1.00";
info.pluginCreator = "MAK Technologies";
info.pluginCreatorEmail = "sales@mak.com";
info.pluginContactWebPage = "www.mak.com";
info.pluginContactMailingAddress = "68 Moulton Street - Cambridge, MA 02138";
info.pluginContactPhone = "(617) 876 8085";
}
//[Registering creator methods]
DT_VRF_DLL_PLUGIN bool DtInitializeVrfPlugin(DtCgf* cgf)
{
//Register the creator function for the controller
cgf->factoryManager()->componentFactory()->addCreatorFcn(
TestRetreatControllerType, DtRetreatController::creator);
//Register the creator function for the task
cgf->factoryManager()->taskFactory()->addCreatorFcn(
DtRetreatTaskTypeString, DtRetreatTaskType, DtRetreatTask::creator);
return true;
}
//[Registering creator methods]
}