Tutorial_VisualDebug.cpp

Tutorial_VisualDebug.cpp
/*
* Copyright 2016 Autodesk, Inc. All rights reserved.
* Use of this software is subject to the terms of the Autodesk license agreement and any attachments or Appendices thereto provided at the time of installation or download,
* or which otherwise accompanies this software in either electronic or hard copy form, or which is signed by you and accepted by Autodesk.
*/
#include "common/oneworldenv.h"
#include "testfwk/System.h"
#include "labengine/commands/textualcommandreceiver.h"
#include "labengine/commands/commands.h"
#include "labengine/base/kaimfileopener.h"
namespace
{
// Use of OneWorldEnv initializes Kaim::BaseSystem and Kaim::World for us in this tutorial.
// For more information on how to initialize Kaim::World, look at Tutorial_WorldInit.cpp
#define KT_TEST_ENV_CLASS OneWorldEnv
KT_TEST_ENV {}
// This class is used in order to process an "Exit" command from the Autodesk Navigation Lab
class ExitCommandProcessor : public LabEngine::ICommandProcessor
{
public:
ExitCommandProcessor() : m_doExit(false) {}
virtual void Process(const LabEngine::CommandInstance&) { m_doExit = true; }
public:
bool m_doExit;
};
KT_TUTORIAL // How to Visual Debug a world
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Visual Debug a world");
#if defined(KY_CONFIG_DEBUG_OR_DEV)
KT_ASSERT(KT_ENV.AddNavData("generated/plane200x200_80ktri/plane200x200_80ktri.NavData") != nullptr);
KT_ASSERT(KT_ENV.AddRandomBots(1) == 1);
Kaim::World* navWorld = KT_ENV.GetNavWorld();
// To start the visual debug of a world call Kaim::World::StartVisualDebug() with a config.
// The config specifies how to use the visual debug server, here we connect to the NavigationLab using the default port,
// and we won't wait on Kaim::World::StartVisualDebug() call (using Kaim::VisualDebugServerConfig::DoWaitOnStart would however wait infinitely)
// However, we can for a given duration by manually calling Kaim::VisualDebugServer::WaitWhileEstablishingConnection()
Kaim::VisualDebugServerConfig visualDebugServerConfig;
KyUInt32 serverPort = Kaim::VisualDebugServerConfig::DefaultServerPort();
KyUInt32 broadcastPort = Kaim::VisualDebugServerConfig::DefaultBroadcastPort(); // Pass 0 to disable broadcast.
visualDebugServerConfig.UseNavigationLab(serverPort, broadcastPort);
visualDebugServerConfig.SetWaitOnStart(Kaim::VisualDebugServerConfig::DoNotWaitOnStart);
KyResult startResult = navWorld->StartVisualDebug(visualDebugServerConfig);
if (startResult == KY_ERROR)
{
TestLog() << "Failed to start visual debug\n";
KT_ASSERT(false);
}
navWorld->GetVisualDebugServer()->WaitWhileEstablishingConnection(1); // waiting for 1 ms
// During the course of the game, the SDK will send information to the NavigationLab
for (KyUInt32 gameFrame = 0; gameFrame < 10; ++gameFrame)
{
// call NewFrame at the beginning of a game frame whatever the status of the VisualdebugServer is
navWorld->NewVisualDebugFrame();
navWorld->Update();
}
navWorld->StopVisualDebug();
#endif
KT_ENV.CleanUpWorld();
}
// This tutorial looks at several aspects of Visual debugging in Navigation.
KT_TUTORIAL // How to visually debug custom information sent to a world
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Send custom information through Kaim::VisualDebugServer");
#if defined(KY_CONFIG_DEBUG_OR_DEV)
KT_ASSERT(KT_ENV.AddNavData("generated/plane200x200_80ktri/plane200x200_80ktri.NavData") != nullptr);
KT_ASSERT(KT_ENV.AddRandomBots(1) == 1);
LabEngine::GameBot* gameBot = KT_ENV.GetGameWorld()->GetBots()[0];
Kaim::World* navWorld = KT_ENV.GetNavWorld();
// Start the Visual Debug Server.
Kaim::VisualDebugServerConfig visualDebugServerConfig;
KyUInt32 serverPort = Kaim::VisualDebugServerConfig::DefaultServerPort();
KyUInt32 broadcastPort = Kaim::VisualDebugServerConfig::DefaultBroadcastPort(); // Pass 0 to disable broadcast.
visualDebugServerConfig.UseNavigationLab(serverPort, broadcastPort);
visualDebugServerConfig.SetWaitOnStart(Kaim::VisualDebugServerConfig::DoNotWaitOnStart);
KyResult startResult = navWorld->StartVisualDebug(visualDebugServerConfig);
if (startResult == KY_ERROR)
{
TestLog() << "Failed to start visual debug\n";
KT_ASSERT(false);
}
Kaim::VisualDebugServer* visualDebugServer = navWorld->GetVisualDebugServer();
// During the course of the game, you can use the Visual Debug Server to send custom information.
// This information can then be:
// - displayed in NavigationLab's viewport using the display list system
// - monitored in NavigationLab's Statistics panel
const char* tutroialCategoryName = "Tutorial_World";
Kaim::FloatStat gameStats("GameFrameAsStats");
Kaim::DisplayListActivation dynamicallyEnableOrDisableDisplayListInGame = Kaim::DisplayList_Enable;
for (KyUInt32 gameFrame = 0; gameFrame < 10; ++gameFrame)
{
// call NewFrame at the beginning of a game frame whatever the status of the VisualdebugServer is
visualDebugServer->NewFrame();
// Update the world
navWorld->Update();
// Update average, max, and min statistics as computed by the game.
gameStats.SetCurrent((KyFloat32)gameFrame);
gameStats.Update();
// always check that IsReadyToSend before sending messages
// to prevent useless construction of messages
if (visualDebugServer->IsReadyToSend() == false)
continue;
// Send a single value
visualDebugServer->SendUInt32("GameFrame", gameFrame, tutroialCategoryName);
// Send current, average, max, and min statistics as computed by the game.
visualDebugServer->SendStats(gameStats, tutroialCategoryName);
{
// Send a first display list
Kaim::DisplayList displayList(navWorld->GetDisplayListManager(), dynamicallyEnableOrDisableDisplayListInGame);
displayList.InitSingleFrameLifespan("GameBot To OriginLine", tutroialCategoryName);
displayList.PushLine(gameBot->GetPosition(), Kaim::Vec3f::Zero(), Kaim::Color::White);
}
{
// Send a second display list that is associated to Kaim::Bot VisualDebug config in the NavigationLab
Kaim::Vec3f destination = gameBot->GetRoute().GetCurrentWayPoint();
Kaim::DisplayList displayList(navWorld->GetDisplayListManager(), dynamicallyEnableOrDisableDisplayListInGame);
displayList.InitSingleFrameLifespan("Destination", "Tutorial", gameBot->GetBot()->GetVisualDebugId());
KyFloat32 displayRadius = 1.0f;
displayList.PushPoint(destination, displayRadius, Kaim::Color::Yellow);
displayList.PushArrowTube(gameBot->GetPosition(), destination, displayRadius, Kaim::ShapeColor::FillAndLine(Kaim::Color::Magenta));
displayList.PushText(destination + Kaim::Vec3f::UnitZ(),Kaim::Color::Magenta, "Destination");
}
}
#endif
KT_ENV.CleanUpWorld();
}
KT_TUTORIAL // How to control lifetime of a display list over several frames without sending it each frame
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Send a DisplayList once, but keep it alive several frames in the NavigationLab");
#if defined(KY_CONFIG_DEBUG_OR_DEV)
Kaim::World* navWorld = KT_ENV.GetNavWorld();
Kaim::VisualDebugServerConfig::WaitOnStart waitOnStart = Kaim::VisualDebugServerConfig::DoNotWaitOnStart; // Change this to DoWaitOnStart to try it with the Lab
// Start the Visual Debug Server.
Kaim::VisualDebugServerConfig visualDebugServerConfig;
KyUInt32 serverPort = Kaim::VisualDebugServerConfig::DefaultServerPort();
KyUInt32 broadcastPort = Kaim::VisualDebugServerConfig::DefaultBroadcastPort(); // Pass 0 to disable broadcast.
visualDebugServerConfig.UseNavigationLab(serverPort, broadcastPort);
visualDebugServerConfig.SetWaitOnStart(waitOnStart);
KyResult startResult = navWorld->StartVisualDebug(visualDebugServerConfig);
if (startResult == KY_ERROR)
{
TestLog() << "Failed to start visual debug\n";
KT_ASSERT(false);
}
const char* tutorialCategoryName = "Tutorial_World";
// id assigned to our DisplayList
KyUInt32 displayListId = KyUInt32MAXVAL;
for (KyUInt32 gameFrame = 0; gameFrame < 1000; ++gameFrame)
{
// call NewFrame at the beginning of a game frame whatever the status of the VisualdebugServer is
navWorld->NewVisualDebugFrame();
// Update the world
navWorld->Update();
// always check that IsReadyToSend before sending messages
// to prevent useless construction of messages
if (navWorld->GetVisualDebugServer()->IsReadyToSend())
{
if (gameFrame == 4)
{
// Send a display list only once
Kaim::DisplayList displayList(navWorld->GetDisplayListManager());
displayListId = displayList.InitUserControlledLifespan("UserControlledLifespan", tutorialCategoryName, displayListId);
displayList.PushText(Kaim::Vec3f::Zero(), Kaim::Color::Red, "Sent at frame 4");
}
else if (gameFrame == 8)
{
// if we want to change it
Kaim::DisplayList displayList(navWorld->GetDisplayListManager());
displayListId = displayList.InitUserControlledLifespan("UserControlledLifespan", tutorialCategoryName, displayListId);
displayList.PushText(Kaim::Vec3f::Zero(), Kaim::Color::Red, "Changed at frame 8, will be removed at frame 16");
}
else if (gameFrame == 16)
{
// destroy the displayList in the NavigationLab
navWorld->GetDisplayListManager()->RemoveDisplayList(displayListId);
displayListId = KyUInt32MAXVAL;
}
else if (gameFrame == 20)
{
// if we want to change it
Kaim::DisplayList displayList(navWorld->GetDisplayListManager());
displayList.InitUserControlledLifespan("UserControlledLifespanNoId", tutorialCategoryName);
displayList.PushText(Kaim::Vec3f::Zero(), Kaim::Color::Red, "Sent without Id at frame 20.");
}
else if (gameFrame == 24)
{
// if we want to change it
Kaim::DisplayList displayList(navWorld->GetDisplayListManager());
displayList.InitUserControlledLifespan("UserControlledLifespanNoId", tutorialCategoryName);
displayList.PushText(Kaim::Vec3f::Zero(), Kaim::Color::Red, "Updated at frame 24, will be removed at frame 30");
}
else if (gameFrame == 30)
{
// destroy the displayList in the NavigationLab
navWorld->GetDisplayListManager()->RemoveDisplayList("UserControlledLifespanNoId", tutorialCategoryName);
}
}
}
#endif
KT_ENV.CleanUpWorld();
}
KT_TUTORIAL // How to use Visual Debug for automated testing and playback of the tests
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Use Kaim::VisualDebugServer for testing");
#if defined(KY_CONFIG_DEBUG_OR_DEV)
KT_ASSERT(KT_ENV.AddNavData("generated/plane200x200_80ktri/plane200x200_80ktri.NavData") != nullptr);
KT_ASSERT(KT_ENV.AddRandomBots(1) == 1);
Kaim::World* navWorld = KT_ENV.GetNavWorld();
// To run automatic tests on your game, and save the test results for later viewing,
// set up the ViualDebugServer to save the session in a file that can be loaded into the NavigationLab.
// The enire result will be loaded in the NavigationLab (as if it was monitored over a network).
// Avoid logging data for too long, as the file may be too large to handle.
Kaim::VisualDebugServerConfig visualDebugServerConfig;
std::string filename = KT_ENV.GetAbsoluteOutputFileName("UsefulForAutomatedTesing.VisualDebug");
visualDebugServerConfig.UseLocalFile(filename.c_str(), &fileOpener);
KyResult startResult = navWorld->StartVisualDebug(visualDebugServerConfig);
if (startResult == KY_ERROR)
{
TestLog() << "==== Failed to start visual debug through file: " << filename.c_str() << " ====\n";
KT_ASSERT(false);
}
// Game loop
for (KyUInt32 gameFrame = 0; gameFrame < 10; ++gameFrame)
{
// call NewFrame at the beginning of a game frame whatever the status of the VisualdebugServer is
navWorld->NewVisualDebugFrame();
KT_ENV.Update();
}
#endif
KT_ENV.CleanUpWorld();
}
KT_TUTORIAL // How to handle custom messages through Kaim::VisualDebugServer
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Custom messages reception in Kaim::VisualDebugServer");
#if defined(KY_CONFIG_DEBUG_OR_DEV)
KT_ASSERT(KT_ENV.AddNavData("generated/plane200x200_80ktri/plane200x200_80ktri.NavData") != nullptr);
KT_ASSERT(KT_ENV.AddRandomBots(1) == 1);
Kaim::World* navWorld = KT_ENV.GetNavWorld();
// Provide a Kaim::MessageReceiverRegistry to Kaim::World::StartVisualDebug()
// This handles messages sent from the NavigationLab.
// The LabEngine is helpful in receiving textual commands.
// This example illustrates how to exit the game when receiving the command "exit"
Kaim::VisualDebugServerConfig visualDebugServerConfig;
Kaim::MessageReceiverRegistry registry;
LabEngine::CommandRegistry commands;
Kaim::Ptr<LabEngine::CommandContract> exitCmdContract = *KY_NEW LabEngine::CommandContract("exit");
Kaim::Ptr<ExitCommandProcessor> exitCommandProcessor = *KY_NEW ExitCommandProcessor;
exitCmdContract->SetCommandProcessor(exitCommandProcessor);
commands.AddCommand(exitCmdContract);
registry.SetVal(Kaim::TextualCommandBlob::GetBlobTypeId(), KY_NEW LabEngine::TextualCommandReceiver(&commands));
KyUInt32 serverPort = Kaim::VisualDebugServerConfig::DefaultServerPort();
KyUInt32 broadcastPort = Kaim::VisualDebugServerConfig::DefaultBroadcastPort(); // Pass 0 to disable broadcast.
visualDebugServerConfig.UseNavigationLab(serverPort, broadcastPort, &registry);
visualDebugServerConfig.SetWaitOnStart(Kaim::VisualDebugServerConfig::DoNotWaitOnStart);
// Logging will occur in the console of the NavigationLab because if no VisualDebugServer is set to Kaim::BaseLog,
// the world assigns its server on StartVisualDebug.
KyResult startResult = navWorld->StartVisualDebug(visualDebugServerConfig);
if (startResult == KY_ERROR)
{
TestLog() << "Failed to start visual debug\n";
KT_ASSERT(false);
}
// Game loop
for (KyUInt32 gameFrame = 0; gameFrame < 10 && exitCommandProcessor->m_doExit == false; ++gameFrame)
{
navWorld->NewVisualDebugFrame();
navWorld->Update();
// Send the Log into the NavigationLab.
KY_LOG_MESSAGE_IF(navWorld->GetVisualDebugServer()->IsReadyToSend(),
("==== Type exit in the NavigationLab Console in order to close this tutorial ===="));
}
// On StopVisualDebug, if World's VisualDebugServer was assigned to Kaim::BaseLog, it will be removed from Kaim::BaseLog.
navWorld->StopVisualDebug();
exitCommandProcessor = nullptr;
exitCmdContract = nullptr;
#endif
KT_ENV.CleanUpWorld();
}
}