added navmesh tester tool

Added ground work for tester tool
tester tool works but needs to fill out list of acceptable datablocks and spawnclasses
navpaths now share 1 navmeshquery
AIControllerData now has a vector of area costs for different polyareas
General cleanup
This commit is contained in:
marauder2k7 2025-07-26 10:34:19 +01:00
parent edf4d47be0
commit 6d36e17d91
17 changed files with 604 additions and 421 deletions

View file

@ -535,6 +535,10 @@ AIControllerData::AIControllerData()
#ifdef TORQUE_NAVIGATION_ENABLED #ifdef TORQUE_NAVIGATION_ENABLED
mLinkTypes = LinkData(AllFlags); mLinkTypes = LinkData(AllFlags);
mFilter.setIncludeFlags(mLinkTypes.getFlags());
mFilter.setExcludeFlags(0);
mAreaCosts.setSize(PolyAreas::NumAreas);
mAreaCosts.fill(1.0f);
mNavSize = AINavigation::Regular; mNavSize = AINavigation::Regular;
mFlocking.mChance = 90; mFlocking.mChance = 90;
mFlocking.mMin = 1.0f; mFlocking.mMin = 1.0f;
@ -560,6 +564,8 @@ AIControllerData::AIControllerData(const AIControllerData& other, bool temp_clon
#ifdef TORQUE_NAVIGATION_ENABLED #ifdef TORQUE_NAVIGATION_ENABLED
mLinkTypes = other.mLinkTypes; mLinkTypes = other.mLinkTypes;
mFilter = other.mFilter;
mAreaCosts = other.mAreaCosts;
mNavSize = other.mNavSize; mNavSize = other.mNavSize;
mFlocking.mChance = other.mFlocking.mChance; mFlocking.mChance = other.mFlocking.mChance;
mFlocking.mMin = other.mFlocking.mMin; mFlocking.mMin = other.mFlocking.mMin;
@ -629,6 +635,8 @@ void AIControllerData::initPersistFields()
addFieldV("FlockSideStep", TypeRangedF32, Offset(mFlocking.mSideStep, AIControllerData), &CommonValidators::PositiveFloat, addFieldV("FlockSideStep", TypeRangedF32, Offset(mFlocking.mSideStep, AIControllerData), &CommonValidators::PositiveFloat,
"@brief Distance from destination before we stop moving out of the way."); "@brief Distance from destination before we stop moving out of the way.");
addField("areaCosts", TypeF32Vector, Offset(mAreaCosts, AIControllerData),
"Vector of costs for each PolyArea.");
addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, AIControllerData), addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, AIControllerData),
"Allow the character to walk on dry land."); "Allow the character to walk on dry land.");
addField("allowJump", TypeBool, Offset(mLinkTypes.jump, AIControllerData), addField("allowJump", TypeBool, Offset(mLinkTypes.jump, AIControllerData),
@ -662,6 +670,10 @@ void AIControllerData::packData(BitStream* stream)
#ifdef TORQUE_NAVIGATION_ENABLED #ifdef TORQUE_NAVIGATION_ENABLED
//enums //enums
stream->write(mAreaCosts.size());
for (U32 i = 0; i < mAreaCosts.size(); i++) {
stream->write(mAreaCosts[i]);
}
stream->write(mLinkTypes.getFlags()); stream->write(mLinkTypes.getFlags());
stream->write((U32)mNavSize); stream->write((U32)mNavSize);
// end enums // end enums
@ -684,10 +696,23 @@ void AIControllerData::unpackData(BitStream* stream)
stream->read(&mFollowTolerance); stream->read(&mFollowTolerance);
#ifdef TORQUE_NAVIGATION_ENABLED #ifdef TORQUE_NAVIGATION_ENABLED
U32 num;
stream->read(&num);
mAreaCosts.setSize(num);
for (U32 i = 0; i < num; i++)
{
stream->read(&mAreaCosts[i]);
}
//enums //enums
U16 linkFlags; U16 linkFlags;
stream->read(&linkFlags); stream->read(&linkFlags);
mLinkTypes = LinkData(linkFlags); mLinkTypes = LinkData(linkFlags);
mFilter.setIncludeFlags(mLinkTypes.getFlags());
mFilter.setExcludeFlags(mLinkTypes.getExcludeFlags());
for (U32 i = 0; i < PolyAreas::NumAreas; i++)
{
mFilter.setAreaCost((PolyAreas)i, mAreaCosts[i]);
}
U32 navSize; U32 navSize;
stream->read(&navSize); stream->read(&navSize);
mNavSize = (AINavigation::NavSize)(navSize); mNavSize = (AINavigation::NavSize)(navSize);

View file

@ -168,6 +168,8 @@ public:
/// Types of link we can use. /// Types of link we can use.
LinkData mLinkTypes; LinkData mLinkTypes;
dtQueryFilter mFilter;
Vector<F32> mAreaCosts;
AINavigation::NavSize mNavSize; AINavigation::NavSize mNavSize;
#endif #endif
Delegate<void(AIController* obj, Point3F location, Move* movePtr)> resolveYawPtr; Delegate<void(AIController* obj, Point3F location, Move* movePtr)> resolveYawPtr;

View file

@ -77,6 +77,7 @@ bool AINavigation::setPathDestination(const Point3F& pos, bool replace)
path->mAlwaysRender = true; path->mAlwaysRender = true;
path->mLinkTypes = getCtrl()->mControllerData->mLinkTypes; path->mLinkTypes = getCtrl()->mControllerData->mLinkTypes;
path->mXray = true; path->mXray = true;
path->mFilter = getCtrl()->mControllerData->mFilter;
// Paths plan automatically upon being registered. // Paths plan automatically upon being registered.
if (!path->registerObject()) if (!path->registerObject())
{ {

View file

@ -114,6 +114,10 @@ AIPlayer::AIPlayer()
mJump = None; mJump = None;
mNavSize = Regular; mNavSize = Regular;
mLinkTypes = LinkData(AllFlags); mLinkTypes = LinkData(AllFlags);
mFilter.setIncludeFlags(mLinkTypes.getFlags());
mFilter.setExcludeFlags(0);
mAreaCosts.setSize(PolyAreas::NumAreas);
mAreaCosts.fill(1.0f);
#endif #endif
mIsAiControlled = true; mIsAiControlled = true;
@ -163,7 +167,8 @@ void AIPlayer::initPersistFields()
#ifdef TORQUE_NAVIGATION_ENABLED #ifdef TORQUE_NAVIGATION_ENABLED
addGroup("Pathfinding"); addGroup("Pathfinding");
addField("areaCosts", TypeF32Vector, Offset(mAreaCosts, AIPlayer),
"Vector of costs for each PolyArea.");
addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, AIPlayer), addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, AIPlayer),
"Allow the character to walk on dry land."); "Allow the character to walk on dry land.");
addField("allowJump", TypeBool, Offset(mLinkTypes.jump, AIPlayer), addField("allowJump", TypeBool, Offset(mLinkTypes.jump, AIPlayer),
@ -785,6 +790,7 @@ void AIPlayer::moveToNode(S32 node)
bool AIPlayer::setPathDestination(const Point3F &pos) bool AIPlayer::setPathDestination(const Point3F &pos)
{ {
#ifdef TORQUE_NAVIGATION_ENABLED
// Pathfinding only happens on the server. // Pathfinding only happens on the server.
if(!isServerObject()) if(!isServerObject())
return false; return false;
@ -799,6 +805,13 @@ bool AIPlayer::setPathDestination(const Point3F &pos)
return false; return false;
} }
mFilter.setIncludeFlags(mLinkTypes.getFlags());
mFilter.setExcludeFlags(mLinkTypes.getExcludeFlags());
for (U32 i = 0; i < PolyAreas::NumAreas; i++)
{
mFilter.setAreaCost((PolyAreas)i, mAreaCosts[i]);
}
// Create a new path. // Create a new path.
NavPath *path = new NavPath(); NavPath *path = new NavPath();
@ -808,6 +821,7 @@ bool AIPlayer::setPathDestination(const Point3F &pos)
path->mFromSet = path->mToSet = true; path->mFromSet = path->mToSet = true;
path->mAlwaysRender = true; path->mAlwaysRender = true;
path->mLinkTypes = mLinkTypes; path->mLinkTypes = mLinkTypes;
path->mFilter = mFilter;
path->mXray = true; path->mXray = true;
// Paths plan automatically upon being registered. // Paths plan automatically upon being registered.
if(!path->registerObject()) if(!path->registerObject())
@ -839,6 +853,9 @@ bool AIPlayer::setPathDestination(const Point3F &pos)
path->deleteObject(); path->deleteObject();
return false; return false;
} }
#else
setMoveDestination(pos, false);
#endif
} }
DefineEngineMethod(AIPlayer, setPathDestination, bool, (Point3F goal),, DefineEngineMethod(AIPlayer, setPathDestination, bool, (Point3F goal),,

View file

@ -59,8 +59,6 @@ GuiNavEditorCtrl::GuiNavEditorCtrl()
mIsDirty = false; mIsDirty = false;
mStartDragMousePoint = InvalidMousePoint; mStartDragMousePoint = InvalidMousePoint;
mMesh = NULL; mMesh = NULL;
mPlayer = mCurPlayer = NULL;
mSpawnClass = mSpawnDatablock = "";
} }
GuiNavEditorCtrl::~GuiNavEditorCtrl() GuiNavEditorCtrl::~GuiNavEditorCtrl()
@ -97,11 +95,6 @@ void GuiNavEditorCtrl::initPersistFields()
docsURL; docsURL;
addField("isDirty", TypeBool, Offset(mIsDirty, GuiNavEditorCtrl)); addField("isDirty", TypeBool, Offset(mIsDirty, GuiNavEditorCtrl));
addField("spawnClass", TypeRealString, Offset(mSpawnClass, GuiNavEditorCtrl),
"Class of object to spawn in test mode.");
addField("spawnDatablock", TypeRealString, Offset(mSpawnDatablock, GuiNavEditorCtrl),
"Datablock to give new objects in test mode.");
Parent::initPersistFields(); Parent::initPersistFields();
} }
@ -140,79 +133,6 @@ DefineEngineMethod(GuiNavEditorCtrl, getMesh, S32, (),,
return object->getMeshId(); return object->getMeshId();
} }
S32 GuiNavEditorCtrl::getPlayerId()
{
return mPlayer.isNull() ? 0 : mPlayer->getId();
}
DefineEngineMethod(GuiNavEditorCtrl, getPlayer, S32, (),,
"@brief Select a NavMesh object.")
{
return object->getPlayerId();
}
void GuiNavEditorCtrl::deselect()
{
if(!mMesh.isNull())
mMesh->setSelected(false);
mMesh = NULL;
mPlayer = mCurPlayer = NULL;
}
DefineEngineMethod(GuiNavEditorCtrl, deselect, void, (),,
"@brief Deselect whatever is currently selected in the editor.")
{
object->deselect();
}
void GuiNavEditorCtrl::spawnPlayer(const Point3F &pos)
{
SceneObject *obj = (SceneObject*)Sim::spawnObject(mSpawnClass, mSpawnDatablock);
if(obj)
{
MatrixF mat(true);
mat.setPosition(pos);
obj->setTransform(mat);
SimObject* cleanup = Sim::findObject("MissionCleanup");
if(cleanup)
{
SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup);
missionCleanup->addObject(obj);
}
mPlayer = obj;
#ifdef TORQUE_NAVIGATION_ENABLED
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(obj);
if (asAIPlayer) //try direct
{
Con::executef(this, "onPlayerSelected", Con::getIntArg(asAIPlayer->mLinkTypes.getFlags()));
}
else
{
ShapeBase* sbo = dynamic_cast<ShapeBase*>(obj);
if (sbo->getAIController())
{
if (sbo->getAIController()->mControllerData)
Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
}
else
{
#endif
Con::executef(this, "onPlayerSelected");
#ifdef TORQUE_NAVIGATION_ENABLED
}
}
#endif
}
}
DefineEngineMethod(GuiNavEditorCtrl, spawnPlayer, void, (),,
"@brief Spawn an AIPlayer at the centre of the screen.")
{
Point3F c;
if(object->get3DCentre(c))
object->spawnPlayer(c);
}
void GuiNavEditorCtrl::get3DCursor(GuiCursor *&cursor, void GuiNavEditorCtrl::get3DCursor(GuiCursor *&cursor,
bool &visible, bool &visible,
const Gui3DMouseEvent &event_) const Gui3DMouseEvent &event_)
@ -277,89 +197,6 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
mouseLock(); mouseLock();
return; return;
// Construct a LineSegment from the camera position to 1000 meters away in
// the direction clicked.
// If that segment hits the terrain, truncate the ray to only be that length.
Point3F startPnt = event.pos;
Point3F endPnt = event.pos + event.vec * 1000.0f;
RayInfo ri;
U8 keys = Input::getModifierKeys();
bool shift = keys & SI_LSHIFT;
bool ctrl = keys & SI_LCTRL;
if(mMode == mTestMode)
{
// Spawn new character
if(ctrl)
{
if(gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
spawnPlayer(ri.point);
}
// Deselect character
else if(shift)
{
mPlayer = NULL;
Con::executef(this, "onPlayerDeselected");
}
// Select/move character
else
{
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
{
if(ri.object)
{
mPlayer = ri.object;
#ifdef TORQUE_NAVIGATION_ENABLED
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(mPlayer.getPointer());
if (asAIPlayer) //try direct
{
Con::executef(this, "onPlayerSelected", Con::getIntArg(asAIPlayer->mLinkTypes.getFlags()));
}
else
{
ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
if (sbo->getAIController())
{
if (sbo->getAIController()->mControllerData)
Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
}
else
{
#endif
Con::executef(this, "onPlayerSelected");
}
#ifdef TORQUE_NAVIGATION_ENABLED
}
}
#endif
}
else if (!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
{
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(mPlayer.getPointer());
if (asAIPlayer) //try direct
{
#ifdef TORQUE_NAVIGATION_ENABLED
asAIPlayer->setPathDestination(ri.point);
#else
asAIPlayer->setMoveDestination(ri.point,false);
#endif
}
else
{
ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
if (sbo->getAIController())
{
if (sbo->getAIController()->mControllerData)
sbo->getAIController()->getNav()->setPathDestination(ri.point, true);
}
}
}
}
}
} }
void GuiNavEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event) void GuiNavEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event)
@ -385,22 +222,6 @@ void GuiNavEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
mTool->on3DMouseMove(event); mTool->on3DMouseMove(event);
return; return;
//if(mSelRiver != NULL && mSelNode != -1)
//mGizmo->on3DMouseMove(event);
Point3F startPnt = event.pos;
Point3F endPnt = event.pos + event.vec * 1000.0f;
RayInfo ri;
if(mMode == mTestMode)
{
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
mCurPlayer = ri.object;
else
mCurPlayer = NULL;
}
} }
void GuiNavEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event) void GuiNavEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
@ -443,22 +264,6 @@ void GuiNavEditorCtrl::onRender(Point2I offset, const RectI &updateRect)
return; return;
} }
static void renderBoxOutline(const Box3F &box, const ColorI &col)
{
if(box != Box3F::Invalid)
{
GFXStateBlockDesc desc;
desc.setCullMode(GFXCullNone);
desc.setFillModeSolid();
desc.setZReadWrite(true, false);
desc.setBlend(true);
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 20));
desc.setFillModeWireframe();
desc.setBlend(false);
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 255));
}
}
void GuiNavEditorCtrl::renderScene(const RectI & updateRect) void GuiNavEditorCtrl::renderScene(const RectI & updateRect)
{ {
GFX->setStateBlock(mZDisableSB); GFX->setStateBlock(mZDisableSB);
@ -479,14 +284,6 @@ void GuiNavEditorCtrl::renderScene(const RectI & updateRect)
if (mTool) if (mTool)
mTool->onRender3D(); mTool->onRender3D();
if(mMode == mTestMode)
{
if(!mCurPlayer.isNull())
renderBoxOutline(mCurPlayer->getWorldBox(), ColorI::BLUE);
if(!mPlayer.isNull())
renderBoxOutline(mPlayer->getWorldBox(), ColorI::GREEN);
}
duDebugDrawTorque d; duDebugDrawTorque d;
if(!mMesh.isNull()) if(!mMesh.isNull())
mMesh->renderLinks(d); mMesh->renderLinks(d);

View file

@ -103,17 +103,8 @@ public:
String getMode() { return mMode; } String getMode() { return mMode; }
void selectMesh(NavMesh *mesh); void selectMesh(NavMesh *mesh);
void deselect();
S32 getMeshId(); S32 getMeshId();
S32 getPlayerId();
String mSpawnClass;
String mSpawnDatablock;
void deleteLink();
void setLinkFlags(const LinkData &d);
void spawnPlayer(const Point3F &pos);
/// @} /// @}
void setActiveTool(NavMeshTool* tool); void setActiveTool(NavMeshTool* tool);
@ -148,14 +139,6 @@ protected:
/// @} /// @}
/// @name Test mode
/// @{
SimObjectPtr<SceneObject> mPlayer;
SimObjectPtr<SceneObject> mCurPlayer;
/// @}
Gui3DMouseEvent mLastMouseEvent; Gui3DMouseEvent mLastMouseEvent;
#define InvalidMousePoint Point2I(-100,-100) #define InvalidMousePoint Point2I(-100,-100)

View file

@ -225,10 +225,13 @@ NavMesh::NavMesh()
mWaterVertStart = 0; mWaterVertStart = 0;
mWaterTriStart = 0; mWaterTriStart = 0;
mQuery = NULL;
} }
NavMesh::~NavMesh() NavMesh::~NavMesh()
{ {
dtFreeNavMeshQuery(mQuery);
dtFreeNavMesh(nm); dtFreeNavMesh(nm);
nm = NULL; nm = NULL;
delete ctx; delete ctx;
@ -677,32 +680,6 @@ bool NavMesh::build(bool background, bool saveIntermediates)
return false; return false;
} }
Box3F worldBox = getWorldBox();
SceneContainer::CallbackInfo info;
info.context = PLC_Navigation;
info.boundingBox = worldBox;
m_geo = new RecastPolyList;
info.polyList = m_geo;
info.key = this;
getContainer()->findObjects(worldBox, StaticObjectType | DynamicShapeObjectType, buildCallback, &info);
// Parse water objects into the same list, but remember how much geometry was /not/ water.
mWaterVertStart = m_geo->getVertCount();
mWaterTriStart = m_geo->getTriCount();
if (mWaterMethod != Ignore)
{
getContainer()->findObjects(worldBox, WaterObjectType, buildCallback, &info);
}
// Check for no geometry.
if (!m_geo->getVertCount())
{
m_geo->clear();
return false;
}
m_geo->getChunkyMesh();
// Needed for the recast config and generation params. // Needed for the recast config and generation params.
Box3F rc_box = DTStoRC(getWorldBox()); Box3F rc_box = DTStoRC(getWorldBox());
S32 gw = 0, gh = 0; S32 gw = 0, gh = 0;
@ -803,33 +780,6 @@ void NavMesh::createNewFile()
mFileName = StringTable->insert(fileName.c_str()); mFileName = StringTable->insert(fileName.c_str());
} }
void NavMesh::updateConfig()
{
//// Build rcConfig object from our console members.
//dMemset(&cfg, 0, sizeof(cfg));
//cfg.cs = mCellSize;
//cfg.ch = mCellHeight;
//Box3F box = DTStoRC(getWorldBox());
//rcVcopy(cfg.bmin, box.minExtents);
//rcVcopy(cfg.bmax, box.maxExtents);
//rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
//cfg.walkableHeight = mCeil(mWalkableHeight / mCellHeight);
//cfg.walkableClimb = mCeil(mWalkableClimb / mCellHeight);
//cfg.walkableRadius = mCeil(mWalkableRadius / mCellSize);
//cfg.walkableSlopeAngle = mWalkableSlope;
//cfg.borderSize = cfg.walkableRadius + 3;
//cfg.detailSampleDist = mDetailSampleDist;
//cfg.detailSampleMaxError = mDetailSampleMaxError;
//cfg.maxEdgeLen = mMaxEdgeLen;
//cfg.maxSimplificationError = mMaxSimplificationError;
//cfg.maxVertsPerPoly = mMaxVertsPerPoly;
//cfg.minRegionArea = mMinRegionArea;
//cfg.mergeRegionArea = mMergeRegionArea;
//cfg.tileSize = mTileSize / cfg.cs;
}
S32 NavMesh::getTile(const Point3F& pos) S32 NavMesh::getTile(const Point3F& pos)
{ {
if(mBuilding) if(mBuilding)
@ -938,6 +888,8 @@ void NavMesh::buildNextTile()
if(!mDirtyTiles.empty()) if(!mDirtyTiles.empty())
{ {
dtFreeNavMeshQuery(mQuery);
mQuery = NULL;
// Pop a single dirty tile and process it. // Pop a single dirty tile and process it.
U32 i = mDirtyTiles.front(); U32 i = mDirtyTiles.front();
mDirtyTiles.pop_front(); mDirtyTiles.pop_front();
@ -1002,6 +954,12 @@ void NavMesh::buildNextTile()
// Did we just build the last tile? // Did we just build the last tile?
if(mDirtyTiles.empty()) if(mDirtyTiles.empty())
{ {
mQuery = dtAllocNavMeshQuery();
if (dtStatusFailed(mQuery->init(nm, 2048)))
{
Con::errorf("NavMesh - Failed to create navmesh query");
}
ctx->stopTimer(RC_TIMER_TOTAL); ctx->stopTimer(RC_TIMER_TOTAL);
if(getEventManager()) if(getEventManager())
{ {
@ -1012,6 +970,15 @@ void NavMesh::buildNextTile()
mBuilding = false; mBuilding = false;
} }
} }
if (mQuery == NULL)
{
mQuery = dtAllocNavMeshQuery();
if (dtStatusFailed(mQuery->init(nm, 2048)))
{
Con::errorf("NavMesh - Failed to create navmesh query");
}
}
} }
unsigned char *NavMesh::buildTileData(const Tile &tile, U32 &dataSize) unsigned char *NavMesh::buildTileData(const Tile &tile, U32 &dataSize)
@ -1614,11 +1581,13 @@ void NavMesh::renderToDrawer()
m_drawMode == DRAWMODE_NAVMESH_INVIS)) m_drawMode == DRAWMODE_NAVMESH_INVIS))
{ {
if (m_drawMode != DRAWMODE_NAVMESH_INVIS) if (m_drawMode != DRAWMODE_NAVMESH_INVIS)
duDebugDrawNavMesh(&mDbgDraw, *n->nm, 0); duDebugDrawNavMeshWithClosedList(&mDbgDraw, *n->nm, *n->mQuery, 0);
if(m_drawMode == DRAWMODE_NAVMESH_BVTREE) if(m_drawMode == DRAWMODE_NAVMESH_BVTREE)
duDebugDrawNavMeshBVTree(&mDbgDraw, *n->nm); duDebugDrawNavMeshBVTree(&mDbgDraw, *n->nm);
if(m_drawMode == DRAWMODE_NAVMESH_PORTALS) if(m_drawMode == DRAWMODE_NAVMESH_PORTALS)
duDebugDrawNavMeshPortals(&mDbgDraw, *n->nm); duDebugDrawNavMeshPortals(&mDbgDraw, *n->nm);
if (m_drawMode == DRAWMODE_NAVMESH_NODES)
duDebugDrawNavMeshNodes(&mDbgDraw, *n->mQuery);
} }
mDbgDraw.depthMask(true, false); mDbgDraw.depthMask(true, false);

