Tutorial_VisualDebug.cpp

Tutorial_VisualDebug.cpp
/*
* Copyright 2015 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 "GwNavTestFwk/TestSystem.h"
#include "LabEngine/commands/textualcommandreceiver.h"
#include "LabEngine/commands/commands.h"
#include "LabEngine/base/kaimfileopener.h"
//RUN_THIS_FILE
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 TEST_ENV_CLASS OneWorldEnv
TEST_ENV {}
// This class is used in order to process an "Exit" command from the Gameware 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;
};
TUTORIAL // How to Visual Debug a world
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Visual Debug a world");
#ifndef KY_BUILD_SHIPPING
CHECK(env.LoadAndAddNavData("GeneratedNavData/plan/plan.NavData") != KY_NULL);
CHECK(env.AddRandomBots(1) == 1);
Kaim::World* navWorld = env.GetWorld();
// 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 (KY_FAILED(startResult))
{
TestLog() << "Failed to start visual debug\n";
CHECK(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
if (navWorld->GetVisualDebugServer())
navWorld->GetVisualDebugServer()->NewFrame();
navWorld->Update();
}
navWorld->StopVisualDebug();
#endif
env.CleanUpWorld();
}
// This tutorial looks at several aspects of Visual debugging in Navigation.
TUTORIAL // How to visually debug custom information sent to a world
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Send custom information through Kaim::VisualDebugServer");
#ifndef KY_BUILD_SHIPPING
CHECK(env.LoadAndAddNavData("GeneratedNavData/plan/plan.NavData") != KY_NULL);
CHECK(env.AddRandomBots(1) == 1);
LabEngine::GameBot* gameBot = env.GetGameWorld()->GetBots()[0];
Kaim::World* navWorld = env.GetWorld();
// 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 (KY_FAILED(startResult))
{
TestLog() << "Failed to start visual debug\n";
CHECK(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
if (navWorld->GetVisualDebugServer())
navWorld->GetVisualDebugServer()->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 IsConnected before sending messages
// to prevent useless construction of messages
if (navWorld->GetVisualDebugServer()->IsConnected() == 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::ScopedDisplayList displayList(navWorld, dynamicallyEnableOrDisableDisplayListInGame);
displayList.InitSingleFrameLifespan("GameBot To OriginLine", tutroialCategoryName);
displayList.PushLine(gameBot->GetPosition(), Kaim::Vec3f::Zero(), Kaim::VisualColor::White);
}
{
// Send a second display list that is associated to Kaim::Bot VisualDebug config in the NavigationLab
Kaim::Vec3f destination = gameBot->GetRoute().GetCurrentWayPoint();
Kaim::ScopedDisplayList displayList(navWorld, dynamicallyEnableOrDisableDisplayListInGame);
displayList.InitSingleFrameLifespan("Destination", "Tutorial", gameBot->GetBot()->GetVisualDebugId());
KyFloat32 displayRadius = 1.f;
Kaim::VisualShapeColor shapeColor;
shapeColor.m_lineColor = Kaim::VisualColor(255, 255, 0);
displayList.PushPoint(destination, displayRadius, shapeColor);
shapeColor.SetOnlyTriangleColor(Kaim::VisualColor(255, 0, 255));
displayList.PushArrow(gameBot->GetPosition(), destination, displayRadius, shapeColor);
displayList.PushText(destination + Kaim::Vec3f::UnitZ(), Kaim::VisualColor(0, 255, 255), "Destination");
}
}
#endif
env.CleanUpWorld();
}
TUTORIAL // How to control lifetime of a display list over several frames without sending it each frame
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Send a ScopedDisplayList once, but keep it alive several frames in the NavigationLab");
#ifndef KY_BUILD_SHIPPING
Kaim::World* navWorld = env.GetWorld();
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 (KY_FAILED(startResult))
{
TestLog() << "Failed to start visual debug\n";
CHECK(false);
}
// Wait for synchronization - only useful when trying this with the Lab
{
while (1)
{
if (navWorld->GetVisualDebugServer())
navWorld->GetVisualDebugServer()->NewFrame();
if (navWorld->GetVisualDebugServer()->IsConnected())
break;
}
}
const char* tutorialCategoryName = "Tutorial_World";
// id assigned to our ScopedDisplayList
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
if (navWorld->GetVisualDebugServer())
navWorld->GetVisualDebugServer()->NewFrame();
// Update the world
navWorld->Update();
// always check that IsConnected before sending messages
// to prevent useless construction of messages
if (navWorld->GetVisualDebugServer()->IsConnected())
{
if (gameFrame == 4)
{
// Send a display list only once
Kaim::ScopedDisplayList displayList(navWorld);
displayListId = displayList.InitUserControlledLifespan("UserControlledLifespan", tutorialCategoryName, displayListId);
displayList.PushText(Kaim::Vec3f::Zero(), Kaim::VisualColor::Red, "Sent at frame 4");
}
else if (gameFrame == 8)
{
// if we want to change it
Kaim::ScopedDisplayList displayList(navWorld);
displayListId = displayList.InitUserControlledLifespan("UserControlledLifespan", tutorialCategoryName, displayListId);
displayList.PushText(Kaim::Vec3f::Zero(), Kaim::VisualColor::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::ScopedDisplayList displayList(navWorld);
displayList.InitUserControlledLifespan("UserControlledLifespanNoId", tutorialCategoryName);
displayList.PushText(Kaim::Vec3f::Zero(), Kaim::VisualColor::Red, "Sent without Id at frame 20.");
}
else if (gameFrame == 24)
{
// if we want to change it
Kaim::ScopedDisplayList displayList(navWorld);
displayList.InitUserControlledLifespan("UserControlledLifespanNoId", tutorialCategoryName);
displayList.PushText(Kaim::Vec3f::Zero(), Kaim::VisualColor::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
env.CleanUpWorld();
}
TUTORIAL // How to use Visual Debug for automated testing and playback of the tests
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Use Kaim::VisualDebugServer for testing");
#ifndef KY_BUILD_SHIPPING
CHECK(env.LoadAndAddNavData("GeneratedNavData/plan/plan.NavData") != KY_NULL);
CHECK(env.AddRandomBots(1) == 1);
Kaim::World* navWorld = env.GetWorld();
// 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 = env.GetAbsoluteOutputFileName("UsefulForAutomatedTesing.VisualDebug");
visualDebugServerConfig.UseLocalFile(filename.c_str(), &fileOpener);
KyResult startResult = navWorld->StartVisualDebug(visualDebugServerConfig);
if (KY_FAILED(startResult))
{
TestLog() << "==== Failed to start visual debug through file: " << filename.c_str() << " ====\n";
CHECK(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
if (navWorld->GetVisualDebugServer())
navWorld->GetVisualDebugServer()->NewFrame();
env.Update();
}
#endif
env.CleanUpWorld();
}
TUTORIAL // How to handle custom messages through Kaim::VisualDebugServer
{
KT_LOG_TITLE_BEGIN("TUTORIAL - Custom messages reception in Kaim::VisualDebugServer");
#ifndef KY_BUILD_SHIPPING
CHECK(env.LoadAndAddNavData("GeneratedNavData/plan/plan.NavData") != KY_NULL);
CHECK(env.AddRandomBots(1) == 1);
Kaim::World* navWorld = env.GetWorld();
// 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 (KY_FAILED(startResult))
{
TestLog() << "Failed to start visual debug\n";
CHECK(false);
}
// Game loop
for (KyUInt32 gameFrame = 0; gameFrame < 10 && exitCommandProcessor->m_doExit == false; ++gameFrame)
{
if (navWorld->GetVisualDebugServer())
navWorld->GetVisualDebugServer()->NewFrame();
navWorld->Update();
// Send the Log into the NavigationLab.
KY_LOG_MESSAGE_IF(navWorld->GetVisualDebugServer()->IsConnected(),
("==== 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 = KY_NULL;
exitCmdContract = KY_NULL;
#endif
env.CleanUpWorld();
}
}