Introduction to Project 3C
Project 3C in the Distributed Simulation tutorial takes a look at how to add both an add and a remove reflected entity callback to the simulation connection using VR-Link, which will inform the driver as to the entry and exit of an entity into and from the scene. Entities that are added to the scene can be agents added at scenario load and removed at scenario unload. Note that added entities can also be introduced during the run of a scenario, such as the introduction of a missile by another agent, the detonation of which will result in that missile entity's removal from the scene.
Examining the files that make up the project
For this project, we will again use project 2A as the base, and no more class files will need to be added. All changes will be made in the DistributedSimulationDriver class as before.
Adding Reflected Entity Callbacks
To add callbacks, we will need to add two static callback functions, one for entity addition and the other for entity removal. We will also need instance functions for these callbacks to invoke in order for the actual instance of the driver to receive and respond to received entity data.
The first thing we need to do is to add declarations for both callback functions and both instance functions to the driver header file. All functions will need to take a pointer to a DtReflectedEntity object. The callbacks will also need to receive a void pointer to the object which owns the associated local instance function that the callback function will need to invoke.
static void processReflectedEntityAdditionCb(DtReflectedEntity *reflectedObj, void *usr);
static void processReflectedEntityRemovalCb(DtReflectedEntity *reflectedObj, void *usr);
virtual void processReflectedEntityAdd(DtReflectedEntity *reflectedObj) const;
virtual void processReflectedEntityRemove(DtReflectedEntity *reflectedObj) const;
The new onStart() function looks as follows:
{
std::cout << "DistributedSimulationDriver::onStart(): " << std::endl;
DtExerciseConnInitializer
init;
init.setPort(3152);
init.setExerciseId(1);
init.setSiteId(2);
init.setApplicationNumber(1);
init.setReceiveBufferSize(0x100000);
DtExerciseConn::InitializationStatus status = DtExerciseConn::DtINIT_SUCCESS;
try
{
myConnection = new DtExerciseConn(init, &status);
}
catch(...)
{
return false;
}
myConnectionState = (status == DtExerciseConn::DtINIT_SUCCESS);
myConnection->clock()->setSimTime(0);
myReflectedEntityList->addEntityAdditionCallback(&processReflectedEntityAdditionCb, this);
myReflectedEntityList->addEntityRemovalCallback(&processReflectedEntityRemovalCb, this);
return myConnectionState;
}
The difference between this version and the version in Project 3A is that, instead of directly adding a callback for detonation interactions, we add a code block for instantiating a DtReflectedEntityList object, passing it our connection object. We then add to the entity list object references to our callback functions. It is important that the clock sim time should be reset.
myConnection->clock()->setSimTime(0);
myReflectedEntityList->addEntityAdditionCallback(&processReflectedEntityAdditionCb, this);
myReflectedEntityList->addEntityRemovalCallback(&processReflectedEntityRemovalCb, this);
The callback functions, as noted, both take pointers of the type DtReflectedEntity, as well as void pointers to the object that owns the instance function that will be called from within both callbacks.
void DistributedSimulationDriver::processReflectedEntityAdditionCb(DtReflectedEntity *reflectedObj, void *usr)
{
((DistributedSimulationDriver*)usr)->processReflectedEntityAdd(reflectedObj);
}
void DistributedSimulationDriver::processReflectedEntityRemovalCb(DtReflectedEntity *reflectedObj, void *usr)
{
((DistributedSimulationDriver*)usr)->processReflectedEntityRemove(reflectedObj);
}
Both callback functions will make calls to the instance functions shown here. These instance functions receive a DtReflectedEntity each, and print out arbitrary values regarding the associated entity.
void DistributedSimulationDriver::processReflectedEntityAdd(DtReflectedEntity *reflectedObj) const
{
std::cout << "A(" << reflectedObj->entityId().entityNum() << "," << reflectedObj->id().entityNum() << "," << reflectedObj->idString() << ")";
}
void DistributedSimulationDriver::processReflectedEntityRemove(DtReflectedEntity *reflectedObj) const
{
std::cout << "R(" << reflectedObj->entityId().entityNum() << "," << reflectedObj->id().entityNum() << "," << reflectedObj->idString() << ")";
}
Testing the plugin
Invoke either the tutorialDistributedSimulation3Cd.bat or tutorialDistributedSimulation3C.sh script file to start the VR-Vantage Stealth application. Follow these instructions to test the plugin:
-
Choose File > View > Drivers Panel.
-
Select the driver named "DistributedSimulationDriver3C".
-
Click on the Start button.
-
You will see in the console window that the text "DistributedSimulationDriver::onStart():" has printed, and on the subsequent line, a series of dots is now continually being printed. Each dot is followed by the number of PDUs read in from the simulation connection.
-
Start up a VR-Forces application using DIS as the protocol, open a scenario that has at least one entity added, and then start the scenario. As before, the number of PDUs will increase notably. Once data comes in for an entity addition, an A(x,y,z) will be printed, where A stands for addition, and x, y, and z are arbitrarily chosen values from the detonation interaction object. If the scenario that you started contained detonations, when a detonation occurs, you will also see a R(x,y,z) printed, where R stands for removal. You will notice that the strings "New Entity" and "Final PDU" are printed, just before the A(x,y,z) and R(x,y,z) respectively. The simulation connection prints both of these strings to the command window, while our project prints both of the latter strings. The content of the entity information strings printed after "New Entity" and "Final PDU" helps verify that the printouts from our project show correct data, and that the data corresponds to the additions and removals of entities in the scene.
-
Go back to Stealth, make sure the same driver is selected in the Drivers Panel, and click the Stop button.
-
You will see in the console window that the dots, byte counts, and detonations are no longer being printed, and that the text "DistributedSimulationDriver::onStop():" has been printed on the subsequent line.
-
Continually clicking the Start and Stop button will keep starting and stopping the driver, giving these same results in the console window.
[<< Add a Detonation Listener] [Add an Entity Existence Listener >>]
Project Files
DistributedSimulationDriver3C.h
#pragma once
class DtExerciseConn;
class DtReflectedEntity;
namespace makVrv
{
namespace tutorialDistributedSimulation3C
{
class DistributedSimulationDriver : public DtDriver
{
public:
virtual const std::string&
className()
const;
protected:
protected:
};
}
}
DistributedSimulationDriver3C.cxx
#define DtDIS 1
#include <vl/exConnInit.h>
#include <vl/exerciseConn.h>
#include <vl/dReflEntList.h>
#include <iostream>
namespace makVrv
{
namespace tutorialDistributedSimulation3C
{
DtAgentManager& agentManager, const std::string& instanceName)
: DtDriver(agentManager, instanceName)
, myConnection(0)
, myConnectionState(0)
{
}
DistributedSimulationDriver::~DistributedSimulationDriver(void)
{
}
const std::string& DistributedSimulationDriver::className() const
{
static std::string name("DistributedSimulationDriver");
return name;
}
bool DistributedSimulationDriver::onStart()
{
std::cout << "DistributedSimulationDriver::onStart(): " << std::endl;
DtExerciseConnInitializer
init;
init.setPort(3152);
init.setExerciseId(1);
init.setSiteId(2);
init.setApplicationNumber(1);
init.setReceiveBufferSize(0x100000);
DtExerciseConn::InitializationStatus status = DtExerciseConn::DtINIT_SUCCESS;
try
{
myConnection = new DtExerciseConn(init, &status);
}
catch(...)
{
return false;
}
myConnectionState = (status == DtExerciseConn::DtINIT_SUCCESS);
myConnection->clock()->setSimTime(0);
myReflectedEntityList->addEntityAdditionCallback(&processReflectedEntityAdditionCb, this);
myReflectedEntityList->addEntityRemovalCallback(&processReflectedEntityRemovalCb, this);
return myConnectionState;
}
bool DistributedSimulationDriver::onStop()
{
std::cout << "DistributedSimulationDriver::onStop(): " << std::endl;
delete myConnection;
myConnection = 0;
return true;
}
bool DistributedSimulationDriver::onTick()
{
if (myConnectionState)
{
int numread = myConnection->drainInput();
std::cout << "." << numread;
}
else
std::cout << "x";
return myConnectionState;
}
void DistributedSimulationDriver::processReflectedEntityAdditionCb(DtReflectedEntity *reflectedObj, void *usr)
{
((DistributedSimulationDriver*)usr)->processReflectedEntityAdd(reflectedObj);
}
void DistributedSimulationDriver::processReflectedEntityRemovalCb(DtReflectedEntity *reflectedObj, void *usr)
{
((DistributedSimulationDriver*)usr)->processReflectedEntityRemove(reflectedObj);
}
void DistributedSimulationDriver::processReflectedEntityAdd(DtReflectedEntity *reflectedObj) const
{
std::cout << "A(" << reflectedObj->entityId().entityNum() << "," << reflectedObj->id().entityNum() << "," << reflectedObj->idString() << ")";
}
void DistributedSimulationDriver::processReflectedEntityRemove(DtReflectedEntity *reflectedObj) const
{
std::cout << "R(" << reflectedObj->entityId().entityNum() << "," << reflectedObj->id().entityNum() << "," << reflectedObj->idString() << ")";
}
}
}
DistributedSimulationPlugin3C.h
#pragma once
#ifdef WIN32
#define DT_DE_PLUGIN_EXPORT_MACRO __declspec ( dllexport )
#else
#define DT_DE_PLUGIN_EXPORT_MACRO
#endif
namespace makVrv { class DtDe; }
DistributedSimulationPlugin3C.cxx
#include <boost/bind.hpp>
using namespace makVrv;
using namespace makVrv::tutorialDistributedSimulation3C;
{
DistributedSimulationDriver* driver = new DistributedSimulationDriver(
}
{
{
}
}
{
return true;
}