![]() |
VR-Forces Developer's Guide
|
The Add Database Event example demonstrates the following:
By default, VR-Forces will not perform any database logging. Database logging can be enabled by editing the appData\settings\databaseConfig.mtl file to specify a valid database logger and database connection.
VR-Forces defines several different types of database events. Events are logged to the databse logger whenever something occurs in the sim that should be logged. Events include things such as the start of a new scenario run, the creation of an entity, the usage of a resource, a detonation, undertaking damage, or detecting other entities. Each event type maps to a table in the database. As events occur, they are logged to their matching database table. For more on database events, see the DtVrfDatabaseEvent class as well as the list of default events defined in the section VR-Forces Database Events.
To add a new type event, you just need to register the new event type with VR-Forces and tell it the name of the table in the database it should map to. This can be done by calling DtVrfDatabaseEvent::addEventType().
With a new type registered, you can now log events. This is done by making a call to the logEvent function of the database logger. This example adds callbacks for the creation of any animal entities. When the callback is received an event is logged with the database logger that includes some basic information about the entity.
First, you must setup a database. The only built-in database supported by VR-Forces is SQLite, which just logs to a local file. Other database types can be added via plugin.
In the appData\settings\databaseConfig.mtl file set the following: (database-logger-type "standard-database-logger") (database-connection-type "sqlite-database-connection")
Optionally you can also configure the database-name to specify a database name other than the default. This will change the name of the file created when using SQLite.
Since this example is loaded as a plugin, it will need to be enabled in the Launcher. In the Launcher, click the Plug-ins button to bring up the Plug-ins Selection dialog. Enable the plugin.
As an example, we have included a simple Python client that just prints all logged animal created events to the console. It is included with our other example Python database clients (see Database Clients (databaseClients)). The example simply connects to the database and then prints out all table entries in the AnimalCreated table. The examples are written to work with either SQLite or MySQL, though at this time VR-Forces can only has built-in support for SQLite. See the Database Clients (databaseClients) example documentation for more details.
/*******************************************************************************
** Copyright (c) 2024 MAK Technologies, Inc.
** All rights reserved.
*******************************************************************************/
#include <vrfcgf/vrfPluginExtension.h>
#include <vrfcgf/cgf.h>
#include <vrfMsgTransport/vrfDatabaseLogger.h>
#include <vrfMsgTransport/vrfDatabaseEvent.h>
#include <vrfobjcore/localObjectManager.h>
#include <vrfMsgTransport/vrfDatabaseLoggerInterface.h>
#include <vrfobjcore/localObject.h>
const DtVrfDatabaseEvent::EventType AnimalCreatedEvent = DtVrfDatabaseEvent::UserEvent;
void objectAddedCallback(const DtLocalObject* simObject, void* usr);
extern "C" {
DT_VRF_DLL_PLUGIN void DtPluginInformation(DtVrfPluginInformation& info)
{
info.pluginName = "Add Database Event";
info.pluginVersion = "1.00";
info.pluginCreator = "MAK Technologies";
info.pluginCreatorEmail = "sales@mak.com";
info.pluginContactWebPage = "www.mak.com";
info.pluginContactMailingAddress = "10 Fawcett Street, Suite 204, Cambridge, MA 02138 USA";
info.pluginContactPhone = "(617) 876 8085";
}
DT_VRF_DLL_PLUGIN bool DtInitializeVrfPlugin(DtCgf* cgf)
{
// Register the new event type. Events require a unique
// DtVrfDatabaseEvent::EventType value and a unique table name. A table with
// this name will be created in the database the first time an event of this
// type is logged.
// All user events should start at the value DtVrfDatabaseEvent::UserEvent and
// increase from there.
DtVrfDatabaseEvent::addEventType(AnimalCreatedEvent, "AnimalCreated");
return true;
}
DT_VRF_DLL_PLUGIN bool DtPostInitializeVrfPlugin(DtCgf* cgf)
{
// Add a callback for the creation of a non-human lifeform.
cgf->localObjectManager()->addSimObjectAddedCallback(objectAddedCallback, cgf,
DtObjectType(1, 3, -1, -1, 5, -1, -1, -1));
cgf->localObjectManager()->addSimObjectAddedCallback(objectAddedCallback, cgf,
DtObjectType(1, 3, -1, -1, 200, -1, -1, -1));
cgf->localObjectManager()->addSimObjectAddedCallback(objectAddedCallback, cgf,
DtObjectType(1, 3, -1, -1, 201, -1, -1, -1));
cgf->localObjectManager()->addSimObjectAddedCallback(objectAddedCallback, cgf,
DtObjectType(1, 3, -1, -1, 202, -1, -1, -1));
cgf->localObjectManager()->addSimObjectAddedCallback(objectAddedCallback, cgf,
DtObjectType(1, 3, -1, -1, 203, -1, -1, -1));
cgf->localObjectManager()->addSimObjectAddedCallback(objectAddedCallback, cgf,
DtObjectType(1, 3, -1, -1, 204, -1, -1, -1));
return true;
}
}
// Callback to process the creation of a non-human lifeform.
void objectAddedCallback(const DtLocalObject* simObject, void* usr)
{
DtCgf* cgf = static_cast<DtCgf*>(usr);
// Create some example data just based on entity type. This is just
// to demonstrate that many data types can be logged.
static const std::map<DtEntityType, std::string> sounds{
{DtEntityType(3, 1, 0, 5, 1, 1, 0), "woof"},
{DtEntityType(3, 1, 0, 5, 1, 6, 0), "cluck"},
{DtEntityType(3, 1, 0, 5, 1, 3, 0), "moo"},
{DtEntityType(3, 1, 0, 5, 1, 7, 1), "baa"}
};
static const std::map<DtEntityType, bool> mammal{
{DtEntityType(3, 1, 0, 5, 1, 1, 0), true},
{DtEntityType(3, 1, 0, 5, 1, 6, 0), false},
{DtEntityType(3, 1, 0, 5, 1, 3, 0), true},
{DtEntityType(3, 1, 0, 5, 1, 7, 1), true}
};
static const std::map<DtEntityType, int> numLegs{
{DtEntityType(3, 1, 0, 5, 1, 1, 0), 4},
{DtEntityType(3, 1, 0, 5, 1, 6, 0), 2},
{DtEntityType(3, 1, 0, 5, 1, 3, 0), 4},
{DtEntityType(3, 1, 0, 5, 1, 7, 1), 4}
};
std::string sound = "other";
auto soundIter = sounds.find(simObject->entityType());
if (soundIter != sounds.end())
{
sound = soundIter->second;
}
bool isMammal = false;
auto mammalIter = mammal.find(simObject->entityType());
if (mammalIter != mammal.end())
{
isMammal = mammalIter->second;
}
int numberOfLegs = -1;
auto numLegsIter = numLegs.find(simObject->entityType());
if (numLegsIter != numLegs.end())
{
numberOfLegs = numLegsIter->second;
}
// Log the database event with a variety parameter data types (such as strings,
// integers, doubles, bools, UUIDs, entity types, and location vectors).
// The API supports simply passing a DtVrfDatabaseEvent directly, however it provides the
// option to pass a function such as the lambda used here. The reason this is useful
// is that it prevents the Event from ever being created if logging for that event type
// is disabled. In that case, the passed function is simply not called, minimizing the
// effect on performance when logging is disabled.
// Additionally, a std::move() is added to allow the created DtVrfDatabaseEvent to use
// a move instead of a copy, which is more efficient.
cgf->simulationServices()->databaseLogger()->logEvent(AnimalCreatedEvent, [=]() {
return std::move(DtVrfDatabaseEvent()
.addParameter("entity", simObject->uuid())
.addParameter("entityType", simObject->entityType())
.addParameter("location", simObject->worldPosition())
.addParameter("sound", sound)
.addParameter("isMammal", isMammal)
.addParameter("numberOfLegs", numberOfLegs)
.addParameter("height", simObject->boundingVolume().height()));
});
}