View file

@ -187,6 +187,8 @@ public:
/// Delete the selected link. /// Delete the selected link.
void deleteLink(U32 idx); void deleteLink(U32 idx);
dtNavMeshQuery* getNavMeshQuery() { return mQuery; }
/// @} /// @}
/// Should small characters use this mesh? /// Should small characters use this mesh?
@ -381,16 +383,9 @@ private:
/// @} /// @}
/// @name Intermediate data
/// @{
/// Updates our config from console members.
void updateConfig();
dtNavMesh *nm; dtNavMesh *nm;
rcContext *ctx; rcContext *ctx;
dtNavMeshQuery* mQuery;
/// @}
/// @name Cover /// @name Cover
/// @{ /// @{

View file

@ -0,0 +1,302 @@
#include "navMeshTestTool.h"
#include "navigation/guiNavEditorCtrl.h"
#include "console/consoleTypes.h"
#include "gfx/gfxDrawUtil.h"
#include "scene/sceneManager.h"
#include "math/mathUtils.h"
#include "T3D/gameBase/gameConnection.h"
#include "T3D/AI/AIController.h"
IMPLEMENT_CONOBJECT(NavMeshTestTool);
//// take control
// GameConnection* conn = GameConnection::getConnectionToServer();
// if (conn)
// conn->setControlObject(static_cast<GameBase*>(obj));
//}
static void renderBoxOutline(const Box3F& box, const ColorI& col)
{
if (box != Box3F::Invalid)
{
GFXStateBlockDesc desc;
desc.setCullMode(GFXCullNone);
desc.setFillModeSolid();
desc.setZReadWrite(true, false);
desc.setBlend(true);
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 20));
desc.setFillModeWireframe();
desc.setBlend(false);
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 255));
}
}
void NavMeshTestTool::spawnPlayer(const Point3F& position)
{
if (mSpawnClass.isEmpty() || mSpawnDatablock.isEmpty())
{
Con::warnf("NavMeshTestTool::spawnPlayer - spawn class/datablock not set!");
return;
}
SimObject* spawned = Sim::spawnObject(mSpawnClass, mSpawnDatablock);
SceneObject* obj = dynamic_cast<SceneObject*>(spawned);
if (!obj)
{
Con::warnf("NavMeshTestTool::spawnPlayer - spawn failed or not a SceneObject");
if (spawned)
spawned->deleteObject();
return;
}
obj->setPosition(position);
obj->registerObject();
SimObject* cleanup = Sim::findObject("MissionCleanup");
if (cleanup)
{
SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup);
missionCleanup->addObject(obj);
}
mPlayer = obj;
Con::executef(this, "onPlayerSpawned", obj->getIdString());
}
void NavMeshTestTool::drawAgent(duDebugDrawTorque& dd, const F32* pos, F32 r, F32 h, F32 c, const U32 col)
{
dd.depthMask(false);
// Agent dimensions.
duDebugDrawCylinderWire(&dd, pos[0] - r, pos[1] + 0.02f, pos[2] - r, pos[0] + r, pos[1] + h, pos[2] + r, col, 2.0f);
duDebugDrawCircle(&dd, pos[0], pos[1] + c, pos[2], r, duRGBA(0, 0, 0, 64), 1.0f);
U32 colb = duRGBA(0, 0, 0, 196);
dd.begin(DU_DRAW_LINES);
dd.vertex(pos[0], pos[1] - c, pos[2], colb);
dd.vertex(pos[0], pos[1] + c, pos[2], colb);
dd.vertex(pos[0] - r / 2, pos[1] + 0.02f, pos[2], colb);
dd.vertex(pos[0] + r / 2, pos[1] + 0.02f, pos[2], colb);
dd.vertex(pos[0], pos[1] + 0.02f, pos[2] - r / 2, colb);
dd.vertex(pos[0], pos[1] + 0.02f, pos[2] + r / 2, colb);
dd.end();
dd.depthMask(true);
}
NavMeshTestTool::NavMeshTestTool()
{
mSpawnClass = String::EmptyString;
mSpawnDatablock = String::EmptyString;
mPlayer = NULL;
mCurPlayer = NULL;
mPathStart = Point3F::Max;
mPathEnd = Point3F::Max;
}
void NavMeshTestTool::onActivated(const Gui3DMouseEvent& evt)
{
Con::executef(this, "onActivated");
}
void NavMeshTestTool::onDeactivated()
{
Con::executef(this, "onDeactivated");
}
void NavMeshTestTool::on3DMouseDown(const Gui3DMouseEvent& evt)
{
if (mNavMesh.isNull())
return;
Point3F startPnt = evt.pos;
Point3F endPnt = evt.pos + evt.vec * 1000.0f;
RayInfo ri;
bool shift = evt.modifier & SI_LSHIFT;
bool ctrl = evt.modifier & SI_LCTRL;
if (ctrl)
{
if (gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
{
spawnPlayer(ri.point);
}
return;
}
if (shift)
{
mPlayer = NULL;
Con::executef(this, "onPlayerDeselected");
return;
}
if (gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
{
if (!ri.object)
return;
mPlayer = ri.object;
#ifdef TORQUE_NAVIGATION_ENABLED
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(mPlayer.getPointer());
if (asAIPlayer)
{
Con::executef(this, "onPlayerSelected", Con::getIntArg(asAIPlayer->mLinkTypes.getFlags()));
}
else
{
ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
if (sbo && sbo->getAIController() && sbo->getAIController()->mControllerData)
{
Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
}
else
{
Con::executef(this, "onPlayerSelected");
}
}
#else
Con::executef(this, "onPlayerSelected");
#endif
}
else if (gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
{
if (mPlayer.isNull())
{
if (mPathStart != Point3F::Max && mPathEnd != Point3F::Max) // start a new path.
{
mPathStart = Point3F::Max;
mPathEnd = Point3F::Max;
}
if (mPathStart != Point3F::Max)
{
mPathEnd = ri.point;
}
else
{
mPathStart = ri.point;
}
}
else
{
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(mPlayer.getPointer());
if (asAIPlayer) //try direct
{
asAIPlayer->setPathDestination(ri.point);
mPathStart = mPlayer->getPosition();
mPathEnd = ri.point;
}
else
{
ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
if (sbo->getAIController())
{
if (sbo->getAIController()->mControllerData)
{
sbo->getAIController()->getNav()->setPathDestination(ri.point, true);
mPathStart = mPlayer->getPosition();
mPathEnd = ri.point;
}
}
}
}
}
}
void NavMeshTestTool::on3DMouseMove(const Gui3DMouseEvent& evt)
{
if (mNavMesh.isNull())
return;
Point3F startPnt = evt.pos;
Point3F endPnt = evt.pos + evt.vec * 1000.0f;
RayInfo ri;
if (gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
mCurPlayer = ri.object;
else
mCurPlayer = NULL;
}
void NavMeshTestTool::onRender3D()
{
if (mNavMesh.isNull())
return;
static const U32 startCol = duRGBA(128, 25, 0, 192);
static const U32 endCol = duRGBA(51, 102, 0, 129);
const F32 agentRadius = mNavMesh->mWalkableRadius;
const F32 agentHeight = mNavMesh->mWalkableHeight;
const F32 agentClimb = mNavMesh->mWalkableClimb;
duDebugDrawTorque dd;
dd.depthMask(false);
if (mPathStart != Point3F::Max)
{
drawAgent(dd, DTStoRC(mPathStart), agentRadius, agentHeight, agentClimb, startCol);
}
if (mPathEnd != Point3F::Max)
{
drawAgent(dd, DTStoRC(mPathEnd), agentRadius, agentHeight, agentClimb, endCol);
}
dd.depthMask(true);
dd.immediateRender();
if (!mCurPlayer.isNull())
renderBoxOutline(mCurPlayer->getWorldBox(), ColorI::BLUE);
if (!mPlayer.isNull())
renderBoxOutline(mPlayer->getWorldBox(), ColorI::GREEN);
}
bool NavMeshTestTool::updateGuiInfo()
{
SimObject* statusbar;
Sim::findObject("EditorGuiStatusBar", statusbar);
GuiTextCtrl* selectionBar;
Sim::findObject("EWorldEditorStatusBarSelection", selectionBar);
String text;
if (statusbar)
Con::executef(statusbar, "setInfo", text.c_str());
text = "";
if (selectionBar)
selectionBar->setText(text);
return true;
}
S32 NavMeshTestTool::getPlayerId()
{
return mPlayer.isNull() ? 0 : mPlayer->getId();
}
DefineEngineMethod(NavMeshTestTool, getPlayer, S32, (), ,
"@brief Return the current player id.")
{
return object->getPlayerId();
}
DefineEngineMethod(NavMeshTestTool, setSpawnClass, void, (String className), , "")
{
object->setSpawnClass(className);
}
DefineEngineMethod(NavMeshTestTool, setSpawnDatablock, void, (String dbName), , "")
{
object->setSpawnDatablock(dbName);
}

View file

@ -0,0 +1,47 @@
#ifndef _NAVMESHTESTTOOL_H_
#define _NAVMESHTESTTOOL_H_
#ifndef _NAVMESH_TOOL_H_
#include "navigation/navMeshTool.h"
#endif
class NavMeshTestTool : public NavMeshTool
{
typedef NavMeshTool Parent;
protected:
String mSpawnClass;
String mSpawnDatablock;
SimObjectPtr<SceneObject> mPlayer;
SimObjectPtr<SceneObject> mCurPlayer;
Point3F mPathStart;
Point3F mPathEnd;
public:
DECLARE_CONOBJECT(NavMeshTestTool);
void spawnPlayer(const Point3F& position);
void drawAgent(duDebugDrawTorque& dd, const F32* pos, F32 r, F32 h, F32 c, const U32 col);
NavMeshTestTool();
virtual ~NavMeshTestTool() {}
void onActivated(const Gui3DMouseEvent& evt) override;
void onDeactivated() override;
void on3DMouseDown(const Gui3DMouseEvent& evt) override;
void on3DMouseMove(const Gui3DMouseEvent& evt) override;
void onRender3D() override;
bool updateGuiInfo() override;
S32 getPlayerId();
void setSpawnClass(String className) { mSpawnClass = className; }
void setSpawnDatablock(String dbName) { mSpawnDatablock = dbName; }
};
#endif // !_NAVMESHTESTTOOL_H_

View file

@ -69,14 +69,11 @@ NavPath::NavPath() :
mXray = false; mXray = false;
mRenderSearch = false; mRenderSearch = false;
mQuery = NULL;
mStatus = DT_FAILURE; mStatus = DT_FAILURE;
} }
NavPath::~NavPath() NavPath::~NavPath()
{ {
dtFreeNavMeshQuery(mQuery);
mQuery = NULL;
} }
void NavPath::checkAutoUpdate() void NavPath::checkAutoUpdate()
@ -264,9 +261,6 @@ bool NavPath::onAdd()
if(isServerObject()) if(isServerObject())
{ {
mQuery = dtAllocNavMeshQuery();
if(!mQuery)
return false;
checkAutoUpdate(); checkAutoUpdate();
if(!plan()) if(!plan())
setProcessTick(true); setProcessTick(true);
@ -293,7 +287,8 @@ bool NavPath::init()
return false; return false;
// Initialise our query. // Initialise our query.
if(dtStatusFailed(mQuery->init(mMesh->getNavMesh(), MaxPathLen))) mQuery = mMesh->getNavMeshQuery();
if(!mQuery)
return false; return false;
mPoints.clear(); mPoints.clear();
@ -372,9 +367,6 @@ void NavPath::resize()
bool NavPath::plan() bool NavPath::plan()
{ {
PROFILE_SCOPE(NavPath_plan); PROFILE_SCOPE(NavPath_plan);
// Initialise filter.
mFilter.setIncludeFlags(mLinkTypes.getFlags());
// Initialise query and visit locations. // Initialise query and visit locations.
if(!init()) if(!init())
return false; return false;
@ -641,6 +633,7 @@ void NavPath::renderSimple(ObjectRenderInst *ri, SceneRenderState *state, BaseMa
{ {
duDebugDrawTorque dd; duDebugDrawTorque dd;
duDebugDrawNavMeshNodes(&dd, *np->mQuery); duDebugDrawNavMeshNodes(&dd, *np->mQuery);
dd.immediateRender();
} }
} }
} }

View file

@ -57,7 +57,7 @@ public:
/// What sort of link types are we allowed to move on? /// What sort of link types are we allowed to move on?
LinkData mLinkTypes; LinkData mLinkTypes;
dtQueryFilter mFilter;
/// Plan the path. /// Plan the path.
bool plan(); bool plan();
@ -152,7 +152,6 @@ private:
dtNavMeshQuery *mQuery; dtNavMeshQuery *mQuery;
dtStatus mStatus; dtStatus mStatus;
dtQueryFilter mFilter;
S32 mCurIndex; S32 mCurIndex;
Vector<Point3F> mPoints; Vector<Point3F> mPoints;
Vector<U16> mFlags; Vector<U16> mFlags;

View file

@ -52,7 +52,8 @@ inline void rcCol(unsigned int col, U8 &r, U8 &g, U8 &b, U8 &a)
} }
enum PolyAreas { enum PolyAreas {
GroundArea = 1, NullArea = 0,
GroundArea,
WaterArea, WaterArea,
OffMeshArea, OffMeshArea,
NumAreas NumAreas
@ -99,6 +100,10 @@ struct LinkData {
(climb ? ClimbFlag : 0) | (climb ? ClimbFlag : 0) |
(teleport ? TeleportFlag : 0); (teleport ? TeleportFlag : 0);
} }
U16 getExcludeFlags() const
{
return AllFlags & ~getFlags();
}
}; };
#endif #endif

View file

@ -857,7 +857,27 @@ $guiContent = new GuiNavEditorCtrl(NavEditorGui, EditorGuiGroup) {
visible = "1"; visible = "1";
active = "0"; active = "0";
tooltipProfile = "GuiToolTipProfile"; tooltipProfile = "GuiToolTipProfile";
toolTip = "Can this character walk on ground?"; toolTip = "Can this character walk on ground?";
hovertime = "1000";
isContainer = "0";
canSave = "1";
canSaveDynamicFields = "0";
};
new GuiCheckBoxCtrl() {
internalName = "LinkSwimFlag";
class = "NavMeshTestFlagButton";
text = " Swim";
buttonType = "ToggleButton";
useMouseEvents = "0";
extent = "159 15";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiCheckBoxProfile";
visible = "1";
active = "0";
tooltipProfile = "GuiToolTipProfile";
toolTip = "Can this character swim?";
hovertime = "1000"; hovertime = "1000";
isContainer = "0"; isContainer = "0";
canSave = "1"; canSave = "1";

View file

@ -77,68 +77,5 @@ $guiContent = new GuiControl(NavEditorToolbar,EditorGuiGroup) {
canSave = "1"; canSave = "1";
canSaveDynamicFields = "0"; canSaveDynamicFields = "0";
}; };
new GuiCheckBoxCtrl() {
text = "Mesh";
groupNum = "-1";
buttonType = "ToggleButton";
useMouseEvents = "0";
position = "167 1";
extent = "50 30";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiCheckBoxProfile";
visible = "1";
active = "1";
variable = "$Nav::Editor::renderMesh";
tooltipProfile = "GuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
internalName = "MeshButton";
canSave = "1";
canSaveDynamicFields = "0";
};
new GuiCheckBoxCtrl() {
text = "Portals";
groupNum = "-1";
buttonType = "ToggleButton";
useMouseEvents = "0";
position = "224 1";
extent = "54 30";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiCheckBoxProfile";
visible = "1";
active = "1";
variable = "$Nav::Editor::renderPortals";
tooltipProfile = "GuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
internalName = "PortalButton";
canSave = "1";
canSaveDynamicFields = "0";
};
new GuiCheckBoxCtrl() {
text = "BV tree";
groupNum = "-1";
buttonType = "ToggleButton";
useMouseEvents = "0";
position = "286 1";
extent = "140 30";
minExtent = "8 2";
horizSizing = "right";
vertSizing = "bottom";
profile = "ToolsGuiCheckBoxProfile";
visible = "1";
active = "1";
variable = "$Nav::Editor::renderBVTree";
tooltipProfile = "GuiToolTipProfile";
hovertime = "1000";
isContainer = "0";
internalName = "BVTreeButton";
canSave = "1";
canSaveDynamicFields = "0";
};
}; };
//--- OBJECT WRITE END --- //--- OBJECT WRITE END ---

View file

@ -66,6 +66,13 @@ function initializeNavEditor()
buttonImage = "ToolsModule:nav_link_n_image"; buttonImage = "ToolsModule:nav_link_n_image";
}; };
new NavMeshTestTool()
{
internalName = "TestTool";
toolTip = "PathFinding Test tool";
buttonImage = "ToolsModule:3rd_person_camera_n_image";
};
new TileTool() new TileTool()
{ {
internalName = "TileTool"; internalName = "TileTool";
@ -140,7 +147,7 @@ function EditorGui::SetNavPalletBar()
EWToolsPaletteWindow.addButton("LinkMode", "ToolsModule:nav_link_n_image", "NavEditorGui.setActiveTool(NavMeshTools->LinkTool);", "", "Create off-mesh links", "2"); EWToolsPaletteWindow.addButton("LinkMode", "ToolsModule:nav_link_n_image", "NavEditorGui.setActiveTool(NavMeshTools->LinkTool);", "", "Create off-mesh links", "2");
// EWToolsPaletteWindow.addButton("CoverMode", "ToolsModule:nav_cover_n_image", "NavEditorGui.setMode(\"CoverMode\");", "","Edit cover", "3"); // EWToolsPaletteWindow.addButton("CoverMode", "ToolsModule:nav_cover_n_image", "NavEditorGui.setMode(\"CoverMode\");", "","Edit cover", "3");
// EWToolsPaletteWindow.addButton("TileMode", "ToolsModule:select_bounds_n_image", "NavEditorGui.setMode(\"TileMode\");", "", "View tiles", "4"); // EWToolsPaletteWindow.addButton("TileMode", "ToolsModule:select_bounds_n_image", "NavEditorGui.setMode(\"TileMode\");", "", "View tiles", "4");
// EWToolsPaletteWindow.addButton("TestMode", "ToolsModule:3rd_person_camera_n_image", "NavEditorGui.setMode(\"TestMode\");", "", "Test pathfinding", "5"); EWToolsPaletteWindow.addButton("TestMode", "ToolsModule:3rd_person_camera_n_image", "NavEditorGui.setActiveTool(NavMeshTools->TestTool);", "", "Test pathfinding", "5");
EWToolsPaletteWindow.addButton("TileMode", "ToolsModule:select_bounds_n_image", "NavEditorGui.setActiveTool(NavMeshTools->TileTool);" , "", "View and Edit Tiles", "4"); EWToolsPaletteWindow.addButton("TileMode", "ToolsModule:select_bounds_n_image", "NavEditorGui.setActiveTool(NavMeshTools->TileTool);" , "", "View and Edit Tiles", "4");
EWToolsPaletteWindow.refresh(); EWToolsPaletteWindow.refresh();
} }
@ -263,7 +270,7 @@ function NavEditorPlugin::initSettings(%this)
EditorSettings.beginGroup("NavEditor", true); EditorSettings.beginGroup("NavEditor", true);
EditorSettings.setDefaultValue("SpawnClass", "AIPlayer"); EditorSettings.setDefaultValue("SpawnClass", "AIPlayer");
EditorSettings.setDefaultValue("SpawnDatablock", "DefaultPlayerData"); EditorSettings.setDefaultValue("SpawnDatablock", "ProtoPlayer");
EditorSettings.endGroup(); EditorSettings.endGroup();
} }
@ -273,9 +280,6 @@ function NavEditorPlugin::readSettings(%this)
EditorSettings.beginGroup("NavEditor", true); EditorSettings.beginGroup("NavEditor", true);
// Currently these are globals because of the way they are accessed in navMesh.cpp. // Currently these are globals because of the way they are accessed in navMesh.cpp.
$Nav::Editor::renderMesh = EditorSettings.value("RenderMesh");
$Nav::Editor::renderPortals = EditorSettings.value("RenderPortals");
$Nav::Editor::renderBVTree = EditorSettings.value("RenderBVTree");
NavEditorGui.spawnClass = EditorSettings.value("SpawnClass"); NavEditorGui.spawnClass = EditorSettings.value("SpawnClass");
NavEditorGui.spawnDatablock = EditorSettings.value("SpawnDatablock"); NavEditorGui.spawnDatablock = EditorSettings.value("SpawnDatablock");
NavEditorGui.backgroundBuild = EditorSettings.value("BackgroundBuild"); NavEditorGui.backgroundBuild = EditorSettings.value("BackgroundBuild");
@ -295,9 +299,6 @@ function NavEditorPlugin::writeSettings(%this)
{ {
EditorSettings.beginGroup("NavEditor", true); EditorSettings.beginGroup("NavEditor", true);
EditorSettings.setValue("RenderMesh", $Nav::Editor::renderMesh);
EditorSettings.setValue("RenderPortals", $Nav::Editor::renderPortals);
EditorSettings.setValue("RenderBVTree", $Nav::Editor::renderBVTree);
EditorSettings.setValue("SpawnClass", NavEditorGui.spawnClass); EditorSettings.setValue("SpawnClass", NavEditorGui.spawnClass);
EditorSettings.setValue("SpawnDatablock", NavEditorGui.spawnDatablock); EditorSettings.setValue("SpawnDatablock", NavEditorGui.spawnDatablock);
EditorSettings.setValue("BackgroundBuild", NavEditorGui.backgroundBuild); EditorSettings.setValue("BackgroundBuild", NavEditorGui.backgroundBuild);

View file

@ -411,6 +411,142 @@ function NavMeshLinkBiDirection::onClick(%this)
//------------------------------------------------------ //------------------------------------------------------
function NavMeshTestTool::onActivated(%this)
{
NavInspector.setVisible(false);
%actions = NavEditorOptionsWindow->ActionsBox;
%actions->SelectActions.setVisible(false);
%actions->LinkActions.setVisible(false);
%actions->CoverActions.setVisible(false);
%actions->TileActions.setVisible(false);
%actions->TestActions.setVisible(false);
%properties = NavEditorOptionsWindow->PropertiesBox;
%properties->LinkProperties.setVisible(false);
%properties->TileProperties.setVisible(false);
%properties->TestProperties.setVisible(false);
%actions->TestActions.setVisible(true);
%properties->TestProperties.setVisible(true);
}
function NavMeshTestTool::onDeactivated(%this)
{
NavInspector.setVisible(false);
%actions = NavEditorOptionsWindow->ActionsBox;
%actions->SelectActions.setVisible(false);
%actions->LinkActions.setVisible(false);
%actions->CoverActions.setVisible(false);
%actions->TileActions.setVisible(false);
%actions->TestActions.setVisible(false);
%properties = NavEditorOptionsWindow->PropertiesBox;
%properties->LinkProperties.setVisible(false);
%properties->TileProperties.setVisible(false);
%properties->TestProperties.setVisible(false);
}
function updateTestData(%control, %flags)
{
%control->LinkWalkFlag.setActive(true);
%control->LinkSwimFlag.setActive(true);
%control->LinkJumpFlag.setActive(true);
%control->LinkDropFlag.setActive(true);
%control->LinkLedgeFlag.setActive(true);
%control->LinkClimbFlag.setActive(true);
%control->LinkTeleportFlag.setActive(true);
%control->LinkWalkFlag.setStateOn(%flags & $Nav::WalkFlag);
%control->LinkSwimFlag.setStateOn(%flags & $Nav::SwimFlag);
%control->LinkJumpFlag.setStateOn(%flags & $Nav::JumpFlag);
%control->LinkDropFlag.setStateOn(%flags & $Nav::DropFlag);
%control->LinkLedgeFlag.setStateOn(%flags & $Nav::LedgeFlag);
%control->LinkClimbFlag.setStateOn(%flags & $Nav::ClimbFlag);
%control->LinkTeleportFlag.setStateOn(%flags & $Nav::TeleportFlag);
}
function getTestFlags(%control)
{
return (%control->LinkWalkFlag.isStateOn() ? $Nav::WalkFlag : 0) |
(%control->LinkSwimFlag.isStateOn() ? $Nav::SwimFlag : 0) |
(%control->LinkJumpFlag.isStateOn() ? $Nav::JumpFlag : 0) |
(%control->LinkDropFlag.isStateOn() ? $Nav::DropFlag : 0) |
(%control->LinkLedgeFlag.isStateOn() ? $Nav::LedgeFlag : 0) |
(%control->LinkClimbFlag.isStateOn() ? $Nav::ClimbFlag : 0) |
(%control->LinkTeleportFlag.isStateOn() ? $Nav::TeleportFlag : 0);
}
function disableTestData(%control)
{
%control->LinkWalkFlag.setActive(false);
%control->LinkSwimFlag.setActive(false);
%control->LinkJumpFlag.setActive(false);
%control->LinkDropFlag.setActive(false);
%control->LinkLedgeFlag.setActive(false);
%control->LinkClimbFlag.setActive(false);
%control->LinkTeleportFlag.setActive(false);
}
function getControllerDataFlags(%controllerData)
{
return (%controllerData.allowWalk ? $Nav::WalkFlag : 0 ) |
(%controllerData.allowSwim ? $Nav::SwimFlag : 0 ) |
(%controllerData.allowJump ? $Nav::JumpFlag : 0 ) |
(%controllerData.allowDrop ? $Nav::DropFlag : 0 ) |
(%controllerData.allowLedge ? $Nav::LedgeFlag : 0) |
(%controllerData.allowClimb ? $Nav::ClimbFlag : 0) |
(%controllerData.allowTeleport ? $Nav::TeleportFlag : 0 );
}
function NavMeshTestTool::updateTestFlags(%this)
{
if(isObject(%this.getPlayer()))
{
%properties = NavEditorOptionsWindow-->TestProperties;
%player = %this.getPlayer();
%controllerData = %player.getDatablock().aiControllerData;
%controllerData.allowWalk = %properties->LinkWalkFlag.isStateOn();
%controllerData.allowSwim = %properties->LinkSwimFlag.isStateOn();
%controllerData.allowJump = %properties->LinkJumpFlag.isStateOn();
%controllerData.allowDrop = %properties->LinkDropFlag.isStateOn();
%controllerData.allowLedge = %properties->LinkLedgeFlag.isStateOn();
%controllerData.allowClimb = %properties->LinkClimbFlag.isStateOn();
%controllerData.allowTeleport = %properties->LinkTeleportFlag.isStateOn();
%player.aiController = new AIController(){ ControllerData = %controllerData; };
%player.setAIController(%player.aiController);
}
}
function NavMeshTestTool::onPlayerSelected(%this, %flags)
{
if (!isObject(%this.getPlayer().aiController) || (isObject(%this.getPlayer().aiController) && !(%this.getPlayer().isMemberOfClass("AIPlayer"))))
{
%this.getPlayer().aiController = new AIController(){ ControllerData = %this.getPlayer().getDatablock().aiControllerData; };
%this.getPlayer().setAIController(%this.getPlayer().aiController);
%flags = getControllerDataFlags(%this.getPlayer().getDatablock().aiControllerData);
}
NavMeshIgnore(%this.getPlayer(), true);
%this.getPlayer().setDamageState("Enabled");
updateTestData(NavEditorOptionsWindow-->TestProperties, %flags);
}
function NavMeshTestTool::onPlayerDeselected(%this)
{
disableTestData(NavEditorOptionsWindow-->TestProperties);
}
function NavMeshTestFlagButton::onClick(%this)
{
NavMeshTools->TestTool.updateTestFlags();
}
//------------------------------------------------------
function TileTool::onActivated(%this) function TileTool::onActivated(%this)
{ {
NavInspector.setVisible(false); NavInspector.setVisible(false);
@ -540,13 +676,13 @@ function NavEditorGui::deleteSelected(%this)
toolsMessageBoxYesNo("Warning", toolsMessageBoxYesNo("Warning",
"Are you sure you want to delete" SPC NavEditorGui.selectedObject.getName(), "Are you sure you want to delete" SPC NavEditorGui.selectedObject.getName(),
"NavEditorGui.deleteMesh();"); "NavEditorGui.deleteMesh();");
case "TestMode": // case "TestMode":
%this.getPlayer().delete(); // %this.getPlayer().delete();
%this.onPlayerDeselected(); // %this.onPlayerDeselected();
case "LinkMode": // case "LinkMode":
%this.deleteLink(); // %this.deleteLink();
%this.isDirty = true; // %this.isDirty = true;
} // }
} }
function NavEditorGui::buildSelectedMeshes(%this) function NavEditorGui::buildSelectedMeshes(%this)
@ -567,47 +703,6 @@ function NavEditorGui::buildLinks(%this)
} }
} }
function NavEditorGui::onLinkSelected(%this, %flags)
{
updateLinkData(NavEditorOptionsWindow-->LinkProperties, %flags);
}
function NavEditorGui::onPlayerSelected(%this, %flags)
{
if (!isObject(%this.getPlayer().aiController) || (isObject(%this.getPlayer().aiController) && !(%this.getPlayer().isMemberOfClass("AIPlayer"))))
{
%this.getPlayer().aiController = new AIController(){ ControllerData = %this.getPlayer().getDatablock().aiControllerData; };
%this.getPlayer().setAIController(%this.getPlayer().aiController);
}
NavMeshIgnore(%this.getPlayer(), true);
%this.getPlayer().setDamageState("Enabled");
updateLinkData(NavEditorOptionsWindow-->TestProperties, %flags);
}
function NavEditorGui::updateTestFlags(%this)
{
if(isObject(%this.getPlayer()))
{
%properties = NavEditorOptionsWindow-->TestProperties;
%player = %this.getPlayer();
%player.allowWwalk = %properties->LinkWalkFlag.isStateOn();
%player.allowJump = %properties->LinkJumpFlag.isStateOn();
%player.allowDrop = %properties->LinkDropFlag.isStateOn();
%player.allowLedge = %properties->LinkLedgeFlag.isStateOn();
%player.allowClimb = %properties->LinkClimbFlag.isStateOn();
%player.allowTeleport = %properties->LinkTeleportFlag.isStateOn();
%this.isDirty = true;
}
}
function NavEditorGui::onPlayerDeselected(%this)
{
disableLinkData(NavEditorOptionsWindow-->TestProperties);
}
function NavEditorGui::createCoverPoints(%this) function NavEditorGui::createCoverPoints(%this)
{ {
if(isObject(%this.getMesh())) if(isObject(%this.getMesh()))
@ -718,11 +813,6 @@ function ENavEditorPaletteButton::onClick(%this)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
function NavMeshTestFlagButton::onClick(%this)
{
NavEditorGui.updateTestFlags();
}
singleton GuiControlProfile(NavEditorProfile) singleton GuiControlProfile(NavEditorProfile)
{ {
canKeyFocus = true; canKeyFocus = true